Merge "PreferenceControllers are the way of the future."
This commit is contained in:
committed by
Android (Google) Code Review
commit
d0965a21e4
@@ -15,7 +15,15 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings" >
|
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings">
|
||||||
|
|
||||||
|
<com.android.settings.applications.LayoutPreference
|
||||||
|
android:key="pref_app_header"
|
||||||
|
android:layout="@layout/settings_entity_header" />
|
||||||
|
|
||||||
|
<com.android.settings.applications.LayoutPreference
|
||||||
|
android:key="block"
|
||||||
|
android:layout="@layout/styled_switch_bar" />
|
||||||
|
|
||||||
<!-- Show badge -->
|
<!-- Show badge -->
|
||||||
<com.android.settingslib.RestrictedSwitchPreference
|
<com.android.settingslib.RestrictedSwitchPreference
|
||||||
@@ -24,22 +32,24 @@
|
|||||||
settings:useAdditionalSummary="true"
|
settings:useAdditionalSummary="true"
|
||||||
settings:restrictedSwitchSummary="@string/enabled_by_admin" />
|
settings:restrictedSwitchSummary="@string/enabled_by_admin" />
|
||||||
|
|
||||||
<!-- Importance toggle -->
|
<!-- Channels/Channel groups added here -->
|
||||||
<com.android.settingslib.RestrictedSwitchPreference
|
|
||||||
android:key="allow_sound"
|
|
||||||
android:title="@string/allow_interruption"
|
|
||||||
android:summary="@string/allow_interruption_summary"/>
|
|
||||||
|
|
||||||
<!-- Visibility Override -->
|
<Preference
|
||||||
<com.android.settings.notification.RestrictedDropDownPreference
|
android:key="app_link"
|
||||||
android:key="visibility_override"
|
android:title="@string/app_settings_link"
|
||||||
android:title="@string/app_notification_visibility_override_title" />
|
android:order="500"
|
||||||
|
settings:allowDividerAbove="true"/>
|
||||||
|
|
||||||
<!-- Bypass DND -->
|
<com.android.settings.notification.NotificationFooterPreference
|
||||||
<com.android.settingslib.RestrictedSwitchPreference
|
android:key="block_desc"
|
||||||
android:key="bypass_dnd"
|
android:order="1000" />
|
||||||
android:title="@string/app_notification_override_dnd_title"
|
|
||||||
android:summary="@string/app_notification_override_dnd_summary"
|
<com.android.settings.notification.NotificationFooterPreference
|
||||||
settings:useAdditionalSummary="true" />
|
android:key="desc"
|
||||||
|
android:order="5000" />
|
||||||
|
|
||||||
|
<com.android.settings.notification.NotificationFooterPreference
|
||||||
|
android:key="deleted"
|
||||||
|
android:order="8000" />
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
90
res/xml/channel_notification_settings.xml
Normal file
90
res/xml/channel_notification_settings.xml
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2016 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"
|
||||||
|
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings" >
|
||||||
|
|
||||||
|
<com.android.settings.applications.LayoutPreference
|
||||||
|
android:key="pref_app_header"
|
||||||
|
android:layout="@layout/settings_entity_header" />
|
||||||
|
|
||||||
|
<com.android.settings.applications.LayoutPreference
|
||||||
|
android:key="block"
|
||||||
|
android:layout="@layout/styled_switch_bar" />
|
||||||
|
|
||||||
|
<!-- Importance -->
|
||||||
|
<Preference
|
||||||
|
android:key="importance"
|
||||||
|
android:title="@string/notification_importance_title" />
|
||||||
|
|
||||||
|
<!-- Importance toggle -->
|
||||||
|
<com.android.settingslib.RestrictedSwitchPreference
|
||||||
|
android:key="allow_sound"
|
||||||
|
android:title="@string/allow_interruption"
|
||||||
|
android:summary="@string/allow_interruption_summary" />
|
||||||
|
|
||||||
|
<!-- Default ringtone -->
|
||||||
|
<com.android.settings.notification.NotificationSoundPreference
|
||||||
|
android:key="ringtone"
|
||||||
|
android:title="@string/notification_channel_sound_title"
|
||||||
|
android:dialogTitle="@string/notification_channel_sound_title"
|
||||||
|
android:showSilent="true"
|
||||||
|
android:showDefault="true"
|
||||||
|
android:ringtoneType="notification" />
|
||||||
|
|
||||||
|
<!-- Vibration -->
|
||||||
|
<com.android.settingslib.RestrictedSwitchPreference
|
||||||
|
android:key="vibrate"
|
||||||
|
android:title="@string/notification_vibrate_title"
|
||||||
|
settings:useAdditionalSummary="true" />
|
||||||
|
|
||||||
|
<!-- Visibility Override -->
|
||||||
|
<com.android.settings.notification.RestrictedDropDownPreference
|
||||||
|
android:key="visibility_override"
|
||||||
|
android:title="@string/app_notification_visibility_override_title"/>
|
||||||
|
|
||||||
|
<!-- Lights -->
|
||||||
|
<com.android.settingslib.RestrictedSwitchPreference
|
||||||
|
android:key="lights"
|
||||||
|
android:title="@string/notification_show_lights_title"
|
||||||
|
settings:useAdditionalSummary="true"/>
|
||||||
|
|
||||||
|
<!-- Show badge -->
|
||||||
|
<com.android.settingslib.RestrictedSwitchPreference
|
||||||
|
android:key="badge"
|
||||||
|
android:title="@string/notification_channel_badge_title"
|
||||||
|
settings:useAdditionalSummary="true"
|
||||||
|
settings:restrictedSwitchSummary="@string/enabled_by_admin"/>
|
||||||
|
|
||||||
|
<!-- Bypass DND -->
|
||||||
|
<com.android.settingslib.RestrictedSwitchPreference
|
||||||
|
android:key="bypass_dnd"
|
||||||
|
android:title="@string/app_notification_override_dnd_title"
|
||||||
|
android:summary="@string/app_notification_override_dnd_summary"
|
||||||
|
settings:useAdditionalSummary="true"/>
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="app_link"
|
||||||
|
android:title="@string/app_settings_link"
|
||||||
|
settings:allowDividerAbove="true"/>
|
||||||
|
|
||||||
|
<com.android.settings.notification.NotificationFooterPreference
|
||||||
|
android:key="desc" />
|
||||||
|
|
||||||
|
<com.android.settings.notification.NotificationFooterPreference
|
||||||
|
android:key="block_desc" />
|
||||||
|
|
||||||
|
</PreferenceScreen>
|
||||||
@@ -17,11 +17,24 @@
|
|||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings">
|
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings">
|
||||||
|
|
||||||
<!-- Show badge -->
|
<com.android.settings.applications.LayoutPreference
|
||||||
<com.android.settingslib.RestrictedSwitchPreference
|
android:key="pref_app_header"
|
||||||
android:key="badge"
|
android:layout="@layout/settings_entity_header" />
|
||||||
android:title="@string/notification_badge_title"
|
|
||||||
settings:useAdditionalSummary="true"
|
|
||||||
settings:restrictedSwitchSummary="@string/enabled_by_admin" />
|
|
||||||
|
|
||||||
|
<com.android.settings.applications.LayoutPreference
|
||||||
|
android:key="block"
|
||||||
|
android:layout="@layout/styled_switch_bar" />
|
||||||
|
|
||||||
|
<!-- Channels added here -->
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="app_link"
|
||||||
|
android:title="@string/app_settings_link"
|
||||||
|
settings:allowDividerAbove="true"/>
|
||||||
|
|
||||||
|
<com.android.settings.notification.NotificationFooterPreference
|
||||||
|
android:key="desc" />
|
||||||
|
|
||||||
|
<com.android.settings.notification.NotificationFooterPreference
|
||||||
|
android:key="block_desc" />
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Copyright (C) 2016 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"
|
|
||||||
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings" >
|
|
||||||
|
|
||||||
<!-- Importance -->
|
|
||||||
<Preference
|
|
||||||
android:key="importance"
|
|
||||||
android:title="@string/notification_importance_title" />
|
|
||||||
|
|
||||||
<!-- Default ringtone -->
|
|
||||||
<com.android.settings.notification.NotificationSoundPreference
|
|
||||||
android:key="ringtone"
|
|
||||||
android:title="@string/notification_channel_sound_title"
|
|
||||||
android:dialogTitle="@string/notification_channel_sound_title"
|
|
||||||
android:showSilent="true"
|
|
||||||
android:showDefault="true"
|
|
||||||
android:ringtoneType="notification" />
|
|
||||||
|
|
||||||
<!-- Vibration -->
|
|
||||||
<com.android.settingslib.RestrictedSwitchPreference
|
|
||||||
android:key="vibrate"
|
|
||||||
android:title="@string/notification_vibrate_title"
|
|
||||||
settings:useAdditionalSummary="true" />
|
|
||||||
|
|
||||||
<PreferenceCategory
|
|
||||||
android:key="advanced"
|
|
||||||
android:title="@string/advanced_apps">
|
|
||||||
|
|
||||||
<!-- Visibility Override -->
|
|
||||||
<com.android.settings.notification.RestrictedDropDownPreference
|
|
||||||
android:key="visibility_override"
|
|
||||||
android:title="@string/app_notification_visibility_override_title" />
|
|
||||||
|
|
||||||
<!-- Lights -->
|
|
||||||
<com.android.settingslib.RestrictedSwitchPreference
|
|
||||||
android:key="lights"
|
|
||||||
android:title="@string/notification_show_lights_title"
|
|
||||||
settings:useAdditionalSummary="true" />
|
|
||||||
|
|
||||||
<!-- Show badge -->
|
|
||||||
<com.android.settingslib.RestrictedSwitchPreference
|
|
||||||
android:key="badge"
|
|
||||||
android:title="@string/notification_channel_badge_title"
|
|
||||||
settings:useAdditionalSummary="true"
|
|
||||||
settings:restrictedSwitchSummary="@string/enabled_by_admin" />
|
|
||||||
|
|
||||||
<!-- Bypass DND -->
|
|
||||||
<com.android.settingslib.RestrictedSwitchPreference
|
|
||||||
android:key="bypass_dnd"
|
|
||||||
android:title="@string/app_notification_override_dnd_title"
|
|
||||||
android:summary="@string/app_notification_override_dnd_summary"
|
|
||||||
settings:useAdditionalSummary="true" />
|
|
||||||
|
|
||||||
</PreferenceCategory>
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.settings.core.PreferenceControllerMixin;
|
||||||
|
import com.android.settingslib.RestrictedSwitchPreference;
|
||||||
|
|
||||||
|
public class AllowSoundPreferenceController extends NotificationPreferenceController
|
||||||
|
implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
|
||||||
|
|
||||||
|
private static final String TAG = "AllowSoundPrefContr";
|
||||||
|
private static final String KEY_IMPORTANCE = "allow_sound";
|
||||||
|
private NotificationSettingsBase.ImportanceListener mImportanceListener;
|
||||||
|
|
||||||
|
public AllowSoundPreferenceController(Context context,
|
||||||
|
NotificationSettingsBase.ImportanceListener importanceListener,
|
||||||
|
NotificationBackend backend) {
|
||||||
|
super(context, backend);
|
||||||
|
mImportanceListener = importanceListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPreferenceKey() {
|
||||||
|
return KEY_IMPORTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
if (!super.isAvailable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return mChannel != null && NotificationChannel.DEFAULT_CHANNEL_ID.equals(mChannel.getId());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
if (mChannel != null) {
|
||||||
|
RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
|
||||||
|
pref.setDisabledByAdmin(mAdmin);
|
||||||
|
pref.setEnabled(isChannelConfigurable() && !pref.isDisabledByAdmin());
|
||||||
|
pref.setChecked(mChannel.getImportance() >= IMPORTANCE_DEFAULT
|
||||||
|
|| mChannel.getImportance() == IMPORTANCE_UNSPECIFIED);
|
||||||
|
} else { Log.i(TAG, "tried to updatestate on a null channel?!"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
|
if (mChannel != null) {
|
||||||
|
final int importance =
|
||||||
|
((Boolean) newValue ? IMPORTANCE_UNSPECIFIED : IMPORTANCE_LOW);
|
||||||
|
mChannel.setImportance(importance);
|
||||||
|
mChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
|
||||||
|
saveChannel();
|
||||||
|
mImportanceListener.onImportanceChanged();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
|
||||||
|
import com.android.settings.core.PreferenceControllerMixin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls link to reach more preference settings inside the app.
|
||||||
|
*/
|
||||||
|
public class AppLinkPreferenceController extends NotificationPreferenceController
|
||||||
|
implements PreferenceControllerMixin {
|
||||||
|
|
||||||
|
private static final String TAG = "AppLinkPrefContr";
|
||||||
|
private static final String KEY_APP_LINK = "app_link";
|
||||||
|
|
||||||
|
public AppLinkPreferenceController(Context context) {
|
||||||
|
super(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPreferenceKey() {
|
||||||
|
return KEY_APP_LINK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
if (!super.isAvailable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return mAppRow.settingsIntent != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
if (mAppRow != null) {
|
||||||
|
preference.setIntent(mAppRow.settingsIntent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,12 +16,10 @@
|
|||||||
|
|
||||||
package com.android.settings.notification;
|
package com.android.settings.notification;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
import android.app.NotificationChannelGroup;
|
import android.app.NotificationChannelGroup;
|
||||||
import android.app.NotificationManager;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
@@ -29,43 +27,29 @@ import android.support.v7.preference.Preference;
|
|||||||
import android.support.v7.preference.PreferenceCategory;
|
import android.support.v7.preference.PreferenceCategory;
|
||||||
import android.support.v7.preference.PreferenceGroup;
|
import android.support.v7.preference.PreferenceGroup;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.ArrayMap;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.Switch;
|
|
||||||
|
|
||||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||||
|
import com.android.internal.widget.LockPatternUtils;
|
||||||
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;
|
||||||
import com.android.settings.applications.LayoutPreference;
|
|
||||||
import com.android.settings.notification.NotificationBackend.AppRow;
|
|
||||||
import com.android.settings.widget.EntityHeaderController;
|
|
||||||
import com.android.settings.widget.MasterSwitchPreference;
|
import com.android.settings.widget.MasterSwitchPreference;
|
||||||
import com.android.settings.widget.SwitchBar;
|
import com.android.settingslib.core.AbstractPreferenceController;
|
||||||
import com.android.settingslib.RestrictedSwitchPreference;
|
|
||||||
import com.android.settingslib.widget.FooterPreference;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
|
||||||
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
|
|
||||||
|
|
||||||
/** These settings are per app, so should not be returned in global search results. */
|
/** These settings are per app, so should not be returned in global search results. */
|
||||||
public class AppNotificationSettings extends NotificationSettingsBase {
|
public class AppNotificationSettings extends NotificationSettingsBase {
|
||||||
private static final String TAG = "AppNotificationSettings";
|
private static final String TAG = "AppNotificationSettings";
|
||||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||||
|
|
||||||
private static String KEY_GENERAL_CATEGORY = "categories";
|
private static String KEY_GENERAL_CATEGORY = "categories";
|
||||||
private static String KEY_DELETED = "deleted";
|
|
||||||
|
|
||||||
private List<NotificationChannelGroup> mChannelGroupList;
|
private List<NotificationChannelGroup> mChannelGroupList;
|
||||||
private List<PreferenceCategory> mChannelGroups = new ArrayList();
|
|
||||||
private FooterPreference mDeletedChannels;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMetricsCategory() {
|
public int getMetricsCategory() {
|
||||||
@@ -84,24 +68,13 @@ public class AppNotificationSettings extends NotificationSettingsBase {
|
|||||||
|
|
||||||
if (getPreferenceScreen() != null) {
|
if (getPreferenceScreen() != null) {
|
||||||
getPreferenceScreen().removeAll();
|
getPreferenceScreen().removeAll();
|
||||||
mChannelGroups.clear();
|
mDynamicPreferences.clear();
|
||||||
mDeletedChannels = null;
|
|
||||||
mShowLegacyChannelConfig = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addPreferencesFromResource(R.xml.notification_settings);
|
|
||||||
getPreferenceScreen().setOrderingAsAdded(true);
|
|
||||||
setupBlock();
|
|
||||||
addHeaderPref();
|
|
||||||
|
|
||||||
mShowLegacyChannelConfig = mBackend.onlyHasDefaultChannel(mAppRow.pkg, mAppRow.uid);
|
|
||||||
if (mShowLegacyChannelConfig) {
|
if (mShowLegacyChannelConfig) {
|
||||||
mChannel = mBackend.getChannel(
|
addPreferencesFromResource(R.xml.channel_notification_settings);
|
||||||
mAppRow.pkg, mAppRow.uid, NotificationChannel.DEFAULT_CHANNEL_ID);
|
|
||||||
populateDefaultChannelPrefs();
|
|
||||||
} else {
|
} else {
|
||||||
addPreferencesFromResource(R.xml.upgraded_app_notification_settings);
|
addPreferencesFromResource(R.xml.app_notification_settings);
|
||||||
setupBadge();
|
|
||||||
// Load channel settings
|
// Load channel settings
|
||||||
new AsyncTask<Void, Void, Void>() {
|
new AsyncTask<Void, Void, Void>() {
|
||||||
@Override
|
@Override
|
||||||
@@ -117,41 +90,59 @@ public class AppNotificationSettings extends NotificationSettingsBase {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
populateList();
|
populateList();
|
||||||
addAppLinkPref();
|
|
||||||
}
|
}
|
||||||
}.execute();
|
}.execute();
|
||||||
}
|
}
|
||||||
|
getPreferenceScreen().setOrderingAsAdded(true);
|
||||||
|
|
||||||
updateDependents(mAppRow.banned);
|
for (NotificationPreferenceController controller : mControllers) {
|
||||||
|
controller.onResume(mAppRow, mChannel, mChannelGroup, mSuspendedAppsAdmin);
|
||||||
|
controller.displayPreference(getPreferenceScreen());
|
||||||
|
}
|
||||||
|
updatePreferenceStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addHeaderPref() {
|
@Override
|
||||||
ArrayMap<String, AppRow> rows = new ArrayMap<>();
|
protected String getLogTag() {
|
||||||
rows.put(mAppRow.pkg, mAppRow);
|
return TAG;
|
||||||
collectConfigActivities(rows);
|
|
||||||
final Activity activity = getActivity();
|
|
||||||
final Preference pref = EntityHeaderController
|
|
||||||
.newInstance(activity, this /* fragment */, null /* header */)
|
|
||||||
.setRecyclerView(getListView(), getLifecycle())
|
|
||||||
.setIcon(mAppRow.icon)
|
|
||||||
.setLabel(mAppRow.label)
|
|
||||||
.setPackageName(mAppRow.pkg)
|
|
||||||
.setUid(mAppRow.uid)
|
|
||||||
.setHasAppInfoLink(true)
|
|
||||||
.setButtonActions(EntityHeaderController.ActionType.ACTION_NONE,
|
|
||||||
EntityHeaderController.ActionType.ACTION_NOTIF_PREFERENCE)
|
|
||||||
.done(activity, getPrefContext());
|
|
||||||
pref.setKey(KEY_HEADER);
|
|
||||||
getPreferenceScreen().addPreference(pref);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getPreferenceScreenResId() {
|
||||||
|
return R.xml.notification_settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
|
||||||
|
mControllers = new ArrayList<>();
|
||||||
|
mControllers.add(new HeaderPreferenceController(context, this));
|
||||||
|
mControllers.add(new BlockPreferenceController(context, mImportanceListener, mBackend));
|
||||||
|
mControllers.add(new BadgePreferenceController(context, mBackend));
|
||||||
|
mControllers.add(new AllowSoundPreferenceController(
|
||||||
|
context, mImportanceListener, mBackend));
|
||||||
|
mControllers.add(new ImportancePreferenceController(context));
|
||||||
|
mControllers.add(new SoundPreferenceController(context, this,
|
||||||
|
mImportanceListener, mBackend));
|
||||||
|
mControllers.add(new LightsPreferenceController(context, mBackend));
|
||||||
|
mControllers.add(new VibrationPreferenceController(context, mBackend));
|
||||||
|
mControllers.add(new VisibilityPreferenceController(context, new LockPatternUtils(context),
|
||||||
|
mBackend));
|
||||||
|
mControllers.add(new DndPreferenceController(context, getLifecycle(), mBackend));
|
||||||
|
mControllers.add(new AppLinkPreferenceController(context));
|
||||||
|
mControllers.add(new DescriptionPreferenceController(context));
|
||||||
|
mControllers.add(new NotificationsOffPreferenceController(context));
|
||||||
|
mControllers.add(new DeletedChannelsPreferenceController(context, mBackend));
|
||||||
|
return new ArrayList<>(mControllers);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void populateList() {
|
private void populateList() {
|
||||||
if (!mChannelGroups.isEmpty()) {
|
if (!mDynamicPreferences.isEmpty()) {
|
||||||
// If there's anything in mChannelGroups, we've called populateChannelList twice.
|
// If there's anything in mChannelGroups, we've called populateChannelList twice.
|
||||||
// Clear out existing channels and log.
|
// Clear out existing channels and log.
|
||||||
Log.w(TAG, "Notification channel group posted twice to settings - old size " +
|
Log.w(TAG, "Notification channel group posted twice to settings - old size " +
|
||||||
mChannelGroups.size() + ", new size " + mChannelGroupList.size());
|
mDynamicPreferences.size() + ", new size " + mChannelGroupList.size());
|
||||||
for (Preference p : mChannelGroups) {
|
for (Preference p : mDynamicPreferences) {
|
||||||
getPreferenceScreen().removePreference(p);
|
getPreferenceScreen().removePreference(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,7 +151,7 @@ public class AppNotificationSettings extends NotificationSettingsBase {
|
|||||||
groupCategory.setTitle(R.string.notification_channels);
|
groupCategory.setTitle(R.string.notification_channels);
|
||||||
groupCategory.setKey(KEY_GENERAL_CATEGORY);
|
groupCategory.setKey(KEY_GENERAL_CATEGORY);
|
||||||
getPreferenceScreen().addPreference(groupCategory);
|
getPreferenceScreen().addPreference(groupCategory);
|
||||||
mChannelGroups.add(groupCategory);
|
mDynamicPreferences.add(groupCategory);
|
||||||
|
|
||||||
Preference empty = new Preference(getPrefContext());
|
Preference empty = new Preference(getPrefContext());
|
||||||
empty.setTitle(R.string.no_channels);
|
empty.setTitle(R.string.no_channels);
|
||||||
@@ -168,20 +159,8 @@ public class AppNotificationSettings extends NotificationSettingsBase {
|
|||||||
groupCategory.addPreference(empty);
|
groupCategory.addPreference(empty);
|
||||||
} else {
|
} else {
|
||||||
populateGroupList();
|
populateGroupList();
|
||||||
int deletedChannelCount = mBackend.getDeletedChannelCount(mAppRow.pkg, mAppRow.uid);
|
mImportanceListener.onImportanceChanged();
|
||||||
if (deletedChannelCount > 0 &&
|
|
||||||
getPreferenceScreen().findPreference(KEY_DELETED) == null) {
|
|
||||||
mDeletedChannels = new FooterPreference(getPrefContext());
|
|
||||||
mDeletedChannels.setSelectable(false);
|
|
||||||
mDeletedChannels.setTitle(getResources().getQuantityString(
|
|
||||||
R.plurals.deleted_channels, deletedChannelCount, deletedChannelCount));
|
|
||||||
mDeletedChannels.setEnabled(false);
|
|
||||||
mDeletedChannels.setKey(KEY_DELETED);
|
|
||||||
mDeletedChannels.setOrder(ORDER_LAST);
|
|
||||||
getPreferenceScreen().addPreference(mDeletedChannels);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
updateDependents(mAppRow.banned);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populateGroupList() {
|
private void populateGroupList() {
|
||||||
@@ -190,7 +169,7 @@ public class AppNotificationSettings extends NotificationSettingsBase {
|
|||||||
groupCategory.setKey(KEY_GENERAL_CATEGORY);
|
groupCategory.setKey(KEY_GENERAL_CATEGORY);
|
||||||
groupCategory.setOrderingAsAdded(true);
|
groupCategory.setOrderingAsAdded(true);
|
||||||
getPreferenceScreen().addPreference(groupCategory);
|
getPreferenceScreen().addPreference(groupCategory);
|
||||||
mChannelGroups.add(groupCategory);
|
mDynamicPreferences.add(groupCategory);
|
||||||
for (NotificationChannelGroup group : mChannelGroupList) {
|
for (NotificationChannelGroup group : mChannelGroupList) {
|
||||||
final List<NotificationChannel> channels = group.getChannels();
|
final List<NotificationChannel> channels = group.getChannels();
|
||||||
int N = channels.size();
|
int N = channels.size();
|
||||||
@@ -240,91 +219,6 @@ public class AppNotificationSettings extends NotificationSettingsBase {
|
|||||||
parent.addPreference(groupPref);
|
parent.addPreference(groupPref);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupBadge() {
|
|
||||||
mBadge = (RestrictedSwitchPreference) getPreferenceScreen().findPreference(KEY_BADGE);
|
|
||||||
mBadge.setDisabledByAdmin(mSuspendedAppsAdmin);
|
|
||||||
if (mChannel == null) {
|
|
||||||
mBadge.setChecked(mAppRow.showBadge);
|
|
||||||
} else {
|
|
||||||
mBadge.setChecked(mChannel.canShowBadge());
|
|
||||||
}
|
|
||||||
mBadge.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
|
||||||
final boolean value = (Boolean) newValue;
|
|
||||||
if (mChannel == null) {
|
|
||||||
mBackend.setShowBadge(mPkg, mUid, value);
|
|
||||||
} else {
|
|
||||||
mChannel.setShowBadge(value);
|
|
||||||
mChannel.lockFields(NotificationChannel.USER_LOCKED_SHOW_BADGE);
|
|
||||||
mBackend.updateChannel(mPkg, mUid, mChannel);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setupBlock() {
|
|
||||||
View switchBarContainer = LayoutInflater.from(
|
|
||||||
getPrefContext()).inflate(R.layout.styled_switch_bar, null);
|
|
||||||
mSwitchBar = switchBarContainer.findViewById(R.id.switch_bar);
|
|
||||||
mSwitchBar.show();
|
|
||||||
mSwitchBar.setDisabledByAdmin(mSuspendedAppsAdmin);
|
|
||||||
mSwitchBar.setChecked(!mAppRow.banned);
|
|
||||||
mSwitchBar.addOnSwitchChangeListener(new SwitchBar.OnSwitchChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void onSwitchChanged(Switch switchView, boolean isChecked) {
|
|
||||||
if (mShowLegacyChannelConfig && mChannel != null) {
|
|
||||||
final int importance = isChecked ? IMPORTANCE_UNSPECIFIED : IMPORTANCE_NONE;
|
|
||||||
mImportanceToggle.setChecked(importance == IMPORTANCE_UNSPECIFIED);
|
|
||||||
mChannel.setImportance(importance);
|
|
||||||
mChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
|
|
||||||
mBackend.updateChannel(mPkg, mUid, mChannel);
|
|
||||||
}
|
|
||||||
mBackend.setNotificationsEnabledForPackage(mPkgInfo.packageName, mUid, isChecked);
|
|
||||||
mAppRow.banned = true;
|
|
||||||
updateDependents(!isChecked);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mBlockBar = new LayoutPreference(getPrefContext(), switchBarContainer);
|
|
||||||
mBlockBar.setOrder(ORDER_FIRST);
|
|
||||||
mBlockBar.setKey(KEY_BLOCK);
|
|
||||||
getPreferenceScreen().addPreference(mBlockBar);
|
|
||||||
|
|
||||||
if (mAppRow.systemApp && !mAppRow.banned) {
|
|
||||||
setVisible(mBlockBar, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
setupBlockDesc(R.string.app_notifications_off_desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void updateDependents(boolean banned) {
|
|
||||||
for (PreferenceCategory category : mChannelGroups) {
|
|
||||||
setVisible(category, !banned);
|
|
||||||
}
|
|
||||||
if (mDeletedChannels != null) {
|
|
||||||
setVisible(mDeletedChannels, !banned);
|
|
||||||
}
|
|
||||||
setVisible(mBlockedDesc, banned);
|
|
||||||
setVisible(mBadge, !banned);
|
|
||||||
if (mShowLegacyChannelConfig) {
|
|
||||||
setVisible(mImportanceToggle, !banned);
|
|
||||||
setVisible(mPriority, checkCanBeVisible(NotificationManager.IMPORTANCE_DEFAULT)
|
|
||||||
|| (checkCanBeVisible(NotificationManager.IMPORTANCE_LOW)
|
|
||||||
&& mDndVisualEffectsSuppressed));
|
|
||||||
setVisible(mVisibilityOverride, !banned &&
|
|
||||||
checkCanBeVisible(NotificationManager.IMPORTANCE_LOW) && isLockScreenSecure());
|
|
||||||
}
|
|
||||||
if (mAppLink != null) {
|
|
||||||
setVisible(mAppLink, !banned);
|
|
||||||
}
|
|
||||||
if (mAppRow.systemApp && !mAppRow.banned) {
|
|
||||||
setVisible(mBlockBar, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private Comparator<NotificationChannelGroup> mChannelGroupComparator =
|
private Comparator<NotificationChannelGroup> mChannelGroupComparator =
|
||||||
new Comparator<NotificationChannelGroup>() {
|
new Comparator<NotificationChannelGroup>() {
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import static android.provider.Settings.Secure.NOTIFICATION_BADGING;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
|
||||||
|
import com.android.settings.core.PreferenceControllerMixin;
|
||||||
|
import com.android.settingslib.RestrictedSwitchPreference;
|
||||||
|
|
||||||
|
public class BadgePreferenceController extends NotificationPreferenceController
|
||||||
|
implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
|
||||||
|
|
||||||
|
private static final String TAG = "BadgePrefContr";
|
||||||
|
private static final String KEY_BADGE = "badge";
|
||||||
|
private static final int SYSTEM_WIDE_ON = 1;
|
||||||
|
private static final int SYSTEM_WIDE_OFF = 0;
|
||||||
|
|
||||||
|
public BadgePreferenceController(Context context,
|
||||||
|
NotificationBackend backend) {
|
||||||
|
super(context, backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPreferenceKey() {
|
||||||
|
return KEY_BADGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
if (!super.isAvailable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mAppRow == null && mChannel == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Settings.Secure.getInt(mContext.getContentResolver(),
|
||||||
|
NOTIFICATION_BADGING, SYSTEM_WIDE_ON) == SYSTEM_WIDE_OFF) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mChannel != null && !mAppRow.showBadge) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
if (mAppRow != null) {
|
||||||
|
RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
|
||||||
|
pref.setDisabledByAdmin(mAdmin);
|
||||||
|
if (mChannel != null) {
|
||||||
|
pref.setChecked(mChannel.canShowBadge());
|
||||||
|
pref.setEnabled(isChannelConfigurable() && !pref.isDisabledByAdmin());
|
||||||
|
} else {
|
||||||
|
pref.setChecked(mAppRow.showBadge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
|
final boolean showBadge = (Boolean) newValue;
|
||||||
|
if (mChannel != null) {
|
||||||
|
mChannel.setShowBadge(showBadge);
|
||||||
|
saveChannel();
|
||||||
|
} else if (mAppRow != null){
|
||||||
|
mAppRow.showBadge = showBadge;
|
||||||
|
mBackend.setShowBadge(mAppRow.pkg, mAppRow.uid, showBadge);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
|
||||||
|
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
import android.widget.Switch;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.applications.LayoutPreference;
|
||||||
|
import com.android.settings.core.PreferenceControllerMixin;
|
||||||
|
import com.android.settings.widget.SwitchBar;
|
||||||
|
|
||||||
|
public class BlockPreferenceController extends NotificationPreferenceController
|
||||||
|
implements PreferenceControllerMixin, SwitchBar.OnSwitchChangeListener {
|
||||||
|
|
||||||
|
private static final String KEY_BLOCK = "block";
|
||||||
|
private NotificationSettingsBase.ImportanceListener mImportanceListener;
|
||||||
|
|
||||||
|
public BlockPreferenceController(Context context,
|
||||||
|
NotificationSettingsBase.ImportanceListener importanceListener,
|
||||||
|
NotificationBackend backend) {
|
||||||
|
super(context, backend);
|
||||||
|
mImportanceListener = importanceListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPreferenceKey() {
|
||||||
|
return KEY_BLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
if (mAppRow == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mChannel != null) {
|
||||||
|
return isChannelBlockable();
|
||||||
|
} else if (mChannelGroup != null && mChannelGroup.getGroup() != null) {
|
||||||
|
return isChannelGroupBlockable();
|
||||||
|
} else {
|
||||||
|
return !mAppRow.systemApp || (mAppRow.systemApp && mAppRow.banned);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
LayoutPreference pref = (LayoutPreference) preference;
|
||||||
|
SwitchBar bar = pref.findViewById(R.id.switch_bar);
|
||||||
|
if (bar != null) {
|
||||||
|
bar.show();
|
||||||
|
try {
|
||||||
|
bar.addOnSwitchChangeListener(this);
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// an exception is thrown if you try to add the listener twice
|
||||||
|
}
|
||||||
|
bar.setDisabledByAdmin(mAdmin);
|
||||||
|
|
||||||
|
if (mChannel != null) {
|
||||||
|
bar.setChecked(!mAppRow.banned
|
||||||
|
&& mChannel.getImportance() != NotificationManager.IMPORTANCE_NONE);
|
||||||
|
} else if (mChannelGroup != null && mChannelGroup.getGroup() != null) {
|
||||||
|
bar.setChecked(!mAppRow.banned && !mChannelGroup.isBlocked());
|
||||||
|
} else {
|
||||||
|
bar.setChecked(!mAppRow.banned);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSwitchChanged(Switch switchView, boolean isChecked) {
|
||||||
|
boolean blocked = !isChecked;
|
||||||
|
if (mChannel != null) {
|
||||||
|
final int originalImportance = mChannel.getImportance();
|
||||||
|
// setting the initial state of the switch in updateState() triggers this callback.
|
||||||
|
// It's always safe to override the importance if it's meant to be blocked or if
|
||||||
|
// it was blocked and we are unblocking it.
|
||||||
|
if (blocked || originalImportance == IMPORTANCE_NONE) {
|
||||||
|
final int importance = blocked ? IMPORTANCE_NONE
|
||||||
|
: DEFAULT_CHANNEL_ID.equals(mChannel.getId())
|
||||||
|
? IMPORTANCE_UNSPECIFIED : IMPORTANCE_DEFAULT;
|
||||||
|
mChannel.setImportance(importance);
|
||||||
|
saveChannel();
|
||||||
|
}
|
||||||
|
} else if (mChannelGroup != null && mChannelGroup.getGroup() != null) {
|
||||||
|
mChannelGroup.setBlocked(blocked);
|
||||||
|
mBackend.updateChannelGroup(mAppRow.pkg, mAppRow.uid, mChannelGroup.getGroup());
|
||||||
|
} else if (mAppRow != null) {
|
||||||
|
mAppRow.banned = blocked;
|
||||||
|
mBackend.setNotificationsEnabledForPackage(mAppRow.pkg, mAppRow.uid, !blocked);
|
||||||
|
}
|
||||||
|
mImportanceListener.onImportanceChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,20 +16,15 @@
|
|||||||
|
|
||||||
package com.android.settings.notification;
|
package com.android.settings.notification;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
|
import android.content.Context;
|
||||||
import android.support.v7.preference.Preference;
|
import android.support.v7.preference.Preference;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.ArrayMap;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
|
|
||||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.applications.LayoutPreference;
|
import com.android.settingslib.core.AbstractPreferenceController;
|
||||||
import com.android.settings.widget.EntityHeaderController;
|
|
||||||
import com.android.settingslib.widget.FooterPreference;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -38,12 +33,6 @@ import java.util.List;
|
|||||||
public class ChannelGroupNotificationSettings extends NotificationSettingsBase {
|
public class ChannelGroupNotificationSettings extends NotificationSettingsBase {
|
||||||
private static final String TAG = "ChannelGroupSettings";
|
private static final String TAG = "ChannelGroupSettings";
|
||||||
|
|
||||||
private static String KEY_DELETED = "deleted";
|
|
||||||
|
|
||||||
private EntityHeaderController mHeaderPref;
|
|
||||||
private List<Preference> mChannels = new ArrayList();
|
|
||||||
private FooterPreference mDeletedChannels;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMetricsCategory() {
|
public int getMetricsCategory() {
|
||||||
return MetricsEvent.NOTIFICATION_CHANNEL_GROUP;
|
return MetricsEvent.NOTIFICATION_CHANNEL_GROUP;
|
||||||
@@ -52,137 +41,68 @@ public class ChannelGroupNotificationSettings extends NotificationSettingsBase {
|
|||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
if (mUid < 0 || TextUtils.isEmpty(mPkg) || mPkgInfo == null || mChannelGroup == null) {
|
if (mAppRow == null || mChannelGroup == null || mChannelGroup.getGroup() == null) {
|
||||||
Log.w(TAG, "Missing package or uid or packageinfo or group");
|
Log.w(TAG, "Missing package or uid or packageinfo or group");
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getPreferenceScreen() != null) {
|
|
||||||
getPreferenceScreen().removeAll();
|
|
||||||
}
|
|
||||||
addPreferencesFromResource(R.xml.notification_settings);
|
|
||||||
setupBlock();
|
|
||||||
addHeaderPref();
|
|
||||||
addAppLinkPref();
|
|
||||||
addFooterPref();
|
|
||||||
populateChannelList();
|
populateChannelList();
|
||||||
|
for (NotificationPreferenceController controller : mControllers) {
|
||||||
updateDependents(mChannelGroup.isBlocked());
|
controller.onResume(mAppRow, mChannel, mChannelGroup, mSuspendedAppsAdmin);
|
||||||
|
controller.displayPreference(getPreferenceScreen());
|
||||||
|
}
|
||||||
|
updatePreferenceStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void setupBadge() {
|
protected String getLogTag() {
|
||||||
|
return TAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getPreferenceScreenResId() {
|
||||||
|
return R.xml.notification_group_settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
|
||||||
|
mControllers = new ArrayList<>();
|
||||||
|
mControllers.add(new HeaderPreferenceController(context, this));
|
||||||
|
mControllers.add(new BlockPreferenceController(context, mImportanceListener, mBackend));
|
||||||
|
mControllers.add(new AppLinkPreferenceController(context));
|
||||||
|
mControllers.add(new NotificationsOffPreferenceController(context));
|
||||||
|
mControllers.add(new DescriptionPreferenceController(context));
|
||||||
|
return new ArrayList<>(mControllers);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populateChannelList() {
|
private void populateChannelList() {
|
||||||
if (!mChannels.isEmpty()) {
|
if (!mDynamicPreferences.isEmpty()) {
|
||||||
// If there's anything in mChannels, we've called populateChannelList twice.
|
// If there's anything in mDynamicPreferences, we've called populateChannelList twice.
|
||||||
// Clear out existing channels and log.
|
// Clear out existing channels and log.
|
||||||
Log.w(TAG, "Notification channel group posted twice to settings - old size " +
|
Log.w(TAG, "Notification channel group posted twice to settings - old size " +
|
||||||
mChannels.size() + ", new size " + mChannels.size());
|
mDynamicPreferences.size() + ", new size " + mDynamicPreferences.size());
|
||||||
for (Preference p : mChannels) {
|
for (Preference p : mDynamicPreferences) {
|
||||||
getPreferenceScreen().removePreference(p);
|
getPreferenceScreen().removePreference(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mChannelGroup.getChannels().isEmpty()) {
|
if (mChannelGroup.getGroup().getChannels().isEmpty()) {
|
||||||
Preference empty = new Preference(getPrefContext());
|
Preference empty = new Preference(getPrefContext());
|
||||||
empty.setTitle(R.string.no_channels);
|
empty.setTitle(R.string.no_channels);
|
||||||
empty.setEnabled(false);
|
empty.setEnabled(false);
|
||||||
getPreferenceScreen().addPreference(empty);
|
getPreferenceScreen().addPreference(empty);
|
||||||
mChannels.add(empty);
|
mDynamicPreferences.add(empty);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
final List<NotificationChannel> channels = mChannelGroup.getChannels();
|
final List<NotificationChannel> channels = mChannelGroup.getGroup().getChannels();
|
||||||
Collections.sort(channels, mChannelComparator);
|
Collections.sort(channels, mChannelComparator);
|
||||||
for (NotificationChannel channel : channels) {
|
for (NotificationChannel channel : channels) {
|
||||||
mChannels.add(populateSingleChannelPrefs(
|
mDynamicPreferences.add(populateSingleChannelPrefs(
|
||||||
getPreferenceScreen(), channel, getImportanceSummary(channel)));
|
getPreferenceScreen(), channel,
|
||||||
|
ImportancePreferenceController.getImportanceSummary(
|
||||||
|
getPrefContext(), channel)));
|
||||||
}
|
}
|
||||||
|
|
||||||
int deletedChannelCount = mBackend.getDeletedChannelCount(mAppRow.pkg, mAppRow.uid);
|
|
||||||
if (deletedChannelCount > 0) {
|
|
||||||
mDeletedChannels = new FooterPreference(getPrefContext());
|
|
||||||
mDeletedChannels.setSelectable(false);
|
|
||||||
mDeletedChannels.setTitle(getResources().getQuantityString(
|
|
||||||
R.plurals.deleted_channels, deletedChannelCount, deletedChannelCount));
|
|
||||||
mDeletedChannels.setEnabled(false);
|
|
||||||
mDeletedChannels.setKey(KEY_DELETED);
|
|
||||||
mDeletedChannels.setOrder(ORDER_LAST);
|
|
||||||
getPreferenceScreen().addPreference(mDeletedChannels);
|
|
||||||
mChannels.add(mDeletedChannels);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDependents(mAppRow.banned);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addHeaderPref() {
|
|
||||||
ArrayMap<String, NotificationBackend.AppRow> rows = new ArrayMap<>();
|
|
||||||
rows.put(mAppRow.pkg, mAppRow);
|
|
||||||
collectConfigActivities(rows);
|
|
||||||
final Activity activity = getActivity();
|
|
||||||
mHeaderPref = EntityHeaderController
|
|
||||||
.newInstance(activity, this /* fragment */, null /* header */)
|
|
||||||
.setRecyclerView(getListView(), getLifecycle());
|
|
||||||
final Preference pref = mHeaderPref
|
|
||||||
.setIcon(mAppRow.icon)
|
|
||||||
.setLabel(mChannelGroup.getName())
|
|
||||||
.setSummary(mAppRow.label)
|
|
||||||
.setPackageName(mAppRow.pkg)
|
|
||||||
.setUid(mAppRow.uid)
|
|
||||||
.setButtonActions(EntityHeaderController.ActionType.ACTION_NOTIF_PREFERENCE,
|
|
||||||
EntityHeaderController.ActionType.ACTION_NONE)
|
|
||||||
.setHasAppInfoLink(true)
|
|
||||||
.done(activity, getPrefContext());
|
|
||||||
getPreferenceScreen().addPreference(pref);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addFooterPref() {
|
|
||||||
if (!TextUtils.isEmpty(mChannelGroup.getDescription())) {
|
|
||||||
FooterPreference descPref = new FooterPreference(getPrefContext());
|
|
||||||
descPref.setOrder(ORDER_LAST);
|
|
||||||
descPref.setSelectable(false);
|
|
||||||
descPref.setTitle(mChannelGroup.getDescription());
|
|
||||||
getPreferenceScreen().addPreference(descPref);
|
|
||||||
mChannels.add(descPref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupBlock() {
|
|
||||||
View switchBarContainer = LayoutInflater.from(
|
|
||||||
getPrefContext()).inflate(R.layout.styled_switch_bar, null);
|
|
||||||
mSwitchBar = switchBarContainer.findViewById(R.id.switch_bar);
|
|
||||||
mSwitchBar.show();
|
|
||||||
mSwitchBar.setDisabledByAdmin(mSuspendedAppsAdmin);
|
|
||||||
mSwitchBar.setChecked(!mChannelGroup.isBlocked());
|
|
||||||
mSwitchBar.addOnSwitchChangeListener((switchView, isChecked) -> {
|
|
||||||
mChannelGroup.setBlocked(!isChecked);
|
|
||||||
mBackend.updateChannelGroup(mPkg, mUid, mChannelGroup);
|
|
||||||
updateDependents(!isChecked);
|
|
||||||
});
|
|
||||||
|
|
||||||
mBlockBar = new LayoutPreference(getPrefContext(), switchBarContainer);
|
|
||||||
mBlockBar.setOrder(ORDER_FIRST);
|
|
||||||
mBlockBar.setKey(KEY_BLOCK);
|
|
||||||
getPreferenceScreen().addPreference(mBlockBar);
|
|
||||||
|
|
||||||
if (!isChannelGroupBlockable(mChannelGroup)) {
|
|
||||||
setVisible(mBlockBar, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
setupBlockDesc(R.string.channel_group_notifications_off_desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void updateDependents(boolean banned) {
|
|
||||||
for (Preference channel : mChannels) {
|
|
||||||
setVisible(channel, !banned);
|
|
||||||
}
|
|
||||||
if (mAppLink != null) {
|
|
||||||
setVisible(mAppLink, !banned);
|
|
||||||
}
|
|
||||||
setVisible(mBlockBar, isChannelGroupBlockable(mChannelGroup));
|
|
||||||
setVisible(mBlockedDesc, mAppRow.banned || mChannelGroup.isBlocked());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import com.android.settings.R;
|
|||||||
import com.android.settings.search.BaseSearchIndexProvider;
|
import com.android.settings.search.BaseSearchIndexProvider;
|
||||||
import com.android.settings.search.Indexable;
|
import com.android.settings.search.Indexable;
|
||||||
import com.android.settings.widget.RadioButtonPreference;
|
import com.android.settings.widget.RadioButtonPreference;
|
||||||
|
import com.android.settingslib.core.AbstractPreferenceController;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -60,8 +61,8 @@ public class ChannelImportanceSettings extends NotificationSettingsBase
|
|||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
if (mUid < 0 || TextUtils.isEmpty(mPkg) || mPkgInfo == null || mChannel == null) {
|
if (mAppRow == null || mChannel == null) {
|
||||||
Log.w(TAG, "Missing package or uid or packageinfo or channel");
|
Log.w(TAG, "Missing package or channel");
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -69,10 +70,19 @@ public class ChannelImportanceSettings extends NotificationSettingsBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void setupBadge() {}
|
protected String getLogTag() {
|
||||||
|
return TAG;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void updateDependents(boolean banned) {}
|
protected int getPreferenceScreenResId() {
|
||||||
|
return R.xml.notification_importance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
@@ -81,11 +91,6 @@ public class ChannelImportanceSettings extends NotificationSettingsBase
|
|||||||
|
|
||||||
private PreferenceScreen createPreferenceHierarchy() {
|
private PreferenceScreen createPreferenceHierarchy() {
|
||||||
PreferenceScreen root = getPreferenceScreen();
|
PreferenceScreen root = getPreferenceScreen();
|
||||||
if (root != null) {
|
|
||||||
root.removeAll();
|
|
||||||
}
|
|
||||||
addPreferencesFromResource(R.xml.notification_importance);
|
|
||||||
root = getPreferenceScreen();
|
|
||||||
|
|
||||||
for (int i = 0; i < root.getPreferenceCount(); i++) {
|
for (int i = 0; i < root.getPreferenceCount(); i++) {
|
||||||
Preference pref = root.getPreference(i);
|
Preference pref = root.getPreference(i);
|
||||||
@@ -148,8 +153,9 @@ public class ChannelImportanceSettings extends NotificationSettingsBase
|
|||||||
// but the sound you had selected was "Silence",
|
// but the sound you had selected was "Silence",
|
||||||
// then set sound for this channel to your default sound,
|
// then set sound for this channel to your default sound,
|
||||||
// because you probably intended to cause this channel to actually start making sound.
|
// because you probably intended to cause this channel to actually start making sound.
|
||||||
if (oldImportance < IMPORTANCE_DEFAULT && !hasValidSound(mChannel) &&
|
if (oldImportance < IMPORTANCE_DEFAULT
|
||||||
mChannel.getImportance() >= IMPORTANCE_DEFAULT) {
|
&& !SoundPreferenceController.hasValidSound(mChannel)
|
||||||
|
&& mChannel.getImportance() >= IMPORTANCE_DEFAULT) {
|
||||||
mChannel.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION),
|
mChannel.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION),
|
||||||
mChannel.getAudioAttributes());
|
mChannel.getAudioAttributes());
|
||||||
mChannel.lockFields(USER_LOCKED_SOUND);
|
mChannel.lockFields(USER_LOCKED_SOUND);
|
||||||
|
|||||||
@@ -16,59 +16,23 @@
|
|||||||
|
|
||||||
package com.android.settings.notification;
|
package com.android.settings.notification;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.content.Context;
|
||||||
import android.app.NotificationChannel;
|
|
||||||
import android.app.NotificationChannelGroup;
|
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.preference.PreferenceManager;
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.provider.Settings;
|
|
||||||
import android.support.v7.preference.Preference;
|
|
||||||
import android.support.v7.preference.PreferenceGroup;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.BidiFormatter;
|
|
||||||
import android.text.SpannableStringBuilder;
|
|
||||||
import android.util.ArrayMap;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.Switch;
|
|
||||||
|
|
||||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||||
|
import com.android.internal.widget.LockPatternUtils;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.RingtonePreference;
|
import com.android.settingslib.core.AbstractPreferenceController;
|
||||||
import com.android.settings.Utils;
|
|
||||||
import com.android.settings.applications.AppInfoBase;
|
|
||||||
import com.android.settings.applications.LayoutPreference;
|
|
||||||
import com.android.settings.widget.EntityHeaderController;
|
|
||||||
import com.android.settings.widget.SwitchBar;
|
|
||||||
import com.android.settingslib.RestrictedSwitchPreference;
|
|
||||||
import com.android.settingslib.widget.FooterPreference;
|
|
||||||
|
|
||||||
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
import java.util.ArrayList;
|
||||||
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
import java.util.List;
|
||||||
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
|
|
||||||
|
|
||||||
public class ChannelNotificationSettings extends NotificationSettingsBase {
|
public class ChannelNotificationSettings extends NotificationSettingsBase {
|
||||||
private static final String TAG = "ChannelSettings";
|
private static final String TAG = "ChannelSettings";
|
||||||
|
|
||||||
private static final String KEY_LIGHTS = "lights";
|
|
||||||
private static final String KEY_VIBRATE = "vibrate";
|
|
||||||
private static final String KEY_RINGTONE = "ringtone";
|
|
||||||
private static final String KEY_IMPORTANCE = "importance";
|
|
||||||
private static final String KEY_ADVANCED = "advanced";
|
|
||||||
|
|
||||||
private Preference mImportance;
|
|
||||||
private RestrictedSwitchPreference mLights;
|
|
||||||
private RestrictedSwitchPreference mVibrate;
|
|
||||||
private NotificationSoundPreference mRingtone;
|
|
||||||
private FooterPreference mFooter;
|
|
||||||
private NotificationChannelGroup mChannelGroup;
|
|
||||||
private EntityHeaderController mHeaderPref;
|
|
||||||
private PreferenceGroup mAdvanced;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMetricsCategory() {
|
public int getMetricsCategory() {
|
||||||
return MetricsEvent.NOTIFICATION_TOPIC_NOTIFICATION;
|
return MetricsEvent.NOTIFICATION_TOPIC_NOTIFICATION;
|
||||||
@@ -83,308 +47,52 @@ public class ChannelNotificationSettings extends NotificationSettingsBase {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getPreferenceScreen() != null) {
|
for (NotificationPreferenceController controller : mControllers) {
|
||||||
getPreferenceScreen().removeAll();
|
controller.onResume(mAppRow, mChannel, mChannelGroup, mSuspendedAppsAdmin);
|
||||||
|
controller.displayPreference(getPreferenceScreen());
|
||||||
}
|
}
|
||||||
addPreferencesFromResource(R.xml.notification_settings);
|
updatePreferenceStates();
|
||||||
setupBlock();
|
|
||||||
addHeaderPref();
|
|
||||||
addAppLinkPref();
|
|
||||||
addFooterPref();
|
|
||||||
|
|
||||||
if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(mChannel.getId())) {
|
|
||||||
populateDefaultChannelPrefs();
|
|
||||||
mShowLegacyChannelConfig = true;
|
|
||||||
} else {
|
|
||||||
populateUpgradedChannelPrefs();
|
|
||||||
|
|
||||||
if (mChannel.getGroup() != null) {
|
|
||||||
mChannelGroup = mBackend.getGroup(mPkg, mUid, mChannel.getGroup());
|
|
||||||
if (mChannelGroup != null) {
|
|
||||||
setChannelGroupLabel(mChannelGroup.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateDependents(mChannel.getImportance() == IMPORTANCE_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void populateUpgradedChannelPrefs() {
|
|
||||||
addPreferencesFromResource(R.xml.upgraded_channel_notification_settings);
|
|
||||||
setupBadge();
|
|
||||||
setupPriorityPref(mChannel.canBypassDnd());
|
|
||||||
setupVisOverridePref(mChannel.getLockscreenVisibility());
|
|
||||||
setupLights();
|
|
||||||
setupVibrate();
|
|
||||||
setupRingtone();
|
|
||||||
setupImportance();
|
|
||||||
mAdvanced = (PreferenceGroup) findPreference(KEY_ADVANCED);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addHeaderPref() {
|
|
||||||
ArrayMap<String, NotificationBackend.AppRow> rows = new ArrayMap<>();
|
|
||||||
rows.put(mAppRow.pkg, mAppRow);
|
|
||||||
collectConfigActivities(rows);
|
|
||||||
final Activity activity = getActivity();
|
|
||||||
mHeaderPref = EntityHeaderController
|
|
||||||
.newInstance(activity, this /* fragment */, null /* header */)
|
|
||||||
.setRecyclerView(getListView(), getLifecycle());
|
|
||||||
final Preference pref = mHeaderPref
|
|
||||||
.setIcon(mAppRow.icon)
|
|
||||||
.setLabel(mChannel.getName())
|
|
||||||
.setSummary(mAppRow.label)
|
|
||||||
.setPackageName(mAppRow.pkg)
|
|
||||||
.setUid(mAppRow.uid)
|
|
||||||
.setButtonActions(EntityHeaderController.ActionType.ACTION_NOTIF_PREFERENCE,
|
|
||||||
EntityHeaderController.ActionType.ACTION_NONE)
|
|
||||||
.setHasAppInfoLink(true)
|
|
||||||
.done(activity, getPrefContext());
|
|
||||||
getPreferenceScreen().addPreference(pref);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setChannelGroupLabel(CharSequence groupName) {
|
|
||||||
final SpannableStringBuilder summary = new SpannableStringBuilder();
|
|
||||||
BidiFormatter bidi = BidiFormatter.getInstance();
|
|
||||||
summary.append(bidi.unicodeWrap(mAppRow.label.toString()));
|
|
||||||
if (groupName != null) {
|
|
||||||
summary.append(bidi.unicodeWrap(mContext.getText(
|
|
||||||
R.string.notification_header_divider_symbol_with_spaces)));
|
|
||||||
summary.append(bidi.unicodeWrap(groupName.toString()));
|
|
||||||
}
|
|
||||||
final Activity activity = getActivity();
|
|
||||||
mHeaderPref.setSummary(summary.toString());
|
|
||||||
mHeaderPref.done(activity, getPrefContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addFooterPref() {
|
|
||||||
if (!TextUtils.isEmpty(mChannel.getDescription())) {
|
|
||||||
FooterPreference descPref = new FooterPreference(getPrefContext());
|
|
||||||
descPref.setOrder(ORDER_LAST);
|
|
||||||
descPref.setSelectable(false);
|
|
||||||
descPref.setTitle(mChannel.getDescription());
|
|
||||||
getPreferenceScreen().addPreference(descPref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setupBadge() {
|
|
||||||
mBadge = (RestrictedSwitchPreference) getPreferenceScreen().findPreference(KEY_BADGE);
|
|
||||||
mBadge.setDisabledByAdmin(mSuspendedAppsAdmin);
|
|
||||||
mBadge.setEnabled(mAppRow.showBadge);
|
|
||||||
mBadge.setChecked(mChannel.canShowBadge());
|
|
||||||
|
|
||||||
mBadge.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
|
||||||
final boolean value = (Boolean) newValue;
|
|
||||||
mChannel.setShowBadge(value);
|
|
||||||
mChannel.lockFields(NotificationChannel.USER_LOCKED_SHOW_BADGE);
|
|
||||||
mBackend.updateChannel(mPkg, mUid, mChannel);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupLights() {
|
|
||||||
mLights = (RestrictedSwitchPreference) findPreference(KEY_LIGHTS);
|
|
||||||
mLights.setDisabledByAdmin(mSuspendedAppsAdmin);
|
|
||||||
mLights.setChecked(mChannel.shouldShowLights());
|
|
||||||
mLights.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
|
||||||
final boolean lights = (Boolean) newValue;
|
|
||||||
mChannel.enableLights(lights);
|
|
||||||
mChannel.lockFields(NotificationChannel.USER_LOCKED_LIGHTS);
|
|
||||||
mBackend.updateChannel(mPkg, mUid, mChannel);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupVibrate() {
|
|
||||||
mVibrate = (RestrictedSwitchPreference) findPreference(KEY_VIBRATE);
|
|
||||||
mVibrate.setDisabledByAdmin(mSuspendedAppsAdmin);
|
|
||||||
mVibrate.setEnabled(!mVibrate.isDisabledByAdmin() && isChannelConfigurable(mChannel));
|
|
||||||
mVibrate.setChecked(mChannel.shouldVibrate());
|
|
||||||
mVibrate.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
|
||||||
final boolean vibrate = (Boolean) newValue;
|
|
||||||
mChannel.enableVibration(vibrate);
|
|
||||||
mChannel.lockFields(NotificationChannel.USER_LOCKED_VIBRATION);
|
|
||||||
mBackend.updateChannel(mPkg, mUid, mChannel);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupRingtone() {
|
|
||||||
mRingtone = (NotificationSoundPreference) findPreference(KEY_RINGTONE);
|
|
||||||
mRingtone.setRingtone(mChannel.getSound());
|
|
||||||
mRingtone.setEnabled(isChannelConfigurable(mChannel));
|
|
||||||
mRingtone.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
|
||||||
mChannel.setSound((Uri) newValue, mChannel.getAudioAttributes());
|
|
||||||
mChannel.lockFields(NotificationChannel.USER_LOCKED_SOUND);
|
|
||||||
mBackend.updateChannel(mPkg, mUid, mChannel);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupBlock() {
|
|
||||||
View switchBarContainer = LayoutInflater.from(
|
|
||||||
getPrefContext()).inflate(R.layout.styled_switch_bar, null);
|
|
||||||
mSwitchBar = switchBarContainer.findViewById(R.id.switch_bar);
|
|
||||||
mSwitchBar.show();
|
|
||||||
mSwitchBar.setDisabledByAdmin(mSuspendedAppsAdmin);
|
|
||||||
mSwitchBar.setChecked(mChannel.getImportance() != NotificationManager.IMPORTANCE_NONE);
|
|
||||||
mSwitchBar.addOnSwitchChangeListener(new SwitchBar.OnSwitchChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void onSwitchChanged(Switch switchView, boolean isChecked) {
|
|
||||||
int importance = 0;
|
|
||||||
if (mShowLegacyChannelConfig) {
|
|
||||||
importance = isChecked ? IMPORTANCE_UNSPECIFIED : IMPORTANCE_NONE;
|
|
||||||
mImportanceToggle.setChecked(importance == IMPORTANCE_UNSPECIFIED);
|
|
||||||
} else {
|
|
||||||
importance = isChecked ? IMPORTANCE_LOW : IMPORTANCE_NONE;
|
|
||||||
mImportance.setSummary(getImportanceSummary(importance));
|
|
||||||
}
|
|
||||||
mChannel.setImportance(importance);
|
|
||||||
mChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
|
|
||||||
mBackend.updateChannel(mPkg, mUid, mChannel);
|
|
||||||
updateDependents(mChannel.getImportance() == IMPORTANCE_NONE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mBlockBar = new LayoutPreference(getPrefContext(), switchBarContainer);
|
|
||||||
mBlockBar.setOrder(ORDER_FIRST);
|
|
||||||
mBlockBar.setKey(KEY_BLOCK);
|
|
||||||
getPreferenceScreen().addPreference(mBlockBar);
|
|
||||||
|
|
||||||
if (!isChannelBlockable(mChannel)) {
|
|
||||||
setVisible(mBlockBar, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
setupBlockDesc(R.string.channel_notifications_off_desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupImportance() {
|
|
||||||
mImportance = findPreference(KEY_IMPORTANCE);
|
|
||||||
Bundle channelArgs = new Bundle();
|
|
||||||
channelArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid);
|
|
||||||
channelArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mPkg);
|
|
||||||
channelArgs.putString(Settings.EXTRA_CHANNEL_ID, mChannel.getId());
|
|
||||||
mImportance.setEnabled(mSuspendedAppsAdmin == null && isChannelConfigurable(mChannel));
|
|
||||||
// Set up intent to show importance selection only if this setting is enabled.
|
|
||||||
if (mImportance.isEnabled()) {
|
|
||||||
Intent channelIntent = Utils.onBuildStartFragmentIntent(getActivity(),
|
|
||||||
ChannelImportanceSettings.class.getName(),
|
|
||||||
channelArgs, null, R.string.notification_importance_title, null,
|
|
||||||
false, getMetricsCategory());
|
|
||||||
mImportance.setIntent(channelIntent);
|
|
||||||
}
|
|
||||||
mImportance.setSummary(getImportanceSummary(mChannel.getImportance()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getImportanceSummary(int importance) {
|
|
||||||
String title;
|
|
||||||
String summary = null;
|
|
||||||
switch (importance) {
|
|
||||||
case IMPORTANCE_UNSPECIFIED:
|
|
||||||
title = getContext().getString(R.string.notification_importance_unspecified);
|
|
||||||
break;
|
|
||||||
case NotificationManager.IMPORTANCE_MIN:
|
|
||||||
title = getContext().getString(R.string.notification_importance_min_title);
|
|
||||||
summary = getContext().getString(R.string.notification_importance_min);
|
|
||||||
break;
|
|
||||||
case NotificationManager.IMPORTANCE_LOW:
|
|
||||||
title = getContext().getString(R.string.notification_importance_low_title);
|
|
||||||
summary = getContext().getString(R.string.notification_importance_low);
|
|
||||||
break;
|
|
||||||
case NotificationManager.IMPORTANCE_DEFAULT:
|
|
||||||
title = getContext().getString(R.string.notification_importance_default_title);
|
|
||||||
if (hasValidSound(mChannel)) {
|
|
||||||
summary = getContext().getString(R.string.notification_importance_default);
|
|
||||||
} else {
|
|
||||||
summary = getContext().getString(R.string.notification_importance_low);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotificationManager.IMPORTANCE_HIGH:
|
|
||||||
case NotificationManager.IMPORTANCE_MAX:
|
|
||||||
title = getContext().getString(R.string.notification_importance_high_title);
|
|
||||||
if (hasValidSound(mChannel)) {
|
|
||||||
summary = getContext().getString(R.string.notification_importance_high);
|
|
||||||
} else {
|
|
||||||
summary = getContext().getString(R.string.notification_importance_high_silent);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (summary != null) {
|
|
||||||
return getContext().getString(R.string.notification_importance_divider, title, summary);
|
|
||||||
} else {
|
|
||||||
return title;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onPreferenceTreeClick(Preference preference) {
|
|
||||||
if (preference instanceof RingtonePreference) {
|
|
||||||
mRingtone.onPrepareRingtonePickerIntent(mRingtone.getIntent());
|
|
||||||
startActivityForResult(preference.getIntent(), 200);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return super.onPreferenceTreeClick(preference);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
if (mRingtone != null) {
|
for (NotificationPreferenceController controller : mControllers) {
|
||||||
mRingtone.onActivityResult(requestCode, resultCode, data);
|
if (controller instanceof PreferenceManager.OnActivityResultListener) {
|
||||||
}
|
((PreferenceManager.OnActivityResultListener) controller)
|
||||||
if (mChannel != null) {
|
.onActivityResult(requestCode, resultCode, data);
|
||||||
mImportance.setSummary(getImportanceSummary(mChannel.getImportance()));
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean canPulseLight() {
|
@Override
|
||||||
if (!getResources()
|
protected String getLogTag() {
|
||||||
.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed)) {
|
return TAG;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return Settings.System.getInt(getContentResolver(),
|
|
||||||
Settings.System.NOTIFICATION_LIGHT_PULSE, 0) == 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateDependents(boolean banned) {
|
@Override
|
||||||
PreferenceGroup parent;
|
protected int getPreferenceScreenResId() {
|
||||||
if (mShowLegacyChannelConfig) {
|
return R.xml.channel_notification_settings;
|
||||||
parent = getPreferenceScreen();
|
}
|
||||||
setVisible(mImportanceToggle, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN));
|
|
||||||
} else {
|
@Override
|
||||||
setVisible(mAdvanced, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN));
|
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
|
||||||
setVisible(mImportance, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN));
|
mControllers = new ArrayList<>();
|
||||||
setVisible(mAdvanced, mLights, checkCanBeVisible(
|
mControllers.add(new HeaderPreferenceController(context, this));
|
||||||
NotificationManager.IMPORTANCE_DEFAULT) && canPulseLight());
|
mControllers.add(new BlockPreferenceController(context, mImportanceListener, mBackend));
|
||||||
setVisible(mVibrate, checkCanBeVisible(NotificationManager.IMPORTANCE_DEFAULT));
|
mControllers.add(new ImportancePreferenceController(context));
|
||||||
setVisible(mRingtone, checkCanBeVisible(NotificationManager.IMPORTANCE_DEFAULT));
|
mControllers.add(new AllowSoundPreferenceController(
|
||||||
parent = mAdvanced;
|
context, mImportanceListener, mBackend));
|
||||||
}
|
mControllers.add(new SoundPreferenceController(context, this,
|
||||||
setVisible(parent, mBadge, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN));
|
mImportanceListener, mBackend));
|
||||||
setVisible(parent, mPriority, checkCanBeVisible(NotificationManager.IMPORTANCE_DEFAULT)
|
mControllers.add(new VibrationPreferenceController(context, mBackend));
|
||||||
|| (checkCanBeVisible(NotificationManager.IMPORTANCE_LOW)
|
mControllers.add(new AppLinkPreferenceController(context));
|
||||||
&& mDndVisualEffectsSuppressed));
|
mControllers.add(new DescriptionPreferenceController(context));
|
||||||
setVisible(parent, mVisibilityOverride, isLockScreenSecure()
|
mControllers.add(new VisibilityPreferenceController(context, new LockPatternUtils(context),
|
||||||
&&checkCanBeVisible(NotificationManager.IMPORTANCE_LOW));
|
mBackend));
|
||||||
setVisible(mBlockedDesc, mChannel.getImportance() == IMPORTANCE_NONE);
|
mControllers.add(new LightsPreferenceController(context, mBackend));
|
||||||
if (mAppLink != null) {
|
mControllers.add(new BadgePreferenceController(context, mBackend));
|
||||||
setVisible(mAppLink, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN));
|
mControllers.add(new DndPreferenceController(context, getLifecycle(), mBackend));
|
||||||
}
|
mControllers.add(new NotificationsOffPreferenceController(context));
|
||||||
if (mFooter != null) {
|
return new ArrayList<>(mControllers);
|
||||||
setVisible(mFooter, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.core.PreferenceControllerMixin;
|
||||||
|
|
||||||
|
public class DeletedChannelsPreferenceController extends NotificationPreferenceController
|
||||||
|
implements PreferenceControllerMixin {
|
||||||
|
|
||||||
|
private static final String KEY_DELETED = "deleted";
|
||||||
|
|
||||||
|
public DeletedChannelsPreferenceController(Context context, NotificationBackend backend) {
|
||||||
|
super(context, backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPreferenceKey() {
|
||||||
|
return KEY_DELETED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
if (!super.isAvailable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// only visible on app screen
|
||||||
|
if (mChannel != null || hasValidGroup()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mBackend.getDeletedChannelCount(mAppRow.pkg, mAppRow.uid) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
if (mAppRow != null) {
|
||||||
|
int deletedChannelCount = mBackend.getDeletedChannelCount(mAppRow.pkg, mAppRow.uid);
|
||||||
|
preference.setTitle(mContext.getResources().getQuantityString(
|
||||||
|
R.plurals.deleted_channels, deletedChannelCount, deletedChannelCount));
|
||||||
|
}
|
||||||
|
preference.setEnabled(false);
|
||||||
|
preference.setSelectable(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import com.android.settings.core.PreferenceControllerMixin;
|
||||||
|
|
||||||
|
public class DescriptionPreferenceController extends NotificationPreferenceController
|
||||||
|
implements PreferenceControllerMixin {
|
||||||
|
|
||||||
|
private static final String KEY_DESC = "desc";
|
||||||
|
|
||||||
|
public DescriptionPreferenceController(Context context) {
|
||||||
|
super(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPreferenceKey() {
|
||||||
|
return KEY_DESC;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
if (!super.isAvailable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mChannel == null && !hasValidGroup()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mChannel != null && !TextUtils.isEmpty(mChannel.getDescription())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (hasValidGroup() && !TextUtils.isEmpty(mChannelGroup.getDescription())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
if (mAppRow != null) {
|
||||||
|
if (mChannel != null) {
|
||||||
|
preference.setTitle(mChannel.getDescription());
|
||||||
|
} else if (hasValidGroup()) {
|
||||||
|
preference.setTitle(mChannelGroup.getDescription());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
preference.setEnabled(false);
|
||||||
|
preference.setSelectable(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
|
||||||
|
import com.android.settings.core.PreferenceControllerMixin;
|
||||||
|
import com.android.settingslib.RestrictedSwitchPreference;
|
||||||
|
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||||
|
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||||
|
import com.android.settingslib.core.lifecycle.events.OnResume;
|
||||||
|
|
||||||
|
public class DndPreferenceController extends NotificationPreferenceController
|
||||||
|
implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener,
|
||||||
|
LifecycleObserver, OnResume {
|
||||||
|
|
||||||
|
private static final String KEY_BYPASS_DND = "bypass_dnd";
|
||||||
|
private boolean mVisualEffectsSuppressed;
|
||||||
|
|
||||||
|
public DndPreferenceController(Context context, Lifecycle lifecycle,
|
||||||
|
NotificationBackend backend) {
|
||||||
|
super(context, backend);
|
||||||
|
if (lifecycle != null) {
|
||||||
|
lifecycle.addObserver(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
NotificationManager.Policy policy = mNm.getNotificationPolicy();
|
||||||
|
mVisualEffectsSuppressed = policy != null && policy.suppressedVisualEffects != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPreferenceKey() {
|
||||||
|
return KEY_BYPASS_DND;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
if (!super.isAvailable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return checkCanBeVisible(NotificationManager.IMPORTANCE_DEFAULT)
|
||||||
|
|| (checkCanBeVisible(NotificationManager.IMPORTANCE_LOW)
|
||||||
|
&& mVisualEffectsSuppressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
if (mChannel != null) {
|
||||||
|
RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
|
||||||
|
pref.setDisabledByAdmin(mAdmin);
|
||||||
|
pref.setEnabled(isChannelConfigurable() && !pref.isDisabledByAdmin());
|
||||||
|
pref.setChecked(mChannel.canBypassDnd());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
|
if (mChannel != null) {
|
||||||
|
final boolean bypassZenMode = (Boolean) newValue;
|
||||||
|
mChannel.setBypassDnd(bypassZenMode);
|
||||||
|
mChannel.lockFields(NotificationChannel.USER_LOCKED_PRIORITY);
|
||||||
|
saveChannel();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import static com.android.settings.widget.EntityHeaderController.PREF_KEY_APP_HEADER;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.v14.preference.PreferenceFragment;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
import android.text.BidiFormatter;
|
||||||
|
import android.text.SpannableStringBuilder;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.applications.LayoutPreference;
|
||||||
|
import com.android.settings.core.PreferenceControllerMixin;
|
||||||
|
import com.android.settings.widget.EntityHeaderController;
|
||||||
|
|
||||||
|
public class HeaderPreferenceController extends NotificationPreferenceController
|
||||||
|
implements PreferenceControllerMixin {
|
||||||
|
|
||||||
|
private final PreferenceFragment mFragment;
|
||||||
|
|
||||||
|
public HeaderPreferenceController(Context context, PreferenceFragment fragment) {
|
||||||
|
super(context, null);
|
||||||
|
mFragment = fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPreferenceKey() {
|
||||||
|
return PREF_KEY_APP_HEADER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
return mAppRow != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
if (mAppRow != null && mFragment != null) {
|
||||||
|
LayoutPreference pref = (LayoutPreference) preference;
|
||||||
|
EntityHeaderController controller = EntityHeaderController
|
||||||
|
.newInstance(mFragment.getActivity(), mFragment,
|
||||||
|
pref.findViewById(R.id.entity_header));
|
||||||
|
pref = controller.setIcon(mAppRow.icon)
|
||||||
|
.setLabel(getLabel())
|
||||||
|
.setSummary(getSummary())
|
||||||
|
.setPackageName(mAppRow.pkg)
|
||||||
|
.setUid(mAppRow.uid)
|
||||||
|
.setButtonActions(EntityHeaderController.ActionType.ACTION_NOTIF_PREFERENCE,
|
||||||
|
EntityHeaderController.ActionType.ACTION_NONE)
|
||||||
|
.setHasAppInfoLink(true)
|
||||||
|
.done(mFragment.getActivity(), mContext);
|
||||||
|
pref.findViewById(R.id.entity_header).setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CharSequence getLabel() {
|
||||||
|
return mChannel != null ? mChannel.getName()
|
||||||
|
: mChannelGroup != null && mChannelGroup.getGroup() != null
|
||||||
|
? mChannelGroup.getGroup().getName()
|
||||||
|
: mAppRow.label;
|
||||||
|
}
|
||||||
|
|
||||||
|
CharSequence getSummary() {
|
||||||
|
if (mChannel != null) {
|
||||||
|
if (mChannelGroup != null && mChannelGroup.getGroup() != null
|
||||||
|
&& !TextUtils.isEmpty(mChannelGroup.getGroup().getName())) {
|
||||||
|
final SpannableStringBuilder summary = new SpannableStringBuilder();
|
||||||
|
BidiFormatter bidi = BidiFormatter.getInstance();
|
||||||
|
summary.append(bidi.unicodeWrap(mAppRow.label.toString()));
|
||||||
|
summary.append(bidi.unicodeWrap(mContext.getText(
|
||||||
|
R.string.notification_header_divider_symbol_with_spaces)));
|
||||||
|
summary.append(bidi.unicodeWrap(mChannelGroup.getGroup().getName().toString()));
|
||||||
|
return summary;
|
||||||
|
} else {
|
||||||
|
return mAppRow.label;
|
||||||
|
}
|
||||||
|
} else if (mChannelGroup != null && mChannelGroup.getGroup() != null) {
|
||||||
|
return mAppRow.label;
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
|
||||||
|
import com.android.internal.logging.nano.MetricsProto;
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.Utils;
|
||||||
|
import com.android.settings.applications.AppInfoBase;
|
||||||
|
import com.android.settings.core.PreferenceControllerMixin;
|
||||||
|
|
||||||
|
public class ImportancePreferenceController extends NotificationPreferenceController
|
||||||
|
implements PreferenceControllerMixin {
|
||||||
|
|
||||||
|
private static final String KEY_IMPORTANCE = "importance";
|
||||||
|
|
||||||
|
// Ironically doesn't take an importance listener because the importance is not changed
|
||||||
|
// by this controller's preference but by the screen it links to.
|
||||||
|
public ImportancePreferenceController(Context context) {
|
||||||
|
super(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPreferenceKey() {
|
||||||
|
return KEY_IMPORTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getMetricsCategory() {
|
||||||
|
return MetricsProto.MetricsEvent.NOTIFICATION_TOPIC_NOTIFICATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
if (!super.isAvailable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mChannel == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !NotificationChannel.DEFAULT_CHANNEL_ID.equals(mChannel.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
if (mAppRow!= null && mChannel != null) {
|
||||||
|
preference.setEnabled(mAdmin == null && isChannelConfigurable());
|
||||||
|
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, mChannel.getId());
|
||||||
|
if (preference.isEnabled()) {
|
||||||
|
Intent channelIntent = Utils.onBuildStartFragmentIntent(mContext,
|
||||||
|
ChannelImportanceSettings.class.getName(),
|
||||||
|
channelArgs, null, R.string.notification_importance_title, null,
|
||||||
|
false, getMetricsCategory());
|
||||||
|
preference.setIntent(channelIntent);
|
||||||
|
preference.setSummary(getImportanceSummary(mContext, mChannel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static String getImportanceSummary(Context context, NotificationChannel channel) {
|
||||||
|
String title;
|
||||||
|
String summary = null;
|
||||||
|
int importance = channel.getImportance();
|
||||||
|
switch (importance) {
|
||||||
|
case IMPORTANCE_UNSPECIFIED:
|
||||||
|
title = context.getString(R.string.notification_importance_unspecified);
|
||||||
|
break;
|
||||||
|
case NotificationManager.IMPORTANCE_MIN:
|
||||||
|
title = context.getString(R.string.notification_importance_min_title);
|
||||||
|
summary = context.getString(R.string.notification_importance_min);
|
||||||
|
break;
|
||||||
|
case NotificationManager.IMPORTANCE_LOW:
|
||||||
|
title = context.getString(R.string.notification_importance_low_title);
|
||||||
|
summary = context.getString(R.string.notification_importance_low);
|
||||||
|
break;
|
||||||
|
case NotificationManager.IMPORTANCE_DEFAULT:
|
||||||
|
title = context.getString(R.string.notification_importance_default_title);
|
||||||
|
if (SoundPreferenceController.hasValidSound(channel)) {
|
||||||
|
summary = context.getString(R.string.notification_importance_default);
|
||||||
|
} else {
|
||||||
|
summary = context.getString(R.string.notification_importance_low);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NotificationManager.IMPORTANCE_HIGH:
|
||||||
|
case NotificationManager.IMPORTANCE_MAX:
|
||||||
|
title = context.getString(R.string.notification_importance_high_title);
|
||||||
|
if (SoundPreferenceController.hasValidSound(channel)) {
|
||||||
|
summary = context.getString(R.string.notification_importance_high);
|
||||||
|
} else {
|
||||||
|
summary = context.getString(R.string.notification_importance_high_silent);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (summary != null) {
|
||||||
|
return context.getString(R.string.notification_importance_divider, title, summary);
|
||||||
|
} else {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
|
||||||
|
import com.android.settings.core.PreferenceControllerMixin;
|
||||||
|
import com.android.settingslib.RestrictedSwitchPreference;
|
||||||
|
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||||
|
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||||
|
import com.android.settingslib.core.lifecycle.events.OnResume;
|
||||||
|
|
||||||
|
public class LightsPreferenceController extends NotificationPreferenceController
|
||||||
|
implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
|
||||||
|
|
||||||
|
private static final String KEY_LIGHTS = "lights";
|
||||||
|
|
||||||
|
public LightsPreferenceController(Context context, NotificationBackend backend) {
|
||||||
|
super(context, backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPreferenceKey() {
|
||||||
|
return KEY_LIGHTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
if (!super.isAvailable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mChannel == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return checkCanBeVisible(NotificationManager.IMPORTANCE_DEFAULT) && canPulseLight()
|
||||||
|
&& !NotificationChannel.DEFAULT_CHANNEL_ID.equals(mChannel.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
if (mChannel != null) {
|
||||||
|
RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
|
||||||
|
pref.setDisabledByAdmin(mAdmin);
|
||||||
|
pref.setEnabled(isChannelConfigurable() && !pref.isDisabledByAdmin());
|
||||||
|
pref.setChecked(mChannel.shouldShowLights());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
|
if (mChannel != null) {
|
||||||
|
final boolean lights = (Boolean) newValue;
|
||||||
|
mChannel.enableLights(lights);
|
||||||
|
saveChannel();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean canPulseLight() {
|
||||||
|
if (!mContext.getResources()
|
||||||
|
.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Settings.System.getInt(mContext.getContentResolver(),
|
||||||
|
Settings.System.NOTIFICATION_LIGHT_PULSE, 0) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.v4.content.res.TypedArrayUtils;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
import android.support.v7.preference.PreferenceViewHolder;
|
||||||
|
import android.text.method.LinkMovementMethod;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.android.settingslib.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FooterPreference that can have any key or ordering.
|
||||||
|
*/
|
||||||
|
public class NotificationFooterPreference extends Preference {
|
||||||
|
|
||||||
|
public NotificationFooterPreference(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs, TypedArrayUtils.getAttr(
|
||||||
|
context, R.attr.footerPreferenceStyle, android.R.attr.preferenceStyle));
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotificationFooterPreference(Context context) {
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(PreferenceViewHolder holder) {
|
||||||
|
super.onBindViewHolder(holder);
|
||||||
|
TextView title = holder.itemView.findViewById(android.R.id.title);
|
||||||
|
title.setMovementMethod(new LinkMovementMethod());
|
||||||
|
title.setClickable(false);
|
||||||
|
title.setLongClickable(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
setIcon(R.drawable.ic_info_outline_24dp);
|
||||||
|
setSelectable(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
||||||
|
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationChannelGroup;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
import android.support.v7.preference.PreferenceGroup;
|
||||||
|
import android.support.v7.preference.PreferenceScreen;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.settings.wrapper.NotificationChannelGroupWrapper;
|
||||||
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
|
import com.android.settingslib.core.AbstractPreferenceController;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parent class for preferences appearing on notification setting pages at the app,
|
||||||
|
* notification channel group, or notification channel level.
|
||||||
|
*/
|
||||||
|
public abstract class NotificationPreferenceController extends AbstractPreferenceController
|
||||||
|
{
|
||||||
|
private static final String TAG = "ChannelPrefContr";
|
||||||
|
@Nullable protected NotificationChannel mChannel;
|
||||||
|
@Nullable protected NotificationChannelGroupWrapper mChannelGroup;
|
||||||
|
protected RestrictedLockUtils.EnforcedAdmin mAdmin;
|
||||||
|
protected NotificationBackend.AppRow mAppRow;
|
||||||
|
protected final NotificationManager mNm;
|
||||||
|
protected final NotificationBackend mBackend;
|
||||||
|
protected final Context mContext;
|
||||||
|
protected final UserManager mUm;
|
||||||
|
protected final PackageManager mPm;
|
||||||
|
protected Preference mPreference;
|
||||||
|
|
||||||
|
public NotificationPreferenceController(Context context, NotificationBackend backend) {
|
||||||
|
super(context);
|
||||||
|
mContext = context;
|
||||||
|
mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
mBackend = backend;
|
||||||
|
mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
|
||||||
|
mPm = mContext.getPackageManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if field's parent object is not blocked.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
if (mAppRow == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mAppRow.banned) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mChannel != null) {
|
||||||
|
return mChannel.getImportance() != IMPORTANCE_NONE;
|
||||||
|
}
|
||||||
|
if (mChannelGroup != null && mChannelGroup.getGroup() == null) {
|
||||||
|
return !mChannelGroup.isBlocked();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays or removes preference in this controller.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void displayPreference(PreferenceScreen screen) {
|
||||||
|
if (isAvailable()) {
|
||||||
|
final Preference preference = screen.findPreference(getPreferenceKey());
|
||||||
|
if (mPreference != null && preference == null) {
|
||||||
|
screen.addPreference(mPreference);
|
||||||
|
}
|
||||||
|
if (preference != null) {
|
||||||
|
mPreference = preference;
|
||||||
|
}
|
||||||
|
if (this instanceof Preference.OnPreferenceChangeListener) {
|
||||||
|
mPreference.setOnPreferenceChangeListener(
|
||||||
|
(Preference.OnPreferenceChangeListener) this);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
findAndRemovePreference(screen, getPreferenceKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// finds the preference recursively and removes it from its parent
|
||||||
|
private void findAndRemovePreference(PreferenceGroup prefGroup, String key) {
|
||||||
|
final int preferenceCount = prefGroup.getPreferenceCount();
|
||||||
|
for (int i = preferenceCount - 1; i >= 0; i--) {
|
||||||
|
final Preference preference = prefGroup.getPreference(i);
|
||||||
|
final String curKey = preference.getKey();
|
||||||
|
|
||||||
|
if (curKey != null && curKey.equals(key)) {
|
||||||
|
mPreference = preference;
|
||||||
|
prefGroup.removePreference(preference);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preference instanceof PreferenceGroup) {
|
||||||
|
findAndRemovePreference((PreferenceGroup) preference, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onResume(NotificationBackend.AppRow appRow,
|
||||||
|
@Nullable NotificationChannel channel, @Nullable NotificationChannelGroupWrapper group,
|
||||||
|
RestrictedLockUtils.EnforcedAdmin admin) {
|
||||||
|
mAppRow = appRow;
|
||||||
|
mChannel = channel;
|
||||||
|
mChannelGroup = group;
|
||||||
|
mAdmin = admin;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean checkCanBeVisible(int minImportanceVisible) {
|
||||||
|
if (mChannel == null) {
|
||||||
|
Log.w(TAG, "No channel");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int importance = mChannel.getImportance();
|
||||||
|
if (importance == NotificationManager.IMPORTANCE_UNSPECIFIED) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return importance >= minImportanceVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void saveChannel() {
|
||||||
|
if (mChannel != null && mAppRow != null) {
|
||||||
|
mBackend.updateChannel(mAppRow.pkg, mAppRow.uid, mChannel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isChannelConfigurable() {
|
||||||
|
if (mChannel != null && mAppRow != null) {
|
||||||
|
return !Objects.equals(mChannel.getId(), mAppRow.lockedChannelId);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isChannelBlockable() {
|
||||||
|
if (mChannel != null && mAppRow != null) {
|
||||||
|
if (!mAppRow.systemApp) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mChannel.isBlockableSystem()
|
||||||
|
|| mChannel.getImportance() == IMPORTANCE_NONE;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isChannelGroupBlockable() {
|
||||||
|
if (mChannelGroup != null && mChannelGroup.getGroup() == null && mAppRow != null) {
|
||||||
|
if (!mAppRow.systemApp) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mChannelGroup.isBlocked();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean hasValidGroup() {
|
||||||
|
return mChannelGroup != null && mChannelGroup.getGroup() != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,10 +27,15 @@ import com.android.settings.SettingsPreferenceFragment;
|
|||||||
import com.android.settings.Utils;
|
import com.android.settings.Utils;
|
||||||
import com.android.settings.applications.AppInfoBase;
|
import com.android.settings.applications.AppInfoBase;
|
||||||
import com.android.settings.applications.LayoutPreference;
|
import com.android.settings.applications.LayoutPreference;
|
||||||
|
import com.android.settings.dashboard.DashboardFragment;
|
||||||
|
import com.android.settings.search.BaseSearchIndexProvider;
|
||||||
|
import com.android.settings.search.Indexable;
|
||||||
import com.android.settings.widget.MasterSwitchPreference;
|
import com.android.settings.widget.MasterSwitchPreference;
|
||||||
import com.android.settings.widget.SwitchBar;
|
import com.android.settings.widget.SwitchBar;
|
||||||
|
import com.android.settings.wrapper.NotificationChannelGroupWrapper;
|
||||||
import com.android.settingslib.RestrictedLockUtils;
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
import com.android.settingslib.RestrictedSwitchPreference;
|
import com.android.settingslib.RestrictedSwitchPreference;
|
||||||
|
import com.android.settingslib.core.AbstractPreferenceController;
|
||||||
import com.android.settingslib.widget.FooterPreference;
|
import com.android.settingslib.widget.FooterPreference;
|
||||||
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
@@ -53,10 +58,12 @@ import android.net.Uri;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
|
import android.provider.SearchIndexableResource;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.service.notification.NotificationListenerService;
|
import android.service.notification.NotificationListenerService;
|
||||||
import android.support.v7.preference.Preference;
|
import android.support.v7.preference.Preference;
|
||||||
import android.support.v7.preference.PreferenceGroup;
|
import android.support.v7.preference.PreferenceGroup;
|
||||||
|
import android.support.v7.preference.PreferenceScreen;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -68,66 +75,30 @@ import java.util.ArrayList;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
abstract public class NotificationSettingsBase extends SettingsPreferenceFragment {
|
abstract public class NotificationSettingsBase extends DashboardFragment {
|
||||||
private static final String TAG = "NotifiSettingsBase";
|
private static final String TAG = "NotifiSettingsBase";
|
||||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||||
|
|
||||||
private static final Intent APP_NOTIFICATION_PREFS_CATEGORY_INTENT
|
|
||||||
= new Intent(Intent.ACTION_MAIN)
|
|
||||||
.addCategory(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES);
|
|
||||||
|
|
||||||
protected static final int ORDER_FIRST = -500;
|
|
||||||
protected static final int ORDER_LAST = 1000;
|
|
||||||
|
|
||||||
protected static final String KEY_APP_LINK = "app_link";
|
|
||||||
protected static final String KEY_HEADER = "header";
|
|
||||||
protected static final String KEY_BLOCK = "block";
|
|
||||||
protected static final String KEY_BADGE = "badge";
|
|
||||||
protected static final String KEY_BYPASS_DND = "bypass_dnd";
|
|
||||||
protected static final String KEY_VISIBILITY_OVERRIDE = "visibility_override";
|
|
||||||
protected static final String KEY_BLOCKED_DESC = "block_desc";
|
|
||||||
protected static final String KEY_ALLOW_SOUND = "allow_sound";
|
|
||||||
|
|
||||||
protected PackageManager mPm;
|
protected PackageManager mPm;
|
||||||
protected UserManager mUm;
|
|
||||||
protected NotificationBackend mBackend = new NotificationBackend();
|
protected NotificationBackend mBackend = new NotificationBackend();
|
||||||
protected LockPatternUtils mLockPatternUtils;
|
|
||||||
protected NotificationManager mNm;
|
protected NotificationManager mNm;
|
||||||
protected Context mContext;
|
protected Context mContext;
|
||||||
protected boolean mCreated;
|
|
||||||
protected int mUid;
|
protected int mUid;
|
||||||
protected int mUserId;
|
protected int mUserId;
|
||||||
protected String mPkg;
|
protected String mPkg;
|
||||||
protected PackageInfo mPkgInfo;
|
protected PackageInfo mPkgInfo;
|
||||||
protected RestrictedSwitchPreference mBadge;
|
|
||||||
protected RestrictedSwitchPreference mPriority;
|
|
||||||
protected RestrictedDropDownPreference mVisibilityOverride;
|
|
||||||
protected RestrictedSwitchPreference mImportanceToggle;
|
|
||||||
protected LayoutPreference mBlockBar;
|
|
||||||
protected SwitchBar mSwitchBar;
|
|
||||||
protected FooterPreference mBlockedDesc;
|
|
||||||
protected Preference mAppLink;
|
|
||||||
|
|
||||||
protected EnforcedAdmin mSuspendedAppsAdmin;
|
protected EnforcedAdmin mSuspendedAppsAdmin;
|
||||||
protected boolean mDndVisualEffectsSuppressed;
|
protected NotificationChannelGroupWrapper mChannelGroup;
|
||||||
|
|
||||||
protected NotificationChannelGroup mChannelGroup;
|
|
||||||
protected NotificationChannel mChannel;
|
protected NotificationChannel mChannel;
|
||||||
protected NotificationBackend.AppRow mAppRow;
|
protected NotificationBackend.AppRow mAppRow;
|
||||||
protected boolean mShowLegacyChannelConfig = false;
|
|
||||||
|
|
||||||
|
protected boolean mShowLegacyChannelConfig = false;
|
||||||
protected boolean mListeningToPackageRemove;
|
protected boolean mListeningToPackageRemove;
|
||||||
|
|
||||||
@Override
|
protected List<NotificationPreferenceController> mControllers = new ArrayList<>();
|
||||||
public void onActivityCreated(Bundle savedInstanceState) {
|
protected List<Preference> mDynamicPreferences = new ArrayList<>();
|
||||||
super.onActivityCreated(savedInstanceState);
|
protected ImportanceListener mImportanceListener = new ImportanceListener();
|
||||||
if (DEBUG) Log.d(TAG, "onActivityCreated mCreated=" + mCreated);
|
|
||||||
if (mCreated) {
|
|
||||||
Log.w(TAG, "onActivityCreated: ignoring duplicate call");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mCreated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
@@ -143,7 +114,6 @@ abstract public class NotificationSettingsBase extends SettingsPreferenceFragmen
|
|||||||
}
|
}
|
||||||
|
|
||||||
mPm = getPackageManager();
|
mPm = getPackageManager();
|
||||||
mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
|
|
||||||
mNm = NotificationManager.from(mContext);
|
mNm = NotificationManager.from(mContext);
|
||||||
|
|
||||||
mPkg = args != null && args.containsKey(AppInfoBase.ARG_PACKAGE_NAME)
|
mPkg = args != null && args.containsKey(AppInfoBase.ARG_PACKAGE_NAME)
|
||||||
@@ -187,35 +157,41 @@ abstract public class NotificationSettingsBase extends SettingsPreferenceFragmen
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mAppRow = mBackend.loadAppRow(mContext, mPm, mPkgInfo);
|
mAppRow = mBackend.loadAppRow(mContext, mPm, mPkgInfo);
|
||||||
|
if (mAppRow == null) {
|
||||||
|
Log.w(TAG, "Can't load package");
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
collectConfigActivities();
|
||||||
Bundle args = getArguments();
|
Bundle args = getArguments();
|
||||||
mChannel = (args != null && args.containsKey(Settings.EXTRA_CHANNEL_ID)) ?
|
mChannel = (args != null && args.containsKey(Settings.EXTRA_CHANNEL_ID)) ?
|
||||||
mBackend.getChannel(mPkg, mUid, args.getString(Settings.EXTRA_CHANNEL_ID)) : null;
|
mBackend.getChannel(mPkg, mUid, args.getString(Settings.EXTRA_CHANNEL_ID)) : null;
|
||||||
|
|
||||||
mChannelGroup = (args != null && args.containsKey(Settings.EXTRA_CHANNEL_GROUP_ID)) ?
|
NotificationChannelGroup group =
|
||||||
mBackend.getGroupWithChannels(mPkg, mUid,
|
(args != null && args.containsKey(Settings.EXTRA_CHANNEL_GROUP_ID))
|
||||||
|
? mBackend.getGroupWithChannels(mPkg, mUid,
|
||||||
args.getString(Settings.EXTRA_CHANNEL_GROUP_ID))
|
args.getString(Settings.EXTRA_CHANNEL_GROUP_ID))
|
||||||
: null;
|
: null;
|
||||||
|
if (group != null) {
|
||||||
|
mChannelGroup = new NotificationChannelGroupWrapper(group);
|
||||||
|
}
|
||||||
|
|
||||||
mSuspendedAppsAdmin = RestrictedLockUtils.checkIfApplicationIsSuspended(
|
mSuspendedAppsAdmin = RestrictedLockUtils.checkIfApplicationIsSuspended(
|
||||||
mContext, mPkg, mUserId);
|
mContext, mPkg, mUserId);
|
||||||
NotificationManager.Policy policy = mNm.getNotificationPolicy();
|
|
||||||
mDndVisualEffectsSuppressed = policy == null ? false : policy.suppressedVisualEffects != 0;
|
|
||||||
|
|
||||||
mSuspendedAppsAdmin = RestrictedLockUtils.checkIfApplicationIsSuspended(
|
mShowLegacyChannelConfig = mBackend.onlyHasDefaultChannel(mAppRow.pkg, mAppRow.uid)
|
||||||
mContext, mPkg, mUserId);
|
|| (mChannel != null
|
||||||
}
|
&& NotificationChannel.DEFAULT_CHANNEL_ID.equals(mChannel.getId()));
|
||||||
|
|
||||||
protected void setVisible(Preference p, boolean visible) {
|
if (mShowLegacyChannelConfig) {
|
||||||
setVisible(getPreferenceScreen(), p, visible);
|
mChannel = mBackend.getChannel(
|
||||||
}
|
mAppRow.pkg, mAppRow.uid, NotificationChannel.DEFAULT_CHANNEL_ID);
|
||||||
|
}
|
||||||
protected void setVisible(PreferenceGroup parent, Preference p, boolean visible) {
|
if (mChannel != null && !TextUtils.isEmpty(mChannel.getGroup())) {
|
||||||
final boolean isVisible = parent.findPreference(p.getKey()) != null;
|
group = mBackend.getGroup(mPkg, mUid, mChannel.getGroup());
|
||||||
if (isVisible == visible) return;
|
if (group != null) {
|
||||||
if (visible) {
|
mChannelGroup = new NotificationChannelGroupWrapper(group);
|
||||||
parent.addPreference(p);
|
}
|
||||||
} else {
|
|
||||||
parent.removePreference(p);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,49 +200,34 @@ abstract public class NotificationSettingsBase extends SettingsPreferenceFragmen
|
|||||||
getActivity().finish();
|
getActivity().finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ResolveInfo> queryNotificationConfigActivities() {
|
protected void collectConfigActivities() {
|
||||||
if (DEBUG) Log.d(TAG, "APP_NOTIFICATION_PREFS_CATEGORY_INTENT is "
|
Intent intent = new Intent(Intent.ACTION_MAIN)
|
||||||
+ APP_NOTIFICATION_PREFS_CATEGORY_INTENT);
|
.addCategory(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES)
|
||||||
|
.setPackage(mAppRow.pkg);
|
||||||
final List<ResolveInfo> resolveInfos = mPm.queryIntentActivities(
|
final List<ResolveInfo> resolveInfos = mPm.queryIntentActivities(
|
||||||
APP_NOTIFICATION_PREFS_CATEGORY_INTENT,
|
intent,
|
||||||
0 //PackageManager.MATCH_DEFAULT_ONLY
|
0 //PackageManager.MATCH_DEFAULT_ONLY
|
||||||
);
|
);
|
||||||
return resolveInfos;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void collectConfigActivities(ArrayMap<String, NotificationBackend.AppRow> rows) {
|
|
||||||
final List<ResolveInfo> resolveInfos = queryNotificationConfigActivities();
|
|
||||||
applyConfigActivities(rows, resolveInfos);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applyConfigActivities(ArrayMap<String, NotificationBackend.AppRow> rows,
|
|
||||||
List<ResolveInfo> resolveInfos) {
|
|
||||||
if (DEBUG) Log.d(TAG, "Found " + resolveInfos.size() + " preference activities"
|
if (DEBUG) Log.d(TAG, "Found " + resolveInfos.size() + " preference activities"
|
||||||
+ (resolveInfos.size() == 0 ? " ;_;" : ""));
|
+ (resolveInfos.size() == 0 ? " ;_;" : ""));
|
||||||
for (ResolveInfo ri : resolveInfos) {
|
for (ResolveInfo ri : resolveInfos) {
|
||||||
final ActivityInfo activityInfo = ri.activityInfo;
|
final ActivityInfo activityInfo = ri.activityInfo;
|
||||||
final ApplicationInfo appInfo = activityInfo.applicationInfo;
|
final ApplicationInfo appInfo = activityInfo.applicationInfo;
|
||||||
final NotificationBackend.AppRow row = rows.get(appInfo.packageName);
|
if (mAppRow.settingsIntent != null) {
|
||||||
if (row == null) {
|
|
||||||
if (DEBUG) Log.v(TAG, "Ignoring notification preference activity ("
|
|
||||||
+ activityInfo.name + ") for unknown package "
|
|
||||||
+ activityInfo.packageName);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (row.settingsIntent != null) {
|
|
||||||
if (DEBUG) Log.v(TAG, "Ignoring duplicate notification preference activity ("
|
if (DEBUG) Log.v(TAG, "Ignoring duplicate notification preference activity ("
|
||||||
+ activityInfo.name + ") for package "
|
+ activityInfo.name + ") for package "
|
||||||
+ activityInfo.packageName);
|
+ activityInfo.packageName);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
row.settingsIntent = new Intent(APP_NOTIFICATION_PREFS_CATEGORY_INTENT)
|
mAppRow.settingsIntent = intent
|
||||||
|
.setPackage(null)
|
||||||
.setClassName(activityInfo.packageName, activityInfo.name);
|
.setClassName(activityInfo.packageName, activityInfo.name);
|
||||||
if (mChannel != null) {
|
if (mChannel != null) {
|
||||||
row.settingsIntent.putExtra(Notification.EXTRA_CHANNEL_ID, mChannel.getId());
|
mAppRow.settingsIntent.putExtra(Notification.EXTRA_CHANNEL_ID, mChannel.getId());
|
||||||
}
|
}
|
||||||
if (mChannelGroup != null) {
|
if (mChannelGroup != null) {
|
||||||
row.settingsIntent.putExtra(
|
mAppRow.settingsIntent.putExtra(
|
||||||
Notification.EXTRA_CHANNEL_GROUP_ID, mChannelGroup.getId());
|
Notification.EXTRA_CHANNEL_GROUP_ID, mChannelGroup.getGroup().getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -292,134 +253,6 @@ abstract public class NotificationSettingsBase extends SettingsPreferenceFragmen
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addAppLinkPref() {
|
|
||||||
if (mAppRow.settingsIntent != null && mAppLink == null) {
|
|
||||||
addPreferencesFromResource(R.xml.inapp_notification_settings);
|
|
||||||
mAppLink = findPreference(KEY_APP_LINK);
|
|
||||||
mAppLink.setIntent(mAppRow.settingsIntent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void populateDefaultChannelPrefs() {
|
|
||||||
if (mPkgInfo != null && mChannel != null) {
|
|
||||||
addPreferencesFromResource(R.xml.legacy_channel_notification_settings);
|
|
||||||
setupPriorityPref(mChannel.canBypassDnd());
|
|
||||||
setupVisOverridePref(mChannel.getLockscreenVisibility());
|
|
||||||
setupImportanceToggle();
|
|
||||||
setupBadge();
|
|
||||||
}
|
|
||||||
mSwitchBar.setChecked(!mAppRow.banned
|
|
||||||
&& mChannel.getImportance() != NotificationManager.IMPORTANCE_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract void setupBadge();
|
|
||||||
|
|
||||||
abstract void updateDependents(boolean banned);
|
|
||||||
|
|
||||||
// 'allow sound'
|
|
||||||
private void setupImportanceToggle() {
|
|
||||||
mImportanceToggle = (RestrictedSwitchPreference) findPreference(KEY_ALLOW_SOUND);
|
|
||||||
mImportanceToggle.setDisabledByAdmin(mSuspendedAppsAdmin);
|
|
||||||
mImportanceToggle.setEnabled(isChannelConfigurable(mChannel)
|
|
||||||
&& !mImportanceToggle.isDisabledByAdmin());
|
|
||||||
mImportanceToggle.setChecked(mChannel.getImportance() >= IMPORTANCE_DEFAULT
|
|
||||||
|| mChannel.getImportance() == IMPORTANCE_UNSPECIFIED);
|
|
||||||
mImportanceToggle.setOnPreferenceChangeListener(
|
|
||||||
new Preference.OnPreferenceChangeListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
|
||||||
final int importance =
|
|
||||||
((Boolean) newValue ? IMPORTANCE_UNSPECIFIED : IMPORTANCE_LOW);
|
|
||||||
mChannel.setImportance(importance);
|
|
||||||
mChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
|
|
||||||
mBackend.updateChannel(mPkg, mUid, mChannel);
|
|
||||||
updateDependents(mChannel.getImportance() == IMPORTANCE_NONE);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setupPriorityPref(boolean priority) {
|
|
||||||
mPriority = (RestrictedSwitchPreference) findPreference(KEY_BYPASS_DND);
|
|
||||||
mPriority.setDisabledByAdmin(mSuspendedAppsAdmin);
|
|
||||||
mPriority.setEnabled(isChannelConfigurable(mChannel) && !mPriority.isDisabledByAdmin());
|
|
||||||
mPriority.setChecked(priority);
|
|
||||||
mPriority.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
|
||||||
final boolean bypassZenMode = (Boolean) newValue;
|
|
||||||
mChannel.setBypassDnd(bypassZenMode);
|
|
||||||
mChannel.lockFields(NotificationChannel.USER_LOCKED_PRIORITY);
|
|
||||||
mBackend.updateChannel(mPkg, mUid, mChannel);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setupVisOverridePref(int sensitive) {
|
|
||||||
mVisibilityOverride =
|
|
||||||
(RestrictedDropDownPreference) findPreference(KEY_VISIBILITY_OVERRIDE);
|
|
||||||
ArrayList<CharSequence> entries = new ArrayList<>();
|
|
||||||
ArrayList<CharSequence> values = new ArrayList<>();
|
|
||||||
|
|
||||||
mVisibilityOverride.clearRestrictedItems();
|
|
||||||
if (getLockscreenNotificationsEnabled() && getLockscreenAllowPrivateNotifications()) {
|
|
||||||
final String summaryShowEntry =
|
|
||||||
getString(R.string.lock_screen_notifications_summary_show);
|
|
||||||
final String summaryShowEntryValue =
|
|
||||||
Integer.toString(NotificationManager.VISIBILITY_NO_OVERRIDE);
|
|
||||||
entries.add(summaryShowEntry);
|
|
||||||
values.add(summaryShowEntryValue);
|
|
||||||
setRestrictedIfNotificationFeaturesDisabled(summaryShowEntry, summaryShowEntryValue,
|
|
||||||
DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS
|
|
||||||
| DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
|
|
||||||
}
|
|
||||||
|
|
||||||
final String summaryHideEntry = getString(R.string.lock_screen_notifications_summary_hide);
|
|
||||||
final String summaryHideEntryValue = Integer.toString(Notification.VISIBILITY_PRIVATE);
|
|
||||||
entries.add(summaryHideEntry);
|
|
||||||
values.add(summaryHideEntryValue);
|
|
||||||
setRestrictedIfNotificationFeaturesDisabled(summaryHideEntry, summaryHideEntryValue,
|
|
||||||
DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
|
|
||||||
entries.add(getString(R.string.lock_screen_notifications_summary_disable));
|
|
||||||
values.add(Integer.toString(Notification.VISIBILITY_SECRET));
|
|
||||||
mVisibilityOverride.setEntries(entries.toArray(new CharSequence[entries.size()]));
|
|
||||||
mVisibilityOverride.setEntryValues(values.toArray(new CharSequence[values.size()]));
|
|
||||||
|
|
||||||
if (sensitive == NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
|
|
||||||
mVisibilityOverride.setValue(Integer.toString(getGlobalVisibility()));
|
|
||||||
} else {
|
|
||||||
mVisibilityOverride.setValue(Integer.toString(sensitive));
|
|
||||||
}
|
|
||||||
mVisibilityOverride.setSummary("%s");
|
|
||||||
|
|
||||||
mVisibilityOverride.setOnPreferenceChangeListener(
|
|
||||||
new Preference.OnPreferenceChangeListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
|
||||||
int sensitive = Integer.parseInt((String) newValue);
|
|
||||||
if (sensitive == getGlobalVisibility()) {
|
|
||||||
sensitive = NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE;
|
|
||||||
}
|
|
||||||
mChannel.setLockscreenVisibility(sensitive);
|
|
||||||
mChannel.lockFields(NotificationChannel.USER_LOCKED_VISIBILITY);
|
|
||||||
mBackend.updateChannel(mPkg, mUid, mChannel);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mVisibilityOverride.setDisabledByAdmin(mSuspendedAppsAdmin);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setupBlockDesc(int summaryResId) {
|
|
||||||
mBlockedDesc = new FooterPreference(getPrefContext());
|
|
||||||
mBlockedDesc.setSelectable(false);
|
|
||||||
mBlockedDesc.setTitle(summaryResId);
|
|
||||||
mBlockedDesc.setEnabled(false);
|
|
||||||
mBlockedDesc.setOrder(50);
|
|
||||||
mBlockedDesc.setKey(KEY_BLOCKED_DESC);
|
|
||||||
getPreferenceScreen().addPreference(mBlockedDesc);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Preference populateSingleChannelPrefs(PreferenceGroup parent,
|
protected Preference populateSingleChannelPrefs(PreferenceGroup parent,
|
||||||
final NotificationChannel channel, String summary) {
|
final NotificationChannel channel, String summary) {
|
||||||
MasterSwitchPreference channelPref = new MasterSwitchPreference(
|
MasterSwitchPreference channelPref = new MasterSwitchPreference(
|
||||||
@@ -461,105 +294,48 @@ abstract public class NotificationSettingsBase extends SettingsPreferenceFragmen
|
|||||||
return channelPref;
|
return channelPref;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean checkCanBeVisible(int minImportanceVisible) {
|
|
||||||
int importance = mChannel.getImportance();
|
|
||||||
if (importance == NotificationManager.IMPORTANCE_UNSPECIFIED) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return importance >= minImportanceVisible;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getImportanceSummary(NotificationChannel channel) {
|
|
||||||
switch (channel.getImportance()) {
|
|
||||||
case NotificationManager.IMPORTANCE_UNSPECIFIED:
|
|
||||||
return getContext().getString(R.string.notification_importance_unspecified);
|
|
||||||
case NotificationManager.IMPORTANCE_NONE:
|
|
||||||
return getContext().getString(R.string.notification_toggle_off);
|
|
||||||
case NotificationManager.IMPORTANCE_MIN:
|
|
||||||
return getContext().getString(R.string.notification_importance_min);
|
|
||||||
case NotificationManager.IMPORTANCE_LOW:
|
|
||||||
return getContext().getString(R.string.notification_importance_low);
|
|
||||||
case NotificationManager.IMPORTANCE_DEFAULT:
|
|
||||||
if (hasValidSound(channel)) {
|
|
||||||
return getContext().getString(R.string.notification_importance_default);
|
|
||||||
} else { // Silent
|
|
||||||
return getContext().getString(R.string.notification_importance_low);
|
|
||||||
}
|
|
||||||
case NotificationManager.IMPORTANCE_HIGH:
|
|
||||||
case NotificationManager.IMPORTANCE_MAX:
|
|
||||||
default:
|
|
||||||
if (hasValidSound(channel)) {
|
|
||||||
return getContext().getString(R.string.notification_importance_high);
|
|
||||||
} else { // Silent
|
|
||||||
return getContext().getString(R.string.notification_importance_high_silent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setRestrictedIfNotificationFeaturesDisabled(CharSequence entry,
|
|
||||||
CharSequence entryValue, int keyguardNotificationFeatures) {
|
|
||||||
RestrictedLockUtils.EnforcedAdmin admin =
|
|
||||||
RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
|
|
||||||
mContext, keyguardNotificationFeatures, mUserId);
|
|
||||||
if (admin != null) {
|
|
||||||
RestrictedDropDownPreference.RestrictedItem item =
|
|
||||||
new RestrictedDropDownPreference.RestrictedItem(entry, entryValue, admin);
|
|
||||||
mVisibilityOverride.addRestrictedItem(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getGlobalVisibility() {
|
|
||||||
int globalVis = NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE;
|
|
||||||
if (!getLockscreenNotificationsEnabled()) {
|
|
||||||
globalVis = Notification.VISIBILITY_SECRET;
|
|
||||||
} else if (!getLockscreenAllowPrivateNotifications()) {
|
|
||||||
globalVis = Notification.VISIBILITY_PRIVATE;
|
|
||||||
}
|
|
||||||
return globalVis;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean getLockscreenNotificationsEnabled() {
|
|
||||||
return Settings.Secure.getInt(getContentResolver(),
|
|
||||||
Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean getLockscreenAllowPrivateNotifications() {
|
|
||||||
return Settings.Secure.getInt(getContentResolver(),
|
|
||||||
Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isLockScreenSecure() {
|
|
||||||
if (mLockPatternUtils == null) {
|
|
||||||
mLockPatternUtils = new LockPatternUtils(getActivity());
|
|
||||||
}
|
|
||||||
boolean lockscreenSecure = mLockPatternUtils.isSecure(UserHandle.myUserId());
|
|
||||||
UserInfo parentUser = mUm.getProfileParent(UserHandle.myUserId());
|
|
||||||
if (parentUser != null){
|
|
||||||
lockscreenSecure |= mLockPatternUtils.isSecure(parentUser.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return lockscreenSecure;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isChannelConfigurable(NotificationChannel channel) {
|
protected boolean isChannelConfigurable(NotificationChannel channel) {
|
||||||
return !channel.getId().equals(mAppRow.lockedChannelId);
|
if (channel != null && mAppRow != null) {
|
||||||
|
return !channel.getId().equals(mAppRow.lockedChannelId);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isChannelBlockable(NotificationChannel channel) {
|
protected boolean isChannelBlockable(NotificationChannel channel) {
|
||||||
if (!mAppRow.systemApp) {
|
if (channel != null && mAppRow != null) {
|
||||||
return true;
|
if (!mAppRow.systemApp) {
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return channel.isBlockableSystem()
|
return channel.isBlockableSystem()
|
||||||
|| channel.getImportance() == NotificationManager.IMPORTANCE_NONE;
|
|| channel.getImportance() == NotificationManager.IMPORTANCE_NONE;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isChannelGroupBlockable(NotificationChannelGroup group) {
|
protected boolean isChannelGroupBlockable(NotificationChannelGroup group) {
|
||||||
if (!mAppRow.systemApp) {
|
if (group != null && mAppRow != null) {
|
||||||
return true;
|
if (!mAppRow.systemApp) {
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return group.isBlocked();
|
return group.isBlocked();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setVisible(Preference p, boolean visible) {
|
||||||
|
setVisible(getPreferenceScreen(), p, visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setVisible(PreferenceGroup parent, Preference p, boolean visible) {
|
||||||
|
final boolean isVisible = parent.findPreference(p.getKey()) != null;
|
||||||
|
if (isVisible == visible) return;
|
||||||
|
if (visible) {
|
||||||
|
parent.addPreference(p);
|
||||||
|
} else {
|
||||||
|
parent.removePreference(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void startListeningToPackageRemove() {
|
protected void startListeningToPackageRemove() {
|
||||||
@@ -604,7 +380,45 @@ abstract public class NotificationSettingsBase extends SettingsPreferenceFragmen
|
|||||||
return left.getId().compareTo(right.getId());
|
return left.getId().compareTo(right.getId());
|
||||||
};
|
};
|
||||||
|
|
||||||
boolean hasValidSound(NotificationChannel channel) {
|
/**
|
||||||
return channel.getSound() != null && !Uri.EMPTY.equals(channel.getSound());
|
* These screens aren't searchable - they only make sense in the context of an app, so
|
||||||
|
* surfacing a generic version would be impossible.
|
||||||
|
*/
|
||||||
|
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||||
|
new BaseSearchIndexProvider() {
|
||||||
|
@Override
|
||||||
|
public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
|
||||||
|
boolean enabled) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AbstractPreferenceController> getPreferenceControllers(Context context) {
|
||||||
|
return getPreferenceControllers(context);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
protected class ImportanceListener {
|
||||||
|
protected void onImportanceChanged() {
|
||||||
|
final PreferenceScreen screen = getPreferenceScreen();
|
||||||
|
for (NotificationPreferenceController controller : mControllers) {
|
||||||
|
controller.displayPreference(screen);
|
||||||
|
}
|
||||||
|
updatePreferenceStates();
|
||||||
|
|
||||||
|
boolean hideDynamicFields = false;
|
||||||
|
if (mAppRow == null || mAppRow.banned) {
|
||||||
|
hideDynamicFields = true;
|
||||||
|
} else {
|
||||||
|
if (mChannel != null) {
|
||||||
|
hideDynamicFields = mChannel.getImportance() == IMPORTANCE_NONE;
|
||||||
|
} else if (mChannelGroup != null) {
|
||||||
|
hideDynamicFields = mChannelGroup.isBlocked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Preference preference : mDynamicPreferences) {
|
||||||
|
setVisible(getPreferenceScreen(), preference, !hideDynamicFields);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.core.PreferenceControllerMixin;
|
||||||
|
import com.android.settingslib.widget.FooterPreference;
|
||||||
|
|
||||||
|
public class NotificationsOffPreferenceController extends NotificationPreferenceController
|
||||||
|
implements PreferenceControllerMixin {
|
||||||
|
|
||||||
|
private static final String KEY_BLOCKED_DESC = "block_desc";
|
||||||
|
|
||||||
|
public NotificationsOffPreferenceController(Context context) {
|
||||||
|
super(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPreferenceKey() {
|
||||||
|
return KEY_BLOCKED_DESC;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
if (mAppRow == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Available only when other controllers are unavailable - this UI replaces the UI that
|
||||||
|
// would give more detailed notification controls.
|
||||||
|
return !super.isAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
if (mAppRow != null) {
|
||||||
|
if (mChannel != null) {
|
||||||
|
preference.setTitle(R.string.channel_notifications_off_desc);
|
||||||
|
} else if (mChannelGroup != null && mChannelGroup.getGroup() == null) {
|
||||||
|
preference.setTitle(R.string.channel_group_notifications_off_desc);
|
||||||
|
} else {
|
||||||
|
preference.setTitle(R.string.app_notifications_off_desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
preference.setEnabled(false);
|
||||||
|
preference.setSelectable(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
import android.support.v7.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.settings.SettingsPreferenceFragment;
|
||||||
|
import com.android.settings.core.PreferenceControllerMixin;
|
||||||
|
|
||||||
|
public class SoundPreferenceController extends NotificationPreferenceController
|
||||||
|
implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener,
|
||||||
|
PreferenceManager.OnActivityResultListener {
|
||||||
|
|
||||||
|
private static final String KEY_SOUND = "ringtone";
|
||||||
|
private final SettingsPreferenceFragment mFragment;
|
||||||
|
private final NotificationSettingsBase.ImportanceListener mListener;
|
||||||
|
private NotificationSoundPreference mPreference;
|
||||||
|
protected static final int CODE = 200;
|
||||||
|
|
||||||
|
public SoundPreferenceController(Context context, SettingsPreferenceFragment hostFragment,
|
||||||
|
NotificationSettingsBase.ImportanceListener importanceListener,
|
||||||
|
NotificationBackend backend) {
|
||||||
|
super(context, backend);
|
||||||
|
mFragment = hostFragment;
|
||||||
|
mListener = importanceListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPreferenceKey() {
|
||||||
|
return KEY_SOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
if (!super.isAvailable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mChannel == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return checkCanBeVisible(NotificationManager.IMPORTANCE_DEFAULT)
|
||||||
|
&& !NotificationChannel.DEFAULT_CHANNEL_ID.equals(mChannel.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void displayPreference(PreferenceScreen screen) {
|
||||||
|
super.displayPreference(screen);
|
||||||
|
|
||||||
|
mPreference = (NotificationSoundPreference) screen.findPreference(getPreferenceKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
if (mAppRow!= null && mChannel != null) {
|
||||||
|
NotificationSoundPreference pref = (NotificationSoundPreference) preference;
|
||||||
|
pref.setEnabled(mAdmin == null && isChannelConfigurable());
|
||||||
|
pref.setRingtone(mChannel.getSound());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
|
if (mChannel != null) {
|
||||||
|
mChannel.setSound((Uri) newValue, mChannel.getAudioAttributes());
|
||||||
|
saveChannel();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handlePreferenceTreeClick(Preference preference) {
|
||||||
|
if (KEY_SOUND.equals(preference.getKey()) && mFragment != null) {
|
||||||
|
NotificationSoundPreference pref = (NotificationSoundPreference) preference;
|
||||||
|
pref.onPrepareRingtonePickerIntent(pref.getIntent());
|
||||||
|
mFragment.startActivityForResult(preference.getIntent(), CODE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
if (CODE == requestCode) {
|
||||||
|
if (mPreference != null) {
|
||||||
|
mPreference.onActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
// the importance hasn't changed, but the importance description might as a result of
|
||||||
|
// user's selection.
|
||||||
|
mListener.onImportanceChanged();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static boolean hasValidSound(NotificationChannel channel) {
|
||||||
|
return channel != null
|
||||||
|
&& channel.getSound() != null && !Uri.EMPTY.equals(channel.getSound());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Vibrator;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
|
||||||
|
import com.android.settings.core.PreferenceControllerMixin;
|
||||||
|
import com.android.settingslib.RestrictedSwitchPreference;
|
||||||
|
|
||||||
|
public class VibrationPreferenceController extends NotificationPreferenceController
|
||||||
|
implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
|
||||||
|
|
||||||
|
private static final String KEY_VIBRATE = "vibrate";
|
||||||
|
private final Vibrator mVibrator;
|
||||||
|
|
||||||
|
public VibrationPreferenceController(Context context, NotificationBackend backend) {
|
||||||
|
super(context, backend);
|
||||||
|
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPreferenceKey() {
|
||||||
|
return KEY_VIBRATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
if (!super.isAvailable() || mChannel == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return checkCanBeVisible(NotificationManager.IMPORTANCE_DEFAULT)
|
||||||
|
&& !NotificationChannel.DEFAULT_CHANNEL_ID.equals(mChannel.getId())
|
||||||
|
&& mVibrator != null
|
||||||
|
&& mVibrator.hasVibrator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
if (mChannel != null) {
|
||||||
|
RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
|
||||||
|
pref.setDisabledByAdmin(mAdmin);
|
||||||
|
pref.setEnabled(!pref.isDisabledByAdmin() && isChannelConfigurable());
|
||||||
|
pref.setChecked(mChannel.shouldVibrate());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
|
if (mChannel != null) {
|
||||||
|
final boolean vibrate = (Boolean) newValue;
|
||||||
|
mChannel.enableVibration(vibrate);
|
||||||
|
saveChannel();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import android.app.Notification;
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.app.admin.DevicePolicyManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.UserInfo;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.service.notification.NotificationListenerService;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
|
||||||
|
import com.android.internal.widget.LockPatternUtils;
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.core.PreferenceControllerMixin;
|
||||||
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class VisibilityPreferenceController extends NotificationPreferenceController
|
||||||
|
implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
|
||||||
|
|
||||||
|
private static final String TAG = "ChannelVisPrefContr";
|
||||||
|
private static final String KEY_VISIBILITY_OVERRIDE = "visibility_override";
|
||||||
|
private LockPatternUtils mLockPatternUtils;
|
||||||
|
|
||||||
|
public VisibilityPreferenceController(Context context, LockPatternUtils utils,
|
||||||
|
NotificationBackend backend) {
|
||||||
|
super(context, backend);
|
||||||
|
mLockPatternUtils = utils;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPreferenceKey() {
|
||||||
|
return KEY_VISIBILITY_OVERRIDE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
if (!super.isAvailable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mChannel == null || mAppRow.banned) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return checkCanBeVisible(NotificationManager.IMPORTANCE_LOW) && isLockScreenSecure();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
if (mChannel != null && mAppRow != null) {
|
||||||
|
RestrictedDropDownPreference pref = (RestrictedDropDownPreference) preference;
|
||||||
|
ArrayList<CharSequence> entries = new ArrayList<>();
|
||||||
|
ArrayList<CharSequence> values = new ArrayList<>();
|
||||||
|
|
||||||
|
pref.clearRestrictedItems();
|
||||||
|
if (getLockscreenNotificationsEnabled() && getLockscreenAllowPrivateNotifications()) {
|
||||||
|
final String summaryShowEntry =
|
||||||
|
mContext.getString(R.string.lock_screen_notifications_summary_show);
|
||||||
|
final String summaryShowEntryValue =
|
||||||
|
Integer.toString(NotificationManager.VISIBILITY_NO_OVERRIDE);
|
||||||
|
entries.add(summaryShowEntry);
|
||||||
|
values.add(summaryShowEntryValue);
|
||||||
|
setRestrictedIfNotificationFeaturesDisabled(pref, summaryShowEntry,
|
||||||
|
summaryShowEntryValue,
|
||||||
|
DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS
|
||||||
|
| DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String summaryHideEntry =
|
||||||
|
mContext.getString(R.string.lock_screen_notifications_summary_hide);
|
||||||
|
final String summaryHideEntryValue = Integer.toString(Notification.VISIBILITY_PRIVATE);
|
||||||
|
entries.add(summaryHideEntry);
|
||||||
|
values.add(summaryHideEntryValue);
|
||||||
|
setRestrictedIfNotificationFeaturesDisabled(pref,
|
||||||
|
summaryHideEntry, summaryHideEntryValue,
|
||||||
|
DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
|
||||||
|
entries.add(mContext.getString(R.string.lock_screen_notifications_summary_disable));
|
||||||
|
values.add(Integer.toString(Notification.VISIBILITY_SECRET));
|
||||||
|
pref.setEntries(entries.toArray(new CharSequence[entries.size()]));
|
||||||
|
pref.setEntryValues(values.toArray(new CharSequence[values.size()]));
|
||||||
|
|
||||||
|
if (mChannel.getLockscreenVisibility()
|
||||||
|
== NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
|
||||||
|
pref.setValue(Integer.toString(getGlobalVisibility()));
|
||||||
|
} else {
|
||||||
|
pref.setValue(Integer.toString(mChannel.getLockscreenVisibility()));
|
||||||
|
}
|
||||||
|
pref.setSummary("%s");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
|
if (mChannel != null) {
|
||||||
|
int sensitive = Integer.parseInt((String) newValue);
|
||||||
|
if (sensitive == getGlobalVisibility()) {
|
||||||
|
sensitive = NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE;
|
||||||
|
}
|
||||||
|
mChannel.setLockscreenVisibility(sensitive);
|
||||||
|
mChannel.lockFields(NotificationChannel.USER_LOCKED_VISIBILITY);
|
||||||
|
saveChannel();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setRestrictedIfNotificationFeaturesDisabled(RestrictedDropDownPreference pref,
|
||||||
|
CharSequence entry, CharSequence entryValue, int keyguardNotificationFeatures) {
|
||||||
|
RestrictedLockUtils.EnforcedAdmin admin =
|
||||||
|
RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
|
||||||
|
mContext, keyguardNotificationFeatures, mAppRow.userId);
|
||||||
|
if (admin != null) {
|
||||||
|
RestrictedDropDownPreference.RestrictedItem item =
|
||||||
|
new RestrictedDropDownPreference.RestrictedItem(entry, entryValue, admin);
|
||||||
|
pref.addRestrictedItem(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getGlobalVisibility() {
|
||||||
|
int globalVis = NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE;
|
||||||
|
if (!getLockscreenNotificationsEnabled()) {
|
||||||
|
globalVis = Notification.VISIBILITY_SECRET;
|
||||||
|
} else if (!getLockscreenAllowPrivateNotifications()) {
|
||||||
|
globalVis = Notification.VISIBILITY_PRIVATE;
|
||||||
|
}
|
||||||
|
return globalVis;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean getLockscreenNotificationsEnabled() {
|
||||||
|
return Settings.Secure.getInt(mContext.getContentResolver(),
|
||||||
|
Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean getLockscreenAllowPrivateNotifications() {
|
||||||
|
return Settings.Secure.getInt(mContext.getContentResolver(),
|
||||||
|
Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isLockScreenSecure() {
|
||||||
|
boolean lockscreenSecure = mLockPatternUtils.isSecure(UserHandle.myUserId());
|
||||||
|
UserInfo parentUser = mUm.getProfileParent(UserHandle.myUserId());
|
||||||
|
if (parentUser != null){
|
||||||
|
lockscreenSecure |= mLockPatternUtils.isSecure(parentUser.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lockscreenSecure;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -64,7 +64,10 @@ import com.android.settings.location.LocationSettings;
|
|||||||
import com.android.settings.location.ScanningSettings;
|
import com.android.settings.location.ScanningSettings;
|
||||||
import com.android.settings.network.NetworkDashboardFragment;
|
import com.android.settings.network.NetworkDashboardFragment;
|
||||||
import com.android.settings.nfc.PaymentSettings;
|
import com.android.settings.nfc.PaymentSettings;
|
||||||
|
import com.android.settings.notification.AppNotificationSettings;
|
||||||
|
import com.android.settings.notification.ChannelGroupNotificationSettings;
|
||||||
import com.android.settings.notification.ChannelImportanceSettings;
|
import com.android.settings.notification.ChannelImportanceSettings;
|
||||||
|
import com.android.settings.notification.ChannelNotificationSettings;
|
||||||
import com.android.settings.notification.ConfigureNotificationSettings;
|
import com.android.settings.notification.ConfigureNotificationSettings;
|
||||||
import com.android.settings.notification.SoundSettings;
|
import com.android.settings.notification.SoundSettings;
|
||||||
import com.android.settings.notification.ZenModeAutomationSettings;
|
import com.android.settings.notification.ZenModeAutomationSettings;
|
||||||
@@ -168,6 +171,10 @@ public final class SearchIndexableResources {
|
|||||||
addIndex(LockscreenDashboardFragment.class);
|
addIndex(LockscreenDashboardFragment.class);
|
||||||
addIndex(ZenModeBehaviorSettings.class);
|
addIndex(ZenModeBehaviorSettings.class);
|
||||||
addIndex(ZenModeAutomationSettings.class);
|
addIndex(ZenModeAutomationSettings.class);
|
||||||
|
addIndex(AppNotificationSettings.class);
|
||||||
|
addIndex(ChannelNotificationSettings.class);
|
||||||
|
addIndex(ChannelImportanceSettings.class);
|
||||||
|
addIndex(ChannelGroupNotificationSettings.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SearchIndexableResources() {
|
private SearchIndexableResources() {
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.wrapper;
|
||||||
|
|
||||||
|
import android.app.NotificationChannelGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for {@link NotificationChannelGroup} until roboletric supports O MR1.
|
||||||
|
*/
|
||||||
|
public class NotificationChannelGroupWrapper {
|
||||||
|
|
||||||
|
private final NotificationChannelGroup mGroup;
|
||||||
|
|
||||||
|
public NotificationChannelGroupWrapper(NotificationChannelGroup group) {
|
||||||
|
mGroup = group;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the real group object so we can call APIs directly on it.
|
||||||
|
*/
|
||||||
|
public NotificationChannelGroup getGroup() {
|
||||||
|
return mGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
if (mGroup != null) {
|
||||||
|
return mGroup.getDescription();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String desc) {
|
||||||
|
if (mGroup != null) {
|
||||||
|
mGroup.setDescription(desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBlocked() {
|
||||||
|
if (mGroup != null) {
|
||||||
|
return mGroup.isBlocked();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBlocked(boolean blocked) {
|
||||||
|
if (mGroup != null) {
|
||||||
|
mGroup.setBlocked(blocked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,8 +19,6 @@ com.android.settings.wifi.WifiInfo
|
|||||||
com.android.settings.applications.VrListenerSettings
|
com.android.settings.applications.VrListenerSettings
|
||||||
com.android.settings.inputmethod.UserDictionaryList
|
com.android.settings.inputmethod.UserDictionaryList
|
||||||
com.android.settings.datausage.DataSaverSummary
|
com.android.settings.datausage.DataSaverSummary
|
||||||
com.android.settings.notification.ChannelNotificationSettings
|
|
||||||
com.android.settings.notification.ChannelGroupNotificationSettings
|
|
||||||
com.android.settings.datausage.AppDataUsage
|
com.android.settings.datausage.AppDataUsage
|
||||||
com.android.settings.datausage.DataPlanUsageSummary
|
com.android.settings.datausage.DataPlanUsageSummary
|
||||||
com.android.settings.accessibility.FontSizePreferenceFragmentForSetupWizard
|
com.android.settings.accessibility.FontSizePreferenceFragmentForSetupWizard
|
||||||
@@ -55,7 +53,6 @@ com.android.settings.applications.InstalledAppDetails
|
|||||||
com.android.settings.accessibility.ToggleAccessibilityServicePreferenceFragment
|
com.android.settings.accessibility.ToggleAccessibilityServicePreferenceFragment
|
||||||
com.android.settings.print.PrintServiceSettingsFragment
|
com.android.settings.print.PrintServiceSettingsFragment
|
||||||
com.android.settings.wfd.WifiDisplaySettings
|
com.android.settings.wfd.WifiDisplaySettings
|
||||||
com.android.settings.notification.AppNotificationSettings
|
|
||||||
com.android.settings.deviceinfo.PrivateVolumeSettings
|
com.android.settings.deviceinfo.PrivateVolumeSettings
|
||||||
com.android.settings.users.AppRestrictionsFragment
|
com.android.settings.users.AppRestrictionsFragment
|
||||||
com.android.settings.deviceinfo.PrivateVolumeUnmount
|
com.android.settings.deviceinfo.PrivateVolumeUnmount
|
||||||
|
|||||||
@@ -0,0 +1,244 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_HIGH;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
import android.support.v7.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
|
import com.android.settingslib.RestrictedSwitchPreference;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Answers;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.shadows.ShadowApplication;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = Build.VERSION_CODES.O)
|
||||||
|
public class AllowSoundPreferenceControllerTest {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
@Mock
|
||||||
|
private NotificationBackend mBackend;
|
||||||
|
@Mock
|
||||||
|
private NotificationManager mNm;
|
||||||
|
@Mock
|
||||||
|
private UserManager mUm;
|
||||||
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
|
private PreferenceScreen mScreen;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
NotificationSettingsBase.ImportanceListener mImportanceListener;
|
||||||
|
|
||||||
|
private AllowSoundPreferenceController mController;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
ShadowApplication shadowApplication = ShadowApplication.getInstance();
|
||||||
|
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
|
||||||
|
shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
|
||||||
|
mContext = shadowApplication.getApplicationContext();
|
||||||
|
mController =
|
||||||
|
spy(new AllowSoundPreferenceController(mContext, mImportanceListener, mBackend));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoCrashIfNoOnResume() throws Exception {
|
||||||
|
mController.isAvailable();
|
||||||
|
mController.updateState(mock(RestrictedSwitchPreference.class));
|
||||||
|
mController.onPreferenceChange(mock(RestrictedSwitchPreference.class), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfNull() throws Exception {
|
||||||
|
mController.onResume(null, mock(NotificationChannel.class), null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
|
||||||
|
mController.onResume(mock(NotificationBackend.AppRow.class), null, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfAppBlocked() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.banned = true;
|
||||||
|
mController.onResume(appRow, mock(NotificationChannel.class), null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfAppCreatedChannel() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn("something new");
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
|
||||||
|
when(channel.getId()).thenReturn(DEFAULT_CHANNEL_ID);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_disabledByAdmin() throws Exception {
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn("something");
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
|
||||||
|
RestrictedLockUtils.EnforcedAdmin.class));
|
||||||
|
|
||||||
|
Preference pref = new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertFalse(pref.isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_notConfigurable() throws Exception {
|
||||||
|
String lockedId = "locked";
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.lockedChannelId = lockedId;
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn(lockedId);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
Preference pref = new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertFalse(pref.isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_configurable() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn("something");
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
Preference pref = new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertTrue(pref.isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_checkedForHighImportanceChannel() throws Exception {
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref = new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
assertTrue(pref.isChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_checkedForUnspecifiedImportanceChannel() throws Exception {
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_UNSPECIFIED);
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref = new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
assertTrue(pref.isChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_notCheckedForLowImportanceChannel() throws Exception {
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref =
|
||||||
|
new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
assertFalse(pref.isChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPreferenceChange_on() {
|
||||||
|
NotificationChannel channel =
|
||||||
|
new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_LOW);
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref =
|
||||||
|
new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
|
||||||
|
mController.displayPreference(mScreen);
|
||||||
|
mController.updateState(pref);
|
||||||
|
pref.setChecked(true);
|
||||||
|
mController.onPreferenceChange(pref, true);
|
||||||
|
|
||||||
|
assertEquals(IMPORTANCE_UNSPECIFIED, mController.mChannel.getImportance());
|
||||||
|
verify(mImportanceListener, times(1)).onImportanceChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPreferenceChange_off() {
|
||||||
|
NotificationChannel channel =
|
||||||
|
new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_HIGH);
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref =
|
||||||
|
new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
|
||||||
|
mController.displayPreference(mScreen);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
pref.setChecked(false);
|
||||||
|
mController.onPreferenceChange(pref, false);
|
||||||
|
|
||||||
|
verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());
|
||||||
|
assertEquals(IMPORTANCE_LOW, mController.mChannel.getImportance());
|
||||||
|
verify(mImportanceListener, times(1)).onImportanceChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.shadows.ShadowApplication;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = Build.VERSION_CODES.O)
|
||||||
|
public class AppLinkPreferenceControllerTest {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
@Mock
|
||||||
|
private NotificationManager mNm;
|
||||||
|
@Mock
|
||||||
|
private UserManager mUm;
|
||||||
|
|
||||||
|
private AppLinkPreferenceController mController;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
ShadowApplication shadowApplication = ShadowApplication.getInstance();
|
||||||
|
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
|
||||||
|
shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
|
||||||
|
mContext = shadowApplication.getApplicationContext();
|
||||||
|
mController = spy(new AppLinkPreferenceController(mContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoCrashIfNoOnResume() throws Exception {
|
||||||
|
mController.isAvailable();
|
||||||
|
mController.updateState(mock(Preference.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfNull() throws Exception {
|
||||||
|
mController.onResume(null, null, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfAppBlocked() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.banned = true;
|
||||||
|
mController.onResume(appRow, null, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfChannelBlocked() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_NONE);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notNoIntent() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
|
||||||
|
when(channel.getId()).thenReturn(DEFAULT_CHANNEL_ID);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.settingsIntent = new Intent("test");
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
|
||||||
|
when(channel.getId()).thenReturn(DEFAULT_CHANNEL_ID);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
Intent intent = new Intent("action");
|
||||||
|
appRow.settingsIntent = intent;
|
||||||
|
mController.onResume(appRow, null, null, null);
|
||||||
|
|
||||||
|
Preference pref = new Preference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertEquals(intent, pref.getIntent());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,298 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_HIGH;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
|
||||||
|
import static android.provider.Settings.Secure.NOTIFICATION_BADGING;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
import android.support.v7.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
|
import com.android.settingslib.RestrictedSwitchPreference;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Answers;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.shadows.ShadowApplication;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = Build.VERSION_CODES.O)
|
||||||
|
public class BadgePreferenceControllerTest {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
@Mock
|
||||||
|
private NotificationBackend mBackend;
|
||||||
|
@Mock
|
||||||
|
private NotificationManager mNm;
|
||||||
|
@Mock
|
||||||
|
private UserManager mUm;
|
||||||
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
|
private PreferenceScreen mScreen;
|
||||||
|
|
||||||
|
private BadgePreferenceController mController;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
ShadowApplication shadowApplication = ShadowApplication.getInstance();
|
||||||
|
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
|
||||||
|
shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
|
||||||
|
mContext = shadowApplication.getApplicationContext();
|
||||||
|
mController = spy(new BadgePreferenceController(mContext, mBackend));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoCrashIfNoOnResume() throws Exception {
|
||||||
|
mController.isAvailable();
|
||||||
|
mController.updateState(mock(RestrictedSwitchPreference.class));
|
||||||
|
mController.onPreferenceChange(mock(RestrictedSwitchPreference.class), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfAppBlocked() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.banned = true;
|
||||||
|
mController.onResume(appRow, mock(NotificationChannel.class), null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfChannelBlocked() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_NONE);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_channel_notIfAppOff() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.showBadge = false;
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfOffGlobally() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
Settings.Secure.putInt(mContext.getContentResolver(), NOTIFICATION_BADGING, 0);
|
||||||
|
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_app() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
mController.onResume(appRow, null, null, null);
|
||||||
|
Settings.Secure.putInt(mContext.getContentResolver(), NOTIFICATION_BADGING, 1);
|
||||||
|
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_channel() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.showBadge = true;
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
Settings.Secure.putInt(mContext.getContentResolver(), NOTIFICATION_BADGING, 1);
|
||||||
|
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_disabledByAdmin() throws Exception {
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn("something");
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
|
||||||
|
RestrictedLockUtils.EnforcedAdmin.class));
|
||||||
|
|
||||||
|
Preference pref = new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertFalse(pref.isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_channelNotConfigurable() throws Exception {
|
||||||
|
String lockedId = "locked";
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.lockedChannelId = lockedId;
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn(lockedId);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
Preference pref = new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertFalse(pref.isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_channel() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.lockedChannelId = "a";
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.canShowBadge()).thenReturn(true);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref =
|
||||||
|
new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertTrue(pref.isChecked());
|
||||||
|
|
||||||
|
when(channel.canShowBadge()).thenReturn(false);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertFalse(pref.isChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_app() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.showBadge = true;
|
||||||
|
mController.onResume(appRow, null, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref =
|
||||||
|
new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
assertTrue(pref.isChecked());
|
||||||
|
|
||||||
|
appRow.showBadge = false;
|
||||||
|
mController.onResume(appRow, null, null, null);
|
||||||
|
|
||||||
|
mController.updateState(pref);
|
||||||
|
assertFalse(pref.isChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPreferenceChange_on_channel() {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.showBadge = true;
|
||||||
|
NotificationChannel channel =
|
||||||
|
new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_LOW);
|
||||||
|
channel.setShowBadge(false);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref =
|
||||||
|
new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
|
||||||
|
mController.displayPreference(mScreen);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
mController.onPreferenceChange(pref, true);
|
||||||
|
assertTrue(channel.canShowBadge());
|
||||||
|
verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPreferenceChange_off_channel() {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.showBadge = true;
|
||||||
|
NotificationChannel channel =
|
||||||
|
new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_HIGH);
|
||||||
|
channel.setShowBadge(true);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref =
|
||||||
|
new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
|
||||||
|
mController.displayPreference(mScreen);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
mController.onPreferenceChange(pref, false);
|
||||||
|
verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());
|
||||||
|
assertFalse(channel.canShowBadge());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPreferenceChange_on_app() {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.showBadge = false;
|
||||||
|
mController.onResume(appRow, null, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref =
|
||||||
|
new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
|
||||||
|
mController.displayPreference(mScreen);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
mController.onPreferenceChange(pref, true);
|
||||||
|
|
||||||
|
assertTrue(appRow.showBadge);
|
||||||
|
verify(mBackend, times(1)).setShowBadge(any(), anyInt(), eq(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPreferenceChange_off_app() {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.showBadge = true;
|
||||||
|
mController.onResume(appRow, null, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref =
|
||||||
|
new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
|
||||||
|
mController.displayPreference(mScreen);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
mController.onPreferenceChange(pref, false);
|
||||||
|
|
||||||
|
assertFalse(appRow.showBadge);
|
||||||
|
verify(mBackend, times(1)).setShowBadge(any(), anyInt(), eq(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
|
||||||
|
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_NONE;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertNotNull;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationChannelGroup;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.UserManager;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.applications.LayoutPreference;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settings.widget.SwitchBar;
|
||||||
|
import com.android.settings.wrapper.NotificationChannelGroupWrapper;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.shadows.ShadowApplication;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = Build.VERSION_CODES.O)
|
||||||
|
public class BlockPreferenceControllerTest {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
@Mock
|
||||||
|
private NotificationBackend mBackend;
|
||||||
|
@Mock
|
||||||
|
private NotificationManager mNm;
|
||||||
|
@Mock
|
||||||
|
private UserManager mUm;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
NotificationSettingsBase.ImportanceListener mImportanceListener;
|
||||||
|
|
||||||
|
private BlockPreferenceController mController;
|
||||||
|
@Mock
|
||||||
|
private LayoutPreference mPreference;
|
||||||
|
private SwitchBar mSwitch;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
ShadowApplication shadowApplication = ShadowApplication.getInstance();
|
||||||
|
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
|
||||||
|
shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
|
||||||
|
mContext = shadowApplication.getApplicationContext();
|
||||||
|
mController = spy(new BlockPreferenceController(mContext, mImportanceListener, mBackend));
|
||||||
|
mSwitch = new SwitchBar(mContext);
|
||||||
|
when(mPreference.findViewById(R.id.switch_bar)).thenReturn(mSwitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoCrashIfNoOnResume() throws Exception {
|
||||||
|
mController.isAvailable();
|
||||||
|
mController.updateState(mock(LayoutPreference.class));
|
||||||
|
mController.onSwitchChanged(null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfNull() throws Exception {
|
||||||
|
mController.onResume(null, null, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfChannelNotBlockable() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.systemApp = true;
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfGroupNotBlockable() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.systemApp = true;
|
||||||
|
mController.onResume(appRow, null, mock(NotificationChannelGroupWrapper.class), null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfAppNotBlockable() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.systemApp = true;
|
||||||
|
mController.onResume(appRow, null, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_systemApp() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.systemApp = true;
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_NONE);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_nonSystemApp() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.systemApp = false;
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_app() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.banned = true;
|
||||||
|
mController.onResume(appRow, null, null, null);
|
||||||
|
mController.updateState(mPreference);
|
||||||
|
|
||||||
|
assertNotNull(mPreference.findViewById(R.id.switch_bar));
|
||||||
|
|
||||||
|
assertFalse(mSwitch.isChecked());
|
||||||
|
|
||||||
|
appRow.banned = false;
|
||||||
|
mController.onResume(appRow, null, null, null);
|
||||||
|
mController.updateState(mPreference);
|
||||||
|
|
||||||
|
assertTrue(mSwitch.isChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_group() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannelGroupWrapper group = mock(NotificationChannelGroupWrapper.class);
|
||||||
|
when(group.getGroup()).thenReturn(mock(NotificationChannelGroup.class));
|
||||||
|
when(group.isBlocked()).thenReturn(true);
|
||||||
|
mController.onResume(appRow, null, group, null);
|
||||||
|
mController.updateState(mPreference);
|
||||||
|
|
||||||
|
assertFalse(mSwitch.isChecked());
|
||||||
|
|
||||||
|
appRow.banned = true;
|
||||||
|
mController.onResume(appRow, null, group, null);
|
||||||
|
when(group.isBlocked()).thenReturn(true);
|
||||||
|
mController.updateState(mPreference);
|
||||||
|
|
||||||
|
assertFalse(mSwitch.isChecked());
|
||||||
|
|
||||||
|
appRow.banned = false;
|
||||||
|
mController.onResume(appRow, null, group, null);
|
||||||
|
when(group.isBlocked()).thenReturn(false);
|
||||||
|
mController.updateState(mPreference);
|
||||||
|
|
||||||
|
assertTrue(mSwitch.isChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_channelBlocked() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_NONE);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
mController.updateState(mPreference);
|
||||||
|
|
||||||
|
assertFalse(mSwitch.isChecked());
|
||||||
|
|
||||||
|
appRow.banned = true;
|
||||||
|
channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
mController.updateState(mPreference);
|
||||||
|
|
||||||
|
assertFalse(mSwitch.isChecked());
|
||||||
|
|
||||||
|
appRow.banned = false;
|
||||||
|
channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
mController.updateState(mPreference);
|
||||||
|
|
||||||
|
assertTrue(mSwitch.isChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_noCrashIfCalledTwice() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
mController.updateState(mPreference);
|
||||||
|
mController.updateState(mPreference);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_doesNotResetImportance() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
mController.updateState(mPreference);
|
||||||
|
|
||||||
|
assertEquals(IMPORTANCE_LOW, channel.getImportance());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnSwitchChanged_channel_default() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel =
|
||||||
|
new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_UNSPECIFIED);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
mController.updateState(mPreference);
|
||||||
|
|
||||||
|
mController.onSwitchChanged(null, false);
|
||||||
|
assertEquals(IMPORTANCE_NONE, channel.getImportance());
|
||||||
|
|
||||||
|
mController.onSwitchChanged(null, true);
|
||||||
|
assertEquals(IMPORTANCE_UNSPECIFIED, channel.getImportance());
|
||||||
|
|
||||||
|
verify(mBackend, times(2)).updateChannel(any(), anyInt(), any());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnSwitchChanged_channel_nonDefault() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
mController.updateState(mPreference);
|
||||||
|
|
||||||
|
mController.onSwitchChanged(null, false);
|
||||||
|
assertEquals(IMPORTANCE_NONE, channel.getImportance());
|
||||||
|
|
||||||
|
mController.onSwitchChanged(null, true);
|
||||||
|
assertEquals(IMPORTANCE_DEFAULT, channel.getImportance());
|
||||||
|
|
||||||
|
verify(mBackend, times(2)).updateChannel(any(), anyInt(), any());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.Mockito.any;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.wrapper.NotificationChannelGroupWrapper;
|
||||||
|
|
||||||
|
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.annotation.Config;
|
||||||
|
import org.robolectric.shadows.ShadowApplication;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
|
public class DeletedChannelsPreferenceControllerTest {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
@Mock
|
||||||
|
private NotificationBackend mBackend;
|
||||||
|
@Mock
|
||||||
|
private NotificationManager mNm;
|
||||||
|
@Mock
|
||||||
|
private UserManager mUm;
|
||||||
|
|
||||||
|
private DeletedChannelsPreferenceController mController;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
ShadowApplication shadowApplication = ShadowApplication.getInstance();
|
||||||
|
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
|
||||||
|
shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
|
||||||
|
mContext = shadowApplication.getApplicationContext();
|
||||||
|
mController = new DeletedChannelsPreferenceController(mContext, mBackend);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void noCrashIfNoOnResume() throws Exception {
|
||||||
|
mController.isAvailable();
|
||||||
|
mController.updateState(mock(Preference.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isAvailable_appScreen_notIfAppBlocked() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.banned = true;
|
||||||
|
mController.onResume(appRow, null, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isAvailable_groupScreen_never() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
mController.onResume(appRow, null, mock(NotificationChannelGroupWrapper.class), null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isAvailable_channelScreen_never() throws Exception {
|
||||||
|
mController.onResume(
|
||||||
|
new NotificationBackend.AppRow(), mock(NotificationChannel.class), null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isAvailable_appScreen_notIfNoDeletedChannels() throws Exception {
|
||||||
|
when(mBackend.getDeletedChannelCount(any(), anyInt())).thenReturn(0);
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), null, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isAvailable_appScreen() throws Exception {
|
||||||
|
when(mBackend.getDeletedChannelCount(any(), anyInt())).thenReturn(1);
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), null, null, null);
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateState() throws Exception {
|
||||||
|
when(mBackend.getDeletedChannelCount(any(), anyInt())).thenReturn(1);
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), null, null, null);
|
||||||
|
|
||||||
|
Preference pref = mock(Preference.class);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
verify(pref, times(1)).setEnabled(false);
|
||||||
|
verify(pref, times(1)).setSelectable(false);
|
||||||
|
verify(mBackend, times(1)).getDeletedChannelCount(any(), anyInt());
|
||||||
|
ArgumentCaptor<CharSequence> argumentCaptor = ArgumentCaptor.forClass(CharSequence.class);
|
||||||
|
verify(pref, times(1)).setTitle(argumentCaptor.capture());
|
||||||
|
assertTrue(argumentCaptor.getValue().toString().contains("1"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationChannelGroup;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settings.wrapper.NotificationChannelGroupWrapper;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.shadows.ShadowApplication;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = Build.VERSION_CODES.O)
|
||||||
|
public class DescriptionPreferenceControllerTest {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
@Mock
|
||||||
|
private NotificationManager mNm;
|
||||||
|
@Mock
|
||||||
|
private UserManager mUm;
|
||||||
|
|
||||||
|
private DescriptionPreferenceController mController;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
ShadowApplication shadowApplication = ShadowApplication.getInstance();
|
||||||
|
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
|
||||||
|
shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
|
||||||
|
mContext = shadowApplication.getApplicationContext();
|
||||||
|
mController = spy(new DescriptionPreferenceController(mContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoCrashIfNoOnResume() throws Exception {
|
||||||
|
mController.isAvailable();
|
||||||
|
mController.updateState(mock(Preference.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfNull() throws Exception {
|
||||||
|
mController.onResume(null, null, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfChannelGroupBlocked() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannelGroupWrapper group = mock(NotificationChannelGroupWrapper.class);
|
||||||
|
when(group.isBlocked()).thenReturn(true);
|
||||||
|
mController.onResume(appRow, null, group, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfChannelBlocked() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_NONE);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfNoChannelDesc() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfNoChannelGroupDesc() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannelGroupWrapper group = mock(NotificationChannelGroupWrapper.class);
|
||||||
|
when(group.getGroup()).thenReturn(mock(NotificationChannelGroup.class));
|
||||||
|
mController.onResume(appRow, null, group, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_channel() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
|
||||||
|
when(channel.getDescription()).thenReturn("AAA");
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_channelGroup() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannelGroupWrapper group = mock(NotificationChannelGroupWrapper.class);
|
||||||
|
when(group.getGroup()).thenReturn(mock(NotificationChannelGroup.class));
|
||||||
|
when(group.getDescription()).thenReturn("something");
|
||||||
|
when(group.isBlocked()).thenReturn(false);
|
||||||
|
mController.onResume(appRow, null, group, null);
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_channel() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
|
||||||
|
when(channel.getDescription()).thenReturn("AAA");
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
Preference pref = new Preference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertEquals("AAA", pref.getTitle());
|
||||||
|
assertFalse(pref.isEnabled());
|
||||||
|
assertFalse(pref.isSelectable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_channelGroup() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannelGroupWrapper group = mock(NotificationChannelGroupWrapper.class);
|
||||||
|
when(group.getGroup()).thenReturn(mock(NotificationChannelGroup.class));
|
||||||
|
when(group.getDescription()).thenReturn("something");
|
||||||
|
mController.onResume(appRow, null, group, null);
|
||||||
|
|
||||||
|
Preference pref = new Preference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertEquals("something", pref.getTitle());
|
||||||
|
assertFalse(pref.isEnabled());
|
||||||
|
assertFalse(pref.isSelectable());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,240 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
|
||||||
|
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 junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
import android.support.v7.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
|
import com.android.settingslib.RestrictedSwitchPreference;
|
||||||
|
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Answers;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.shadows.ShadowApplication;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = Build.VERSION_CODES.O)
|
||||||
|
public class DndPreferenceControllerTest {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
@Mock
|
||||||
|
private NotificationBackend mBackend;
|
||||||
|
@Mock
|
||||||
|
private NotificationManager mNm;
|
||||||
|
@Mock
|
||||||
|
private UserManager mUm;
|
||||||
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
|
private PreferenceScreen mScreen;
|
||||||
|
@Mock
|
||||||
|
private Lifecycle mLifecycle;
|
||||||
|
|
||||||
|
private DndPreferenceController mController;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
ShadowApplication shadowApplication = ShadowApplication.getInstance();
|
||||||
|
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
|
||||||
|
shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
|
||||||
|
mContext = shadowApplication.getApplicationContext();
|
||||||
|
mController = spy(new DndPreferenceController(mContext, mLifecycle, mBackend));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoCrashIfNoOnResume() throws Exception {
|
||||||
|
mController.isAvailable();
|
||||||
|
mController.updateState(mock(RestrictedSwitchPreference.class));
|
||||||
|
mController.onPreferenceChange(mock(RestrictedSwitchPreference.class), true);
|
||||||
|
mController.onResume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfNotImportant_noVisEffects() throws Exception {
|
||||||
|
when(mNm.getNotificationPolicy()).thenReturn(new NotificationManager.Policy(0, 0, 0, 0));
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_LOW);
|
||||||
|
mController.onResume();
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfNotImportant_visEffects() throws Exception {
|
||||||
|
when(mNm.getNotificationPolicy()).thenReturn(new NotificationManager.Policy(0, 0, 0, 1));
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_MIN);
|
||||||
|
mController.onResume();
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_importance_noVisEffects() throws Exception {
|
||||||
|
when(mNm.getNotificationPolicy()).thenReturn(new NotificationManager.Policy(0, 0, 0, 0));
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT);
|
||||||
|
mController.onResume();
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_important_visEffects() throws Exception {
|
||||||
|
when(mNm.getNotificationPolicy()).thenReturn(new NotificationManager.Policy(0, 0, 0, 1));
|
||||||
|
assertTrue(mNm.getNotificationPolicy().suppressedVisualEffects != 0);
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_LOW);
|
||||||
|
mController.onResume();
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_disabledByAdmin() throws Exception {
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn("something");
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
|
||||||
|
RestrictedLockUtils.EnforcedAdmin.class));
|
||||||
|
|
||||||
|
Preference pref = new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertFalse(pref.isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_notConfigurable() throws Exception {
|
||||||
|
String lockedId = "locked";
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.lockedChannelId = lockedId;
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn(lockedId);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
Preference pref = new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertFalse(pref.isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_configurable() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn("something");
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
Preference pref = new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertTrue(pref.isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_bypassDnd() throws Exception {
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.canBypassDnd()).thenReturn(true);
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref =
|
||||||
|
new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
assertTrue(pref.isChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_noBypassDnd() throws Exception {
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.canBypassDnd()).thenReturn(false);
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref =
|
||||||
|
new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
assertFalse(pref.isChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPreferenceChange_on() {
|
||||||
|
NotificationChannel channel =
|
||||||
|
new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_LOW);
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref =
|
||||||
|
new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
|
||||||
|
mController.displayPreference(mScreen);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
mController.onPreferenceChange(pref, true);
|
||||||
|
|
||||||
|
assertTrue(channel.canBypassDnd());
|
||||||
|
verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPreferenceChange_off() {
|
||||||
|
NotificationChannel channel =
|
||||||
|
new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_HIGH);
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref =
|
||||||
|
new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
|
||||||
|
mController.displayPreference(mScreen);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
mController.onPreferenceChange(pref, false);
|
||||||
|
|
||||||
|
assertFalse(channel.canBypassDnd());
|
||||||
|
verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationChannelGroup;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.support.v14.preference.PreferenceFragment;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.applications.LayoutPreference;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settings.wrapper.NotificationChannelGroupWrapper;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.shadows.ShadowApplication;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = Build.VERSION_CODES.O)
|
||||||
|
public class HeaderPreferenceControllerTest {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
@Mock
|
||||||
|
private NotificationManager mNm;
|
||||||
|
@Mock
|
||||||
|
private UserManager mUm;
|
||||||
|
|
||||||
|
private HeaderPreferenceController mController;
|
||||||
|
@Mock
|
||||||
|
private LayoutPreference mPreference;
|
||||||
|
@Mock
|
||||||
|
private View mView;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
ShadowApplication shadowApplication = ShadowApplication.getInstance();
|
||||||
|
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
|
||||||
|
shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
|
||||||
|
mContext = shadowApplication.getApplicationContext();
|
||||||
|
PreferenceFragment fragment = mock(PreferenceFragment.class);
|
||||||
|
when(fragment.getContext()).thenReturn(mContext);
|
||||||
|
Activity activity = mock(Activity.class);
|
||||||
|
when(activity.getApplicationContext()).thenReturn(mContext);
|
||||||
|
when(fragment.getActivity()).thenReturn(activity);
|
||||||
|
mController = spy(new HeaderPreferenceController(mContext, fragment));
|
||||||
|
when(mPreference.findViewById(anyInt())).thenReturn(mView);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoCrashIfNoOnResume() throws Exception {
|
||||||
|
mController.isAvailable();
|
||||||
|
mController.updateState(mock(LayoutPreference.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfNull() throws Exception {
|
||||||
|
mController.onResume(null, null, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.banned = true;
|
||||||
|
mController.onResume(appRow, null, null, null);
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetLabel() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.label = "bananas";
|
||||||
|
mController.onResume(appRow, null, null, null);
|
||||||
|
assertEquals(appRow.label, mController.getLabel());
|
||||||
|
|
||||||
|
NotificationChannelGroup group = new NotificationChannelGroup("id", "name");
|
||||||
|
NotificationChannelGroupWrapper gWrapper = new NotificationChannelGroupWrapper(group);
|
||||||
|
mController.onResume(appRow, null, gWrapper, null);
|
||||||
|
assertEquals(group.getName(), mController.getLabel());
|
||||||
|
|
||||||
|
NotificationChannel channel = new NotificationChannel("cid", "cname", IMPORTANCE_NONE);
|
||||||
|
mController.onResume(appRow, channel, gWrapper, null);
|
||||||
|
assertEquals(channel.getName(), mController.getLabel());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetSummary() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.label = "bananas";
|
||||||
|
mController.onResume(appRow, null, null, null);
|
||||||
|
assertEquals("", mController.getSummary());
|
||||||
|
|
||||||
|
NotificationChannelGroup group = new NotificationChannelGroup("id", "name");
|
||||||
|
NotificationChannelGroupWrapper gWrapper = new NotificationChannelGroupWrapper(group);
|
||||||
|
mController.onResume(appRow, null, gWrapper, null);
|
||||||
|
assertEquals(appRow.label, mController.getSummary());
|
||||||
|
|
||||||
|
NotificationChannel channel = new NotificationChannel("cid", "cname", IMPORTANCE_NONE);
|
||||||
|
mController.onResume(appRow, channel, gWrapper, null);
|
||||||
|
assertTrue(mController.getSummary().toString().contains(group.getName()));
|
||||||
|
assertTrue(mController.getSummary().toString().contains(appRow.label));
|
||||||
|
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.getSummary().toString().contains(group.getName()));
|
||||||
|
assertTrue(mController.getSummary().toString().contains(appRow.label));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_HIGH;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertNull;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.shadows.ShadowApplication;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = Build.VERSION_CODES.O)
|
||||||
|
public class ImportancePreferenceControllerTest {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
@Mock
|
||||||
|
private NotificationManager mNm;
|
||||||
|
@Mock
|
||||||
|
private UserManager mUm;
|
||||||
|
|
||||||
|
private ImportancePreferenceController mController;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
ShadowApplication shadowApplication = ShadowApplication.getInstance();
|
||||||
|
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
|
||||||
|
shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
|
||||||
|
mContext = shadowApplication.getApplicationContext();
|
||||||
|
mController = spy(new ImportancePreferenceController(mContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoCrashIfNoOnResume() throws Exception {
|
||||||
|
mController.isAvailable();
|
||||||
|
mController.updateState(mock(Preference.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfNull() throws Exception {
|
||||||
|
mController.onResume(null, null, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfAppBlocked() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.banned = true;
|
||||||
|
mController.onResume(appRow, mock(NotificationChannel.class), null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfChannelBlocked() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_NONE);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notForDefaultChannel() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
|
||||||
|
when(channel.getId()).thenReturn(DEFAULT_CHANNEL_ID);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_disabledByAdmin() throws Exception {
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
|
||||||
|
RestrictedLockUtils.EnforcedAdmin.class));
|
||||||
|
|
||||||
|
Preference pref = new Preference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertFalse(pref.isEnabled());
|
||||||
|
assertNull(pref.getIntent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_notConfigurable() throws Exception {
|
||||||
|
String lockedId = "locked";
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.lockedChannelId = lockedId;
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn(lockedId);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
Preference pref = new Preference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertFalse(pref.isEnabled());
|
||||||
|
assertNull(pref.getIntent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_HIGH);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
Preference pref = new Preference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertTrue(pref.isEnabled());
|
||||||
|
assertNotNull(pref.getIntent());
|
||||||
|
assertFalse(TextUtils.isEmpty(pref.getSummary()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,245 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_HIGH;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||||
|
import static android.provider.Settings.System.NOTIFICATION_LIGHT_PULSE;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
import android.support.v7.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settings.testutils.shadow.SettingsShadowResources;
|
||||||
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
|
import com.android.settingslib.RestrictedSwitchPreference;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Answers;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.shadows.ShadowApplication;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = Build.VERSION_CODES.O, shadows = {
|
||||||
|
SettingsShadowResources.class,
|
||||||
|
})
|
||||||
|
public class LightsPreferenceControllerTest {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
@Mock
|
||||||
|
private NotificationBackend mBackend;
|
||||||
|
@Mock
|
||||||
|
private NotificationManager mNm;
|
||||||
|
@Mock
|
||||||
|
private UserManager mUm;
|
||||||
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
|
private PreferenceScreen mScreen;
|
||||||
|
|
||||||
|
private LightsPreferenceController mController;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
ShadowApplication shadowApplication = ShadowApplication.getInstance();
|
||||||
|
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
|
||||||
|
shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
|
||||||
|
mContext = shadowApplication.getApplicationContext();
|
||||||
|
mController = spy(new LightsPreferenceController(mContext, mBackend));
|
||||||
|
|
||||||
|
// By default allow lights
|
||||||
|
SettingsShadowResources.overrideResource(
|
||||||
|
com.android.internal.R.bool.config_intrusiveNotificationLed, true);
|
||||||
|
Settings.Secure.putInt(mContext.getContentResolver(), NOTIFICATION_LIGHT_PULSE, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoCrashIfNoOnResume() throws Exception {
|
||||||
|
mController.isAvailable();
|
||||||
|
mController.updateState(mock(RestrictedSwitchPreference.class));
|
||||||
|
mController.onPreferenceChange(mock(RestrictedSwitchPreference.class), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfConfigNotAllowed() throws Exception {
|
||||||
|
SettingsShadowResources.overrideResource(
|
||||||
|
com.android.internal.R.bool.config_intrusiveNotificationLed, false);
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfSettingNotAllowed() throws Exception {
|
||||||
|
Settings.Secure.putInt(mContext.getContentResolver(), NOTIFICATION_LIGHT_PULSE, 0);
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfNotImportant() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_LOW);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfDefaultChannel() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel =
|
||||||
|
new NotificationChannel(DEFAULT_CHANNEL_ID, "", IMPORTANCE_DEFAULT);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_disabledByAdmin() throws Exception {
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn("something");
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
|
||||||
|
RestrictedLockUtils.EnforcedAdmin.class));
|
||||||
|
|
||||||
|
Preference pref = new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertFalse(pref.isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_notConfigurable() throws Exception {
|
||||||
|
String lockedId = "locked";
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.lockedChannelId = lockedId;
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn(lockedId);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
Preference pref = new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertFalse(pref.isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_configurable() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn("something");
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
Preference pref = new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertTrue(pref.isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_lightsOn() throws Exception {
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.shouldShowLights()).thenReturn(true);
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref =
|
||||||
|
new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
assertTrue(pref.isChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_lightsOff() throws Exception {
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.shouldShowLights()).thenReturn(false);
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref =
|
||||||
|
new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
assertFalse(pref.isChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPreferenceChange_on() {
|
||||||
|
NotificationChannel channel =
|
||||||
|
new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_DEFAULT);
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref =
|
||||||
|
new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
|
||||||
|
mController.displayPreference(mScreen);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
mController.onPreferenceChange(pref, true);
|
||||||
|
|
||||||
|
assertTrue(channel.shouldShowLights());
|
||||||
|
verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPreferenceChange_off() {
|
||||||
|
NotificationChannel channel =
|
||||||
|
new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_HIGH);
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref =
|
||||||
|
new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
|
||||||
|
mController.displayPreference(mScreen);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
mController.onPreferenceChange(pref, false);
|
||||||
|
|
||||||
|
assertFalse(channel.shouldShowLights());
|
||||||
|
verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,316 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
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 junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.Mockito.any;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationChannelGroup;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settings.wrapper.NotificationChannelGroupWrapper;
|
||||||
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Answers;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.shadows.ShadowApplication;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = Build.VERSION_CODES.O)
|
||||||
|
public class NotificationPreferenceControllerTest {
|
||||||
|
|
||||||
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
|
private Context mContext;
|
||||||
|
@Mock
|
||||||
|
private NotificationBackend mBackend;
|
||||||
|
@Mock
|
||||||
|
private NotificationManager mNm;
|
||||||
|
@Mock
|
||||||
|
private UserManager mUm;
|
||||||
|
|
||||||
|
private TestPreferenceController mController;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
ShadowApplication shadowApplication = ShadowApplication.getInstance();
|
||||||
|
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
|
||||||
|
shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
|
||||||
|
mContext = shadowApplication.getApplicationContext();
|
||||||
|
mController = new TestPreferenceController(mContext, mBackend);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void noCrashIfNoOnResume() throws Exception {
|
||||||
|
mController.isAvailable();
|
||||||
|
mController.updateState(mock(Preference.class));
|
||||||
|
assertFalse(mController.checkCanBeVisible(IMPORTANCE_UNSPECIFIED));
|
||||||
|
mController.saveChannel();
|
||||||
|
assertFalse(mController.isChannelConfigurable());
|
||||||
|
assertFalse(mController.isChannelBlockable());
|
||||||
|
assertFalse(mController.isChannelGroupBlockable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isAvailable_notIfNull() throws Exception {
|
||||||
|
mController.onResume(null, null, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isAvailable_notIfAppBlocked() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.banned = true;
|
||||||
|
mController.onResume(appRow, mock(NotificationChannel.class),
|
||||||
|
mock(NotificationChannelGroupWrapper.class), null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isAvailable_notIfChannelBlocked() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_NONE);
|
||||||
|
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isAvailable_notIfChannelGroupBlocked() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
NotificationChannelGroupWrapper group = mock(NotificationChannelGroupWrapper.class);
|
||||||
|
|
||||||
|
mController.onResume(appRow, channel, group, null);
|
||||||
|
when(group.isBlocked()).thenReturn(true);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isAvailable() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_DEFAULT);
|
||||||
|
NotificationChannelGroupWrapper group = mock(NotificationChannelGroupWrapper.class);
|
||||||
|
when(group.isBlocked()).thenReturn(false);
|
||||||
|
|
||||||
|
mController.onResume(appRow, channel, group, null);
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnResume() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
NotificationChannelGroupWrapper group = mock(NotificationChannelGroupWrapper.class);
|
||||||
|
RestrictedLockUtils.EnforcedAdmin admin = mock(RestrictedLockUtils.EnforcedAdmin.class);
|
||||||
|
|
||||||
|
mController.onResume(appRow, channel, group, admin);
|
||||||
|
|
||||||
|
assertEquals(appRow, mController.mAppRow);
|
||||||
|
assertEquals(channel, mController.mChannel);
|
||||||
|
assertEquals(group, mController.mChannelGroup);
|
||||||
|
assertEquals(admin, mController.mAdmin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCanBeVisible_unspecified() {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_UNSPECIFIED);
|
||||||
|
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertTrue(mController.checkCanBeVisible(IMPORTANCE_MIN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCanBeVisible_sameImportance() {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
|
||||||
|
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertTrue(mController.checkCanBeVisible(IMPORTANCE_LOW));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCanBeVisible_greaterImportance() {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
|
||||||
|
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertTrue(mController.checkCanBeVisible(IMPORTANCE_MIN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCanBeVisible_lesserImportance() {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
|
||||||
|
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.checkCanBeVisible(IMPORTANCE_DEFAULT));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSaveImportance() {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_DEFAULT);
|
||||||
|
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
mController.saveChannel();
|
||||||
|
verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsConfigurable() {
|
||||||
|
String sameId = "bananas";
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.lockedChannelId = sameId;
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn(sameId);
|
||||||
|
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isChannelConfigurable());
|
||||||
|
|
||||||
|
when(channel.getId()).thenReturn("something new");
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertTrue(mController.isChannelConfigurable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsChannelBlockable_nonSystemAppsBlockable() {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.systemApp = false;
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.isBlockableSystem()).thenReturn(false);
|
||||||
|
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertTrue(mController.isChannelBlockable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsChannelBlockable_mostSystemAppsNotBlockable() {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.systemApp = true;
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.isBlockableSystem()).thenReturn(false);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
|
||||||
|
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isChannelBlockable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsChannelBlockable_someSystemAppsAreBlockable() {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.systemApp = true;
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.isBlockableSystem()).thenReturn(true);
|
||||||
|
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertTrue(mController.isChannelBlockable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsChannelBlockable_canUndoSystemBlock() {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.systemApp = true;
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.isBlockableSystem()).thenReturn(false);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_NONE);
|
||||||
|
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertTrue(mController.isChannelBlockable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsChannelGroupBlockable_nonSystemBlockable() {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.systemApp = false;
|
||||||
|
NotificationChannelGroupWrapper group = mock(NotificationChannelGroupWrapper.class);
|
||||||
|
when(group.isBlocked()).thenReturn(false);
|
||||||
|
|
||||||
|
mController.onResume(appRow, null, group, null);
|
||||||
|
assertTrue(mController.isChannelGroupBlockable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsChannelGroupBlockable_SystemNotBlockable() {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.systemApp = true;
|
||||||
|
NotificationChannelGroupWrapper group = mock(NotificationChannelGroupWrapper.class);
|
||||||
|
when(group.isBlocked()).thenReturn(false);
|
||||||
|
|
||||||
|
mController.onResume(appRow, null, group, null);
|
||||||
|
assertFalse(mController.isChannelGroupBlockable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsChannelGroupBlockable_canUndoSystemBlock() {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.systemApp = true;
|
||||||
|
NotificationChannelGroupWrapper group = mock(NotificationChannelGroupWrapper.class);
|
||||||
|
when(group.isBlocked()).thenReturn(true);
|
||||||
|
|
||||||
|
mController.onResume(appRow, null, group, null);
|
||||||
|
assertTrue(mController.isChannelGroupBlockable());
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class TestPreferenceController extends NotificationPreferenceController {
|
||||||
|
|
||||||
|
public TestPreferenceController(Context context,
|
||||||
|
NotificationBackend backend) {
|
||||||
|
super(context, backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPreferenceKey() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settings.wrapper.NotificationChannelGroupWrapper;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.shadows.ShadowApplication;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = Build.VERSION_CODES.O)
|
||||||
|
public class NotificationsOffPreferenceControllerTest {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
@Mock
|
||||||
|
private NotificationManager mNm;
|
||||||
|
@Mock
|
||||||
|
private UserManager mUm;
|
||||||
|
|
||||||
|
private NotificationsOffPreferenceController mController;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
ShadowApplication shadowApplication = ShadowApplication.getInstance();
|
||||||
|
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
|
||||||
|
shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
|
||||||
|
mContext = shadowApplication.getApplicationContext();
|
||||||
|
mController = spy(new NotificationsOffPreferenceController(mContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoCrashIfNoOnResume() throws Exception {
|
||||||
|
mController.isAvailable();
|
||||||
|
mController.updateState(mock(Preference.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_yesIfAppBlocked() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.banned = true;
|
||||||
|
mController.onResume(appRow, null, null, null);
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_yesIfChannelGroupBlocked() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannelGroupWrapper group = mock(NotificationChannelGroupWrapper.class);
|
||||||
|
when(group.isBlocked()).thenReturn(true);
|
||||||
|
mController.onResume(appRow, null, group, null);
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_yesIfChannelBlocked() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_NONE);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_channel() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getImportance()).thenReturn(IMPORTANCE_NONE);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
Preference pref = new Preference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertTrue(pref.getTitle().toString().contains("category"));
|
||||||
|
assertFalse(pref.isEnabled());
|
||||||
|
assertFalse(pref.isSelectable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_channelGroup() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannelGroupWrapper group = mock(NotificationChannelGroupWrapper.class);
|
||||||
|
when(group.isBlocked()).thenReturn(true);
|
||||||
|
mController.onResume(appRow, null, group, null);
|
||||||
|
|
||||||
|
Preference pref = new Preference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertTrue(pref.getTitle().toString().contains("group"));
|
||||||
|
assertFalse(pref.isEnabled());
|
||||||
|
assertFalse(pref.isSelectable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_app() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.banned = true;
|
||||||
|
mController.onResume(appRow, null, null, null);
|
||||||
|
|
||||||
|
Preference pref = new Preference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertTrue(pref.getTitle().toString().contains("app"));
|
||||||
|
assertFalse(pref.isEnabled());
|
||||||
|
assertFalse(pref.isSelectable());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,257 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_HIGH;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.Fragment;
|
||||||
|
import android.app.Notification;
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
import android.support.v7.preference.PreferenceScreen;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
|
import com.android.settings.SettingsPreferenceFragment;
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Answers;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.shadows.ShadowApplication;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = Build.VERSION_CODES.O)
|
||||||
|
public class SoundPreferenceControllerTest {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
@Mock
|
||||||
|
private NotificationBackend mBackend;
|
||||||
|
@Mock
|
||||||
|
private NotificationManager mNm;
|
||||||
|
@Mock
|
||||||
|
private UserManager mUm;
|
||||||
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
|
private PreferenceScreen mScreen;
|
||||||
|
@Mock
|
||||||
|
private SettingsPreferenceFragment mFragment;
|
||||||
|
@Mock
|
||||||
|
private NotificationSettingsBase.ImportanceListener mImportanceListener;
|
||||||
|
|
||||||
|
private SoundPreferenceController mController;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
ShadowApplication shadowApplication = ShadowApplication.getInstance();
|
||||||
|
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
|
||||||
|
shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
|
||||||
|
mContext = shadowApplication.getApplicationContext();
|
||||||
|
mController = spy(new SoundPreferenceController(
|
||||||
|
mContext, mFragment, mImportanceListener, mBackend));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoCrashIfNoOnResume() throws Exception {
|
||||||
|
mController.isAvailable();
|
||||||
|
mController.updateState(mock(NotificationSoundPreference.class));
|
||||||
|
mController.onPreferenceChange(mock(NotificationSoundPreference.class), Uri.EMPTY);
|
||||||
|
mController.handlePreferenceTreeClick(mock(NotificationSoundPreference.class));
|
||||||
|
mController.onActivityResult(1, 1, null);
|
||||||
|
mController.hasValidSound(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfChannelNull() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
mController.onResume(appRow, null, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfNotImportant() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_LOW);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfDefaultChannel() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel =
|
||||||
|
new NotificationChannel(DEFAULT_CHANNEL_ID, "", IMPORTANCE_DEFAULT);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDisplayPreference_savesPreference() throws Exception {
|
||||||
|
NotificationSoundPreference pref = mock(NotificationSoundPreference.class);
|
||||||
|
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
|
||||||
|
mController.displayPreference(mScreen);
|
||||||
|
|
||||||
|
mController.onActivityResult(SoundPreferenceController.CODE, 1, new Intent());
|
||||||
|
verify(pref, times(1)).onActivityResult(anyInt(), anyInt(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_disabledByAdmin() throws Exception {
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn("something");
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
|
||||||
|
RestrictedLockUtils.EnforcedAdmin.class));
|
||||||
|
|
||||||
|
Preference pref = new NotificationSoundPreference(mContext, mock(AttributeSet.class));
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertFalse(pref.isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_notConfigurable() throws Exception {
|
||||||
|
String lockedId = "locked";
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.lockedChannelId = lockedId;
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn(lockedId);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
Preference pref = new NotificationSoundPreference(mContext, mock(AttributeSet.class));
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertFalse(pref.isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_configurable() throws Exception {
|
||||||
|
Uri sound = Settings.System.DEFAULT_ALARM_ALERT_URI;
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn("something");
|
||||||
|
when(channel.getSound()).thenReturn(sound);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
NotificationSoundPreference pref =
|
||||||
|
new NotificationSoundPreference(mContext, mock(AttributeSet.class));
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertEquals(sound, pref.onRestoreRingtone());
|
||||||
|
assertTrue(pref.isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPreferenceChange() throws Exception {
|
||||||
|
Uri sound = Settings.System.DEFAULT_ALARM_ALERT_URI;
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_HIGH);
|
||||||
|
channel.setSound(sound, Notification.AUDIO_ATTRIBUTES_DEFAULT);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
NotificationSoundPreference pref =
|
||||||
|
new NotificationSoundPreference(mContext, mock(AttributeSet.class));
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
mController.onPreferenceChange(pref, Uri.EMPTY);
|
||||||
|
assertEquals(Uri.EMPTY, channel.getSound());
|
||||||
|
assertEquals(Notification.AUDIO_ATTRIBUTES_DEFAULT, channel.getAudioAttributes());
|
||||||
|
verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPreferenceTreeClick_incorrectPref() throws Exception {
|
||||||
|
NotificationSoundPreference pref = mock(NotificationSoundPreference.class);
|
||||||
|
mController.handlePreferenceTreeClick(pref);
|
||||||
|
|
||||||
|
verify(pref, never()).onPrepareRingtonePickerIntent(any());
|
||||||
|
verify(mFragment, never()).startActivityForResult(any(), anyInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPreferenceTreeClick_correctPref() throws Exception {
|
||||||
|
NotificationSoundPreference pref =
|
||||||
|
spy(new NotificationSoundPreference(mContext, mock(AttributeSet.class)));
|
||||||
|
pref.setKey(mController.getPreferenceKey());
|
||||||
|
mController.handlePreferenceTreeClick(pref);
|
||||||
|
|
||||||
|
verify(pref, times(1)).onPrepareRingtonePickerIntent(any());
|
||||||
|
verify(mFragment, times(1)).startActivityForResult(any(), anyInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnActivityResult() {
|
||||||
|
NotificationSoundPreference pref = mock(NotificationSoundPreference.class);
|
||||||
|
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
|
||||||
|
mController.displayPreference(mScreen);
|
||||||
|
|
||||||
|
mController.onActivityResult(SoundPreferenceController.CODE, 1, new Intent("hi"));
|
||||||
|
verify(pref, times(1)).onActivityResult(anyInt(), anyInt(), any());
|
||||||
|
verify(mImportanceListener, times(1)).onImportanceChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHasValidSound() {
|
||||||
|
NotificationChannel channel =
|
||||||
|
new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_HIGH);
|
||||||
|
assertTrue(mController.hasValidSound(channel));
|
||||||
|
|
||||||
|
channel.setSound(Uri.EMPTY, Notification.AUDIO_ATTRIBUTES_DEFAULT);
|
||||||
|
assertFalse(mController.hasValidSound(channel));
|
||||||
|
|
||||||
|
channel.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT);
|
||||||
|
assertFalse(mController.hasValidSound(channel));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,230 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_HIGH;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.os.Vibrator;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
import android.support.v7.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
|
import com.android.settingslib.RestrictedSwitchPreference;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Answers;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.shadows.ShadowApplication;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = Build.VERSION_CODES.O)
|
||||||
|
public class VibrationPreferenceControllerTest {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
@Mock
|
||||||
|
private NotificationBackend mBackend;
|
||||||
|
@Mock
|
||||||
|
private NotificationManager mNm;
|
||||||
|
@Mock
|
||||||
|
Vibrator mVibrator;
|
||||||
|
@Mock
|
||||||
|
private UserManager mUm;
|
||||||
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
|
private PreferenceScreen mScreen;
|
||||||
|
|
||||||
|
private VibrationPreferenceController mController;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
ShadowApplication shadowApplication = ShadowApplication.getInstance();
|
||||||
|
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
|
||||||
|
shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
|
||||||
|
shadowApplication.setSystemService(Context.VIBRATOR_SERVICE, mVibrator);
|
||||||
|
mContext = shadowApplication.getApplicationContext();
|
||||||
|
mController = spy(new VibrationPreferenceController(mContext, mBackend));
|
||||||
|
|
||||||
|
// by default allow vibration
|
||||||
|
when(mVibrator.hasVibrator()).thenReturn(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoCrashIfNoOnResume() throws Exception {
|
||||||
|
mController.isAvailable();
|
||||||
|
mController.updateState(mock(RestrictedSwitchPreference.class));
|
||||||
|
mController.onPreferenceChange(mock(RestrictedSwitchPreference.class), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notSystemDoesNotHave() throws Exception {
|
||||||
|
when(mVibrator.hasVibrator()).thenReturn(false);
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfNotImportant() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_LOW);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfDefaultChannel() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel =
|
||||||
|
new NotificationChannel(DEFAULT_CHANNEL_ID, "", IMPORTANCE_DEFAULT);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_disabledByAdmin() throws Exception {
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn("something");
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
|
||||||
|
RestrictedLockUtils.EnforcedAdmin.class));
|
||||||
|
|
||||||
|
Preference pref = new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertFalse(pref.isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_notConfigurable() throws Exception {
|
||||||
|
String lockedId = "locked";
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
appRow.lockedChannelId = lockedId;
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn(lockedId);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
Preference pref = new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertFalse(pref.isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_configurable() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn("something");
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
Preference pref = new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
assertTrue(pref.isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_vibrateOn() throws Exception {
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.shouldVibrate()).thenReturn(true);
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref =
|
||||||
|
new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
assertTrue(pref.isChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_vibrateOff() throws Exception {
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.shouldVibrate()).thenReturn(false);
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref =
|
||||||
|
new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
assertFalse(pref.isChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPreferenceChange_on() {
|
||||||
|
NotificationChannel channel =
|
||||||
|
new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_DEFAULT);
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref =
|
||||||
|
new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
mController.onPreferenceChange(pref, true);
|
||||||
|
|
||||||
|
assertTrue(channel.shouldVibrate());
|
||||||
|
verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPreferenceChange_off() {
|
||||||
|
NotificationChannel channel =
|
||||||
|
new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_HIGH);
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
|
||||||
|
|
||||||
|
RestrictedSwitchPreference pref =
|
||||||
|
new RestrictedSwitchPreference(RuntimeEnvironment.application);
|
||||||
|
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
|
||||||
|
mController.displayPreference(mScreen);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
mController.onPreferenceChange(pref, false);
|
||||||
|
|
||||||
|
assertFalse(channel.shouldVibrate());
|
||||||
|
verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,326 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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;
|
||||||
|
|
||||||
|
import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_MIN;
|
||||||
|
import static android.app.NotificationManager.VISIBILITY_NO_OVERRIDE;
|
||||||
|
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS;
|
||||||
|
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.Notification;
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.app.admin.DevicePolicyManager;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.UserInfo;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.support.v7.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.internal.widget.LockPatternUtils;
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settings.testutils.shadow.ShadowRestrictionUtils;
|
||||||
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Answers;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.shadows.ShadowApplication;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = Build.VERSION_CODES.O, shadows = {
|
||||||
|
ShadowRestrictionUtils.class,
|
||||||
|
})
|
||||||
|
public class VisibilityPreferenceControllerTest {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
@Mock
|
||||||
|
private NotificationBackend mBackend;
|
||||||
|
@Mock
|
||||||
|
private NotificationManager mNm;
|
||||||
|
@Mock
|
||||||
|
private LockPatternUtils mLockUtils;
|
||||||
|
@Mock
|
||||||
|
private UserManager mUm;
|
||||||
|
@Mock
|
||||||
|
private DevicePolicyManager mDm;
|
||||||
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
|
private PreferenceScreen mScreen;
|
||||||
|
|
||||||
|
private VisibilityPreferenceController mController;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
ShadowApplication shadowApplication = ShadowApplication.getInstance();
|
||||||
|
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
|
||||||
|
shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
|
||||||
|
shadowApplication.setSystemService(Context.DEVICE_POLICY_SERVICE, mDm);
|
||||||
|
mContext = shadowApplication.getApplicationContext();
|
||||||
|
mController = spy(new VisibilityPreferenceController(mContext, mLockUtils, mBackend));
|
||||||
|
|
||||||
|
// by default the lockscreen is secure
|
||||||
|
when(mLockUtils.isSecure(anyInt())).thenReturn(true);
|
||||||
|
// and notifications are visible in redacted form
|
||||||
|
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||||
|
Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1);
|
||||||
|
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||||
|
Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 1);
|
||||||
|
// and not restricted
|
||||||
|
ShadowRestrictionUtils.setRestricted(false);
|
||||||
|
// with no managed profile
|
||||||
|
UserInfo userInfo = new UserInfo();
|
||||||
|
when(mUm.getUserInfo(anyInt())).thenReturn(userInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoCrashIfNoOnResume() throws Exception {
|
||||||
|
mController.isAvailable();
|
||||||
|
mController.updateState(mock(RestrictedDropDownPreference.class));
|
||||||
|
mController.onPreferenceChange(mock(RestrictedDropDownPreference.class), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notSecure() throws Exception {
|
||||||
|
when(mLockUtils.isSecure(anyInt())).thenReturn(false);
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable_notIfNotImportant() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_MIN);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertFalse(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAvailable() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel =
|
||||||
|
new NotificationChannel(DEFAULT_CHANNEL_ID, "", IMPORTANCE_DEFAULT);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
|
||||||
|
channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
assertTrue(mController.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_disabledByAdmin_disableSecure() throws Exception {
|
||||||
|
ShadowRestrictionUtils.setRestricted(true);
|
||||||
|
UserInfo userInfo = new UserInfo(2, "user 2", UserInfo.FLAG_MANAGED_PROFILE);
|
||||||
|
when(mUm.getUserInfo(anyInt())).thenReturn(userInfo);
|
||||||
|
List<ComponentName> components = new ArrayList<>();
|
||||||
|
components.add(new ComponentName("", ""));
|
||||||
|
when(mDm.getActiveAdminsAsUser(anyInt())).thenReturn(components);
|
||||||
|
when(mDm.getKeyguardDisabledFeatures(any(), anyInt()))
|
||||||
|
.thenReturn(KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
|
||||||
|
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn("something");
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
|
||||||
|
RestrictedLockUtils.EnforcedAdmin.class));
|
||||||
|
|
||||||
|
RestrictedDropDownPreference pref = mock(RestrictedDropDownPreference.class);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
verify(pref, times(2)).addRestrictedItem(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_disabledByAdmin_disableUnredacted() throws Exception {
|
||||||
|
ShadowRestrictionUtils.setRestricted(true);
|
||||||
|
UserInfo userInfo = new UserInfo(2, "user 2", UserInfo.FLAG_MANAGED_PROFILE);
|
||||||
|
when(mUm.getUserInfo(anyInt())).thenReturn(userInfo);
|
||||||
|
List<ComponentName> components = new ArrayList<>();
|
||||||
|
components.add(new ComponentName("", ""));
|
||||||
|
when(mDm.getActiveAdminsAsUser(anyInt())).thenReturn(components);
|
||||||
|
when(mDm.getKeyguardDisabledFeatures(any(), anyInt()))
|
||||||
|
.thenReturn(KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
|
||||||
|
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getId()).thenReturn("something");
|
||||||
|
mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
|
||||||
|
RestrictedLockUtils.EnforcedAdmin.class));
|
||||||
|
|
||||||
|
RestrictedDropDownPreference pref = mock(RestrictedDropDownPreference.class);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
verify(pref, times(1)).addRestrictedItem(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_noLockScreenNotificationsGlobally() throws Exception {
|
||||||
|
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||||
|
Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
|
||||||
|
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
RestrictedDropDownPreference pref = mock(RestrictedDropDownPreference.class);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
ArgumentCaptor<String[]> argumentCaptor = ArgumentCaptor.forClass(String[].class);
|
||||||
|
verify(pref, times(1)).setEntryValues(argumentCaptor.capture());
|
||||||
|
assertFalse(Arrays.asList(argumentCaptor.getValue())
|
||||||
|
.contains(VISIBILITY_NO_OVERRIDE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_noPrivateLockScreenNotificationsGlobally() throws Exception {
|
||||||
|
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||||
|
Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
|
||||||
|
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
RestrictedDropDownPreference pref = mock(RestrictedDropDownPreference.class);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
ArgumentCaptor<String[]> argumentCaptor = ArgumentCaptor.forClass(String[].class);
|
||||||
|
verify(pref, times(1)).setEntryValues(argumentCaptor.capture());
|
||||||
|
assertFalse(Arrays.asList(argumentCaptor.getValue())
|
||||||
|
.contains(VISIBILITY_NO_OVERRIDE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_noGlobalRestriction() throws Exception {
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
RestrictedDropDownPreference pref = mock(RestrictedDropDownPreference.class);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
ArgumentCaptor<String[]> argumentCaptor = ArgumentCaptor.forClass(String[].class);
|
||||||
|
verify(pref, times(1)).setEntryValues(argumentCaptor.capture());
|
||||||
|
List<String> values = Arrays.asList(argumentCaptor.getValue());
|
||||||
|
assertEquals(3, values.size());
|
||||||
|
assertTrue(values.contains(String.valueOf(VISIBILITY_NO_OVERRIDE)));
|
||||||
|
assertTrue(values.contains(String.valueOf(Notification.VISIBILITY_PRIVATE)));
|
||||||
|
assertTrue(values.contains(String.valueOf(Notification.VISIBILITY_SECRET)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_noChannelOverride() throws Exception {
|
||||||
|
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||||
|
Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
|
||||||
|
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getLockscreenVisibility()).thenReturn(VISIBILITY_NO_OVERRIDE);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
RestrictedDropDownPreference pref = mock(RestrictedDropDownPreference.class);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
|
||||||
|
verify(pref, times(1)).setValue(argumentCaptor.capture());
|
||||||
|
|
||||||
|
assertEquals(String.valueOf(Notification.VISIBILITY_PRIVATE), argumentCaptor.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateState_channelOverride() throws Exception {
|
||||||
|
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||||
|
Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
|
||||||
|
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = mock(NotificationChannel.class);
|
||||||
|
when(channel.getLockscreenVisibility()).thenReturn(Notification.VISIBILITY_SECRET);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
RestrictedDropDownPreference pref = mock(RestrictedDropDownPreference.class);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
|
||||||
|
verify(pref, times(1)).setValue(argumentCaptor.capture());
|
||||||
|
|
||||||
|
assertEquals(String.valueOf(Notification.VISIBILITY_SECRET), argumentCaptor.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPreferenceChange_noOverride() {
|
||||||
|
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||||
|
Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
|
||||||
|
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("", "", 4);
|
||||||
|
channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
RestrictedDropDownPreference pref = mock(RestrictedDropDownPreference.class);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
mController.onPreferenceChange(pref, String.valueOf(Notification.VISIBILITY_PRIVATE));
|
||||||
|
|
||||||
|
assertEquals(VISIBILITY_NO_OVERRIDE, channel.getLockscreenVisibility());
|
||||||
|
verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPreferenceChange_override() {
|
||||||
|
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||||
|
Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
|
||||||
|
|
||||||
|
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||||
|
NotificationChannel channel = new NotificationChannel("", "", 4);
|
||||||
|
channel.setLockscreenVisibility(VISIBILITY_NO_OVERRIDE);
|
||||||
|
mController.onResume(appRow, channel, null, null);
|
||||||
|
|
||||||
|
RestrictedDropDownPreference pref = mock(RestrictedDropDownPreference.class);
|
||||||
|
mController.updateState(pref);
|
||||||
|
|
||||||
|
mController.onPreferenceChange(pref, String.valueOf(Notification.VISIBILITY_SECRET));
|
||||||
|
|
||||||
|
assertEquals(Notification.VISIBILITY_SECRET, channel.getLockscreenVisibility());
|
||||||
|
verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user