Update design of channel pages.

Test: atest
Bug: 127796543
Change-Id: I4fabeafe2602c341554959303e67bc69c8817a8f
This commit is contained in:
Julia Reynolds
2019-03-07 10:44:01 -05:00
parent 7d7b09abeb
commit 4253be9191
19 changed files with 1257 additions and 95 deletions

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2019 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.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/back">
<shape android:shape="oval">
<solid
android:color="@android:color/transparent" />
<size
android:height="48dp"
android:width="48dp"/>
<stroke android:width="1dp"
android:color="@color/notification_alert_color"/>
</shape>
</item>
<item
android:id="@+id/fore"
android:gravity="center">
<vector
android:height="24dp"
android:width="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="@color/notification_alert_color"
android:pathData="M7.58 4.08L6.15 2.65C3.75 4.48 2.17 7.3 2.03 10.5h2c.15-2.65 1.51-4.97 3.55-6.42zm12.39 6.42h2c-.15-3.2-1.73-6.02-4.12-7.85l-1.42 1.43c2.02 1.45 3.39 3.77 3.54 6.42zM18 11c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2v-5zm-6 11c.14 0 .27-.01.4-.04.65-.14 1.18-.58 1.44-1.18.1-.24.15-.5.15-.78h-4c.01 1.1.9 2 2.01 2z"/>
</vector>
</item>
</layer-list>

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2019 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.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/back">
<shape android:shape="oval">
<solid
android:color="@android:color/transparent" />
<size
android:height="48dp"
android:width="48dp"/>
<stroke android:width="1dp"
android:color="@color/notification_block_color"/>
</shape>
</item>
<item
android:id="@+id/fore"
android:gravity="center">
<vector
android:height="24dp"
android:width="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="@color/notification_block_color"
android:pathData="M12.0,2.0C6.48,2.0 2.0,6.48 2.0,12.0s4.48,10.0 10.0,10.0 10.0,-4.48 10.0,-10.0S17.52,2.0 12.0,2.0zM4.0,12.0c0.0,-4.42 3.58,-8.0 8.0,-8.0 1.85,0.0 3.5,0.63 4.9,1.69L5.69,16.9C4.63,15.55 4.0,13.85 4.0,12.0zm8.0,8.0c-1.85,0.0 -3.55,-0.63 -4.9,-1.69L18.31,7.1C19.37,8.45 20.0,10.15 20.0,12.0c0.0,4.42 -3.58,8.0 -8.0,8.0z"/>
</vector>
</item>
</layer-list>

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2019 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.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/back">
<shape android:shape="oval">
<solid
android:color="@android:color/transparent" />
<size
android:height="48dp"
android:width="48dp"/>
<stroke android:width="1dp"
android:color="@color/notification_silence_color"/>
</shape>
</item>
<item
android:id="@+id/fore"
android:gravity="center">
<vector
android:height="24dp"
android:width="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="@color/notification_silence_color"
android:pathData="M20 18.69L7.84 6.14 5.27 3.49 4 4.76l2.8 2.8v.01c-.52.99-.8 2.16-.8 3.42v5l-2 2v1h13.73l2 2L21 19.72l-1-1.03zM12 22c1.11 0 2-.89 2-2h-4c0 1.11.89 2 2 2zm6-7.32V11c0-3.08-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68c-.15.03-.29.08-.42.12-.1.03-.2.07-.3.11h-.01c-.01 0-.01 0-.02.01-.23.09-.46.2-.68.31 0 0-.01 0-.01.01L18 14.68z" />
</vector>
</item>
</layer-list>

View File

@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2019 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/app_entities_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/block"
android:layout_width="0dp"
android:layout_weight="33.33"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginTop="16dp"
android:orientation="vertical"
android:gravity="center">
<ImageButton
android:id="@+id/block_icon"
android:layout_width="@dimen/notification_importance_toggle_size"
android:layout_height="@dimen/notification_importance_toggle_size"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_notification_block"
android:contentDescription="@string/notification_block_title" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/notification_block_title"
android:layout_marginTop="@dimen/notification_importance_toggle_marginTop"
android:layout_marginBottom="@dimen/notification_importance_toggle_marginBottom"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead" />
</LinearLayout>
<LinearLayout
android:id="@+id/silence"
android:layout_width="0dp"
android:layout_weight="33.33"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginTop="16dp"
android:orientation="vertical"
android:gravity="center">
<ImageButton
android:id="@+id/silence_icon"
android:layout_width="@dimen/notification_importance_toggle_size"
android:layout_height="@dimen/notification_importance_toggle_size"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_notification_silence"
android:contentDescription="@string/notification_silence_title" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/notification_silence_title"
android:layout_marginTop="@dimen/notification_importance_toggle_marginTop"
android:layout_marginBottom="@dimen/notification_importance_toggle_marginBottom"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead" />
</LinearLayout>
<LinearLayout
android:id="@+id/alert"
android:layout_width="0dp"
android:layout_weight="33.33"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginTop="16dp"
android:orientation="vertical"
android:gravity="center">
<ImageButton
android:id="@+id/alert_icon"
android:layout_width="@dimen/notification_importance_toggle_size"
android:layout_height="@dimen/notification_importance_toggle_size"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_notification_alert"
android:contentDescription="@string/notification_alert_title" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/notification_alert_title"
android:layout_marginTop="@dimen/notification_importance_toggle_marginTop"
android:layout_marginBottom="@dimen/notification_importance_toggle_marginBottom"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead" />
</LinearLayout>
</LinearLayout>

View File

@@ -124,6 +124,11 @@
<color name="face_anim_particle_color_4">#fffdd835</color> <!-- Material Yellow 600 -->
<color name="face_anim_particle_error">#ff9e9e9e</color> <!-- Material Gray 500 -->
<!-- notification settings -->
<color name="notification_block_color">#ffff0000</color>
<color name="notification_silence_color">#fbbc04</color>
<color name="notification_alert_color">#30a751</color>
<!-- launcher icon color -->
<color name="icon_launcher_setting_color">@*android:color/accent_device_default_light</color>

View File

@@ -68,6 +68,9 @@
<dimen name="notification_app_icon_size">64dp</dimen>
<dimen name="notification_app_icon_badge_size">20dp</dimen>
<dimen name="notification_app_icon_badge_margin">4dp</dimen>
<dimen name="notification_importance_toggle_size">48dp</dimen>
<dimen name="notification_importance_toggle_marginTop">8dp</dimen>
<dimen name="notification_importance_toggle_marginBottom">16dp</dimen>
<dimen name="zen_schedule_rule_checkbox_padding">7dp</dimen>
<dimen name="zen_schedule_day_margin">17dp</dimen>

View File

@@ -7771,7 +7771,7 @@
summary on the channel page-->
<!-- [CHAR LIMIT=100] Notification Importance title: min importance level title -->
<string name="notification_importance_min_title">Low</string>
<string name="notification_importance_min_title">Minimize</string>
<!-- [CHAR LIMIT=100] Notification Importance title: low importance level title -->
<string name="notification_importance_low_title">Medium</string>
@@ -7780,7 +7780,16 @@
<string name="notification_importance_default_title">High</string>
<!-- [CHAR LIMIT=100] Notification Importance title: high importance level title -->
<string name="notification_importance_high_title">Urgent</string>
<string name="notification_importance_high_title">Pop on screen</string>
<!-- [CHAR LIMIT=100] Notification Importance title -->
<string name="notification_block_title">Block</string>
<!-- [CHAR LIMIT=100] Notification Importance title -->
<string name="notification_silence_title">Show silently</string>
<!-- [CHAR LIMIT=100] Notification Importance title -->
<string name="notification_alert_title">Alert</string>
<!-- [CHAR LIMIT=40] Notification importance title. This setting controls how notifications in older apps may alert the user (eg, sound, visual, vibrate). -->
<string name="allow_interruption">Allow interruptions</string>

View File

@@ -25,11 +25,6 @@
android:order="1"
android:layout="@layout/settings_entity_header" />
<com.android.settingslib.widget.LayoutPreference
android:key="block"
android:order="2"
android:layout="@layout/styled_switch_bar" />
<!-- Importance toggle -->
<com.android.settingslib.RestrictedSwitchPreference
android:key="allow_sound"
@@ -38,10 +33,23 @@
android:summary="@string/allow_interruption_summary" />
<!-- Importance -->
<com.android.settings.RestrictedListPreference
<com.android.settings.notification.ImportancePreference
android:key="importance"
android:order="10"
android:title="@string/notification_importance_title" />
android:order="4"
android:title="@string/notification_importance_title"
settings:allowDividerBelow="true"/>
<com.android.settingslib.RestrictedSwitchPreference
android:key="min_importance"
android:order="5"
settings:allowDividerAbove="true"
android:title="@string/notification_importance_min_title"/>
<com.android.settingslib.RestrictedSwitchPreference
android:key="high_importance"
android:order="6"
settings:allowDividerAbove="true"
android:title="@string/notification_importance_high_title"/>
<PreferenceCategory
android:key="channel_advanced"
@@ -113,6 +121,7 @@
<com.android.settings.notification.NotificationFooterPreference
android:key="block_desc"
android:order="110"/>
android:order="110"
settings:allowDividerAbove="false"/>
</PreferenceScreen>

View File

@@ -152,6 +152,10 @@ public class AppNotificationSettings extends NotificationSettingsBase {
context, mImportanceListener, mBackend));
mControllers.add(new ImportancePreferenceController(
context, mImportanceListener, mBackend));
mControllers.add(new MinImportancePreferenceController(
context, mImportanceListener, mBackend));
mControllers.add(new HighImportancePreferenceController(
context, mImportanceListener, mBackend));
mControllers.add(new SoundPreferenceController(context, this,
mImportanceListener, mBackend));
mControllers.add(new LightsPreferenceController(context, mBackend));

View File

@@ -94,9 +94,12 @@ public class ChannelNotificationSettings extends NotificationSettingsBase {
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
mControllers = new ArrayList<>();
mControllers.add(new HeaderPreferenceController(context, this));
mControllers.add(new BlockPreferenceController(context, mImportanceListener, mBackend));
mControllers.add(new ImportancePreferenceController(
context, mImportanceListener, mBackend));
mControllers.add(new MinImportancePreferenceController(
context, mImportanceListener, mBackend));
mControllers.add(new HighImportancePreferenceController(
context, mImportanceListener, mBackend));
mControllers.add(new AllowSoundPreferenceController(
context, mImportanceListener, mBackend));
mControllers.add(new SoundPreferenceController(context, this,

View File

@@ -0,0 +1,84 @@
/*
* Copyright (C) 2019 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 android.app.NotificationChannel;
import android.content.Context;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.RestrictedSwitchPreference;
import androidx.preference.Preference;
public class HighImportancePreferenceController extends NotificationPreferenceController
implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
private static final String KEY_IMPORTANCE = "high_importance";
private NotificationSettingsBase.ImportanceListener mImportanceListener;
public HighImportancePreferenceController(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;
}
if (mChannel == null) {
return false;
}
if (isDefaultChannel()) {
return false;
}
return mChannel.getImportance() >= IMPORTANCE_DEFAULT;
}
@Override
public void updateState(Preference preference) {
if (mAppRow!= null && mChannel != null) {
preference.setEnabled(mAdmin == null && isChannelConfigurable());
RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
pref.setChecked(mChannel.getImportance() >= IMPORTANCE_HIGH);
}
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (mChannel != null) {
final boolean checked = (boolean) newValue;
mChannel.setImportance(checked ? IMPORTANCE_HIGH : IMPORTANCE_DEFAULT);
mChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
saveChannel();
mImportanceListener.onImportanceChanged();
}
return true;
}
}

View File

@@ -0,0 +1,172 @@
/*
* Copyright (C) 2019 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 android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.LayerDrawable;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageButton;
import com.android.settingslib.R;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
public class ImportancePreference extends Preference {
boolean mIsBlockable = true;
boolean mIsConfigurable = true;
int mImportance;
ImageButton blockButton;
ImageButton silenceButton;
ImageButton alertButton;
ArrayMap<ImageButton, Integer> mImageButtons = new ArrayMap<>();
Context mContext;
public ImportancePreference(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
public ImportancePreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
public ImportancePreference(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ImportancePreference(Context context) {
super(context);
init(context);
}
private void init(Context context) {
mContext = context;
setLayoutResource(R.layout.notif_importance_preference);
}
public void setImportance(int importance) {
mImportance = importance;
}
public void setBlockable(boolean blockable) {
mIsBlockable = blockable;
}
public void setConfigurable(boolean configurable) {
mIsConfigurable = configurable;
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
View blockView = holder.itemView.findViewById(R.id.block);
View alertView = holder.itemView.findViewById(R.id.alert);
View silenceView = holder.itemView.findViewById(R.id.silence);
if (!mIsBlockable) {
blockView.setVisibility(View.GONE);
if (mImportance == IMPORTANCE_NONE) {
mImportance = IMPORTANCE_LOW;
callChangeListener(IMPORTANCE_LOW);
}
}
blockButton = blockView.findViewById(R.id.block_icon);
silenceButton = silenceView.findViewById(R.id.silence_icon);
alertButton = alertView.findViewById(R.id.alert_icon);
mImageButtons.put(blockButton, mContext.getColor(R.color.notification_block_color));
mImageButtons.put(silenceButton, mContext.getColor(R.color.notification_silence_color));
mImageButtons.put(alertButton, mContext.getColor(R.color.notification_alert_color));
switch (mImportance) {
case IMPORTANCE_NONE:
colorizeImageButton(blockButton.getId());
if (!mIsConfigurable) {
alertView.setVisibility(View.GONE);
silenceView.setVisibility(View.GONE);
}
break;
case IMPORTANCE_MIN:
case IMPORTANCE_LOW:
colorizeImageButton(silenceButton.getId());
if (!mIsConfigurable) {
alertView.setVisibility(View.GONE);
blockView.setVisibility(View.GONE);
}
break;
case IMPORTANCE_HIGH:
default:
colorizeImageButton(alertButton.getId());
if (!mIsConfigurable) {
blockView.setVisibility(View.GONE);
silenceView.setVisibility(View.GONE);
}
break;
}
blockButton.setOnClickListener(v -> {
callChangeListener(IMPORTANCE_NONE);
colorizeImageButton(blockButton.getId());
});
silenceButton.setOnClickListener(v -> {
callChangeListener(IMPORTANCE_LOW);
colorizeImageButton(silenceButton.getId());
});
alertButton.setOnClickListener(v -> {
callChangeListener(IMPORTANCE_DEFAULT);
colorizeImageButton(alertButton.getId());
});
}
private void colorizeImageButton(int buttonId) {
if (mImageButtons != null) {
for (int i = 0; i < mImageButtons.size(); i++) {
final ImageButton imageButton = mImageButtons.keyAt(i);
final int color = mImageButtons.valueAt(i);
if (imageButton != null) {
LayerDrawable drawable = (LayerDrawable) imageButton.getDrawable();
Drawable foreground = drawable.findDrawableByLayerId(R.id.fore);
GradientDrawable background =
(GradientDrawable) drawable.findDrawableByLayerId(R.id.back);
if (buttonId == imageButton.getId()) {
foreground.setTint(Color.WHITE);
background.setColor(color);
} else {
foreground.setTint(color);
background.setColor(Color.TRANSPARENT);
}
}
}
}
}
}

View File

@@ -18,21 +18,15 @@ package com.android.settings.notification;
import static android.app.NotificationChannel.USER_LOCKED_SOUND;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.media.RingtoneManager;
import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.RestrictedListPreference;
import com.android.settings.core.PreferenceControllerMixin;
import androidx.preference.Preference;
public class ImportancePreferenceController extends NotificationPreferenceController
implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
@@ -53,44 +47,33 @@ public class ImportancePreferenceController extends NotificationPreferenceContro
@Override
public boolean isAvailable() {
if (!super.isAvailable()) {
if (mAppRow == null) {
return false;
}
if (mChannel == null) {
return false;
}
return !isDefaultChannel();
if (isDefaultChannel()) {
return false;
}
return true;
}
@Override
public void updateState(Preference preference) {
if (mAppRow!= null && mChannel != null) {
preference.setEnabled(mAdmin == null && isChannelConfigurable());
preference.setSummary(getImportanceSummary(mChannel));
int importances = IMPORTANCE_HIGH - IMPORTANCE_MIN + 1;
CharSequence[] entries = new CharSequence[importances];
CharSequence[] values = new CharSequence[importances];
int index = 0;
for (int i = IMPORTANCE_HIGH; i >= IMPORTANCE_MIN; i--) {
NotificationChannel channel = new NotificationChannel("", "", i);
entries[index] = getImportanceSummary(channel);
values[index] = String.valueOf(i);
index++;
}
RestrictedListPreference pref = (RestrictedListPreference) preference;
pref.setEntries(entries);
pref.setEntryValues(values);
pref.setValue(String.valueOf(mChannel.getImportance()));
ImportancePreference pref = (ImportancePreference) preference;
pref.setBlockable(isChannelBlockable());
pref.setConfigurable(isChannelConfigurable());
pref.setImportance(mChannel.getImportance());
}
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (mChannel != null) {
final int importance = Integer.parseInt((String) newValue);
final int importance = (Integer) newValue;
// If you are moving from an importance level without sound to one with sound,
// but the sound you had selected was "Silence",
@@ -111,39 +94,4 @@ public class ImportancePreferenceController extends NotificationPreferenceContro
}
return true;
}
protected String getImportanceSummary(NotificationChannel channel) {
String summary = "";
int importance = channel.getImportance();
switch (importance) {
case IMPORTANCE_UNSPECIFIED:
summary = mContext.getString(R.string.notification_importance_unspecified);
break;
case NotificationManager.IMPORTANCE_MIN:
summary = mContext.getString(R.string.notification_importance_min);
break;
case NotificationManager.IMPORTANCE_LOW:
summary = mContext.getString(R.string.notification_importance_low);
break;
case NotificationManager.IMPORTANCE_DEFAULT:
if (SoundPreferenceController.hasValidSound(channel)) {
summary = mContext.getString(R.string.notification_importance_default);
} else {
summary = mContext.getString(R.string.notification_importance_low);
}
break;
case NotificationManager.IMPORTANCE_HIGH:
case NotificationManager.IMPORTANCE_MAX:
if (SoundPreferenceController.hasValidSound(channel)) {
summary = mContext.getString(R.string.notification_importance_high);
} else {
summary = mContext.getString(R.string.notification_importance_high_silent);
}
break;
default:
return "";
}
return summary;
}
}

View File

@@ -0,0 +1,84 @@
/*
* 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_MIN;
import android.app.NotificationChannel;
import android.content.Context;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.RestrictedSwitchPreference;
import androidx.preference.Preference;
public class MinImportancePreferenceController extends NotificationPreferenceController
implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
private static final String KEY_IMPORTANCE = "min_importance";
private NotificationSettingsBase.ImportanceListener mImportanceListener;
public MinImportancePreferenceController(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;
}
if (mChannel == null) {
return false;
}
if (isDefaultChannel()) {
return false;
}
return mChannel.getImportance() <= IMPORTANCE_LOW;
}
@Override
public void updateState(Preference preference) {
if (mAppRow!= null && mChannel != null) {
preference.setEnabled(mAdmin == null && isChannelConfigurable());
RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
pref.setChecked(mChannel.getImportance() == IMPORTANCE_MIN);
}
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (mChannel != null) {
final boolean checked = (boolean) newValue;
mChannel.setImportance(checked ? IMPORTANCE_MIN : IMPORTANCE_LOW);
mChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
saveChannel();
mImportanceListener.onImportanceChanged();
}
return true;
}
}

View File

@@ -110,6 +110,26 @@ public class BlockPreferenceControllerTest {
assertFalse(mController.isAvailable());
}
@Test
public void testIsAvailable_notIfChannelNonDefault() {
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_ifChannelDefault() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
when(channel.getId()).thenReturn(DEFAULT_CHANNEL_ID);
mController.onResume(appRow, channel, null, null);
assertTrue(mController.isAvailable());
}
@Test
public void testIsAvailable_notIfGroupNotBlockable() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();

View File

@@ -0,0 +1,199 @@
/*
* 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_NONE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
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.UserManager;
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.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadows.ShadowApplication;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
@RunWith(RobolectricTestRunner.class)
public class HighImportancePreferenceControllerTest {
private Context mContext;
@Mock
private NotificationManager mNm;
@Mock
private NotificationBackend mBackend;
@Mock
private NotificationSettingsBase.ImportanceListener mImportanceListener;
@Mock
private UserManager mUm;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private PreferenceScreen mScreen;
private HighImportancePreferenceController 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 = RuntimeEnvironment.application;
mController = spy(new HighImportancePreferenceController(
mContext, mImportanceListener, mBackend));
}
@Test
public void testNoCrashIfNoOnResume() {
mController.isAvailable();
mController.updateState(mock(Preference.class));
}
@Test
public void testIsAvailable_notIfNull() {
mController.onResume(null, null, null, null);
assertFalse(mController.isAvailable());
}
@Test
public void testIsAvailable_ifAppBlocked() {
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() {
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() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
when(channel.getId()).thenReturn(DEFAULT_CHANNEL_ID);
mController.onResume(appRow, channel, null, null);
assertFalse(mController.isAvailable());
}
@Test
public void testIsAvailable() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_DEFAULT);
mController.onResume(appRow, channel, null, null);
assertTrue(mController.isAvailable());
}
@Test
public void testUpdateState_disabledByAdmin() {
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
RestrictedLockUtils.EnforcedAdmin.class));
Preference pref = new RestrictedSwitchPreference(mContext, null);
mController.updateState(pref);
assertFalse(pref.isEnabled());
}
@Test
public void testUpdateState_notConfigurable() {
String lockedId = "locked";
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.lockedChannelId = lockedId;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getId()).thenReturn(lockedId);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null);
Preference pref = new RestrictedSwitchPreference(mContext, null);
mController.updateState(pref);
assertFalse(pref.isEnabled());
}
@Test
public void testUpdateState_high() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null);
RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
mController.updateState(pref);
assertTrue(pref.isChecked());
}
@Test
public void testUpdateState_default() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT);
mController.onResume(appRow, channel, null, null);
RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
mController.updateState(pref);
assertFalse(pref.isChecked());
}
@Test
public void onPreferenceChange() {
NotificationChannel channel =
new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_HIGH);
mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext, null);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
mController.displayPreference(mScreen);
mController.updateState(pref);
mController.onPreferenceChange(pref, false);
assertEquals(IMPORTANCE_DEFAULT, channel.getImportance());
verify(mImportanceListener, times(1)).onImportanceChanged();
}
}

View File

@@ -27,8 +27,11 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
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;
@@ -36,12 +39,10 @@ import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.UserManager;
import android.text.TextUtils;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.RestrictedListPreference;
import com.android.settingslib.RestrictedLockUtils;
import org.junit.Before;
@@ -95,20 +96,20 @@ public class ImportancePreferenceControllerTest {
}
@Test
public void testIsAvailable_notIfAppBlocked() {
public void testIsAvailable_ifAppBlocked() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.banned = true;
mController.onResume(appRow, mock(NotificationChannel.class), null, null);
assertFalse(mController.isAvailable());
assertTrue(mController.isAvailable());
}
@Test
public void testIsAvailable_notIfChannelBlocked() {
public void testIsAvailable_evenIfChannelBlocked() {
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());
assertTrue(mController.isAvailable());
}
@Test
@@ -137,11 +138,10 @@ public class ImportancePreferenceControllerTest {
mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
RestrictedLockUtils.EnforcedAdmin.class));
Preference pref = new RestrictedListPreference(mContext, null);
Preference pref = new ImportancePreference(mContext, null);
mController.updateState(pref);
assertFalse(pref.isEnabled());
assertFalse(TextUtils.isEmpty(pref.getSummary()));
}
@Test
@@ -154,11 +154,10 @@ public class ImportancePreferenceControllerTest {
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null);
Preference pref = new RestrictedListPreference(mContext, null);
Preference pref = new ImportancePreference(mContext, null);
mController.updateState(pref);
assertFalse(pref.isEnabled());
assertFalse(TextUtils.isEmpty(pref.getSummary()));
}
@Test
@@ -167,11 +166,12 @@ public class ImportancePreferenceControllerTest {
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null);
Preference pref = new RestrictedListPreference(mContext, null);
ImportancePreference pref = mock(ImportancePreference.class);
mController.updateState(pref);
assertTrue(pref.isEnabled());
assertFalse(TextUtils.isEmpty(pref.getSummary()));
verify(pref, times(1)).setConfigurable(anyBoolean());
verify(pref, times(1)).setBlockable(anyBoolean());
verify(pref, times(1)).setImportance(IMPORTANCE_HIGH);
}
@Test
@@ -181,13 +181,12 @@ public class ImportancePreferenceControllerTest {
channel.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT);
mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
RestrictedListPreference pref = new RestrictedListPreference(mContext, null);
ImportancePreference pref = new ImportancePreference(mContext, null);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
mController.displayPreference(mScreen);
mController.updateState(pref);
pref.setValue(String.valueOf(IMPORTANCE_HIGH));
mController.onPreferenceChange(pref, pref.getValue());
mController.onPreferenceChange(pref, IMPORTANCE_HIGH);
assertEquals(IMPORTANCE_HIGH, channel.getImportance());
assertNotNull(channel.getSound());
@@ -200,13 +199,12 @@ public class ImportancePreferenceControllerTest {
channel.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT);
mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
RestrictedListPreference pref = new RestrictedListPreference(mContext, null);
ImportancePreference pref = new ImportancePreference(mContext, null);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
mController.displayPreference(mScreen);
mController.updateState(pref);
pref.setValue(String.valueOf(IMPORTANCE_LOW));
mController.onPreferenceChange(pref, pref.getValue());
mController.onPreferenceChange(pref, IMPORTANCE_LOW);
assertEquals(IMPORTANCE_LOW, channel.getImportance());
assertNull(channel.getSound());

View File

@@ -0,0 +1,192 @@
/*
* Copyright (C) 2019 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 com.google.common.truth.Truth.assertThat;
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 android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.LayerDrawable;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.Switch;
import com.android.settings.R;
import com.android.settingslib.RestrictedLockUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
@RunWith(RobolectricTestRunner.class)
public class ImportancePreferenceTest {
private Context mContext;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
}
private GradientDrawable getBackground(ImageButton button) {
return (GradientDrawable) ((LayerDrawable) button.getDrawable())
.findDrawableByLayerId(R.id.back);
}
@Test
public void createNewPreference_shouldSetLayout() {
final ImportancePreference preference = new ImportancePreference(mContext);
assertThat(preference.getLayoutResource()).isEqualTo(
R.layout.notif_importance_preference);
}
@Test
public void onBindViewHolder_hideBlockNonBlockable() {
final ImportancePreference preference = new ImportancePreference(mContext);
final LayoutInflater inflater = LayoutInflater.from(mContext);
final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
inflater.inflate(R.layout.notif_importance_preference, null));
preference.setBlockable(false);
preference.setConfigurable(true);
preference.setImportance(IMPORTANCE_DEFAULT);
preference.onBindViewHolder(holder);
assertThat(holder.itemView.findViewById(R.id.block).getVisibility()).isEqualTo(View.GONE);
}
@Test
public void onBindViewHolder_hideNonSelectedNonConfigurable() {
final ImportancePreference preference = new ImportancePreference(mContext);
final LayoutInflater inflater = LayoutInflater.from(mContext);
PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
inflater.inflate(R.layout.notif_importance_preference, null));
preference.setBlockable(true);
preference.setConfigurable(false);
preference.setImportance(IMPORTANCE_DEFAULT);
preference.onBindViewHolder(holder);
assertThat(holder.itemView.findViewById(R.id.block).getVisibility()).isEqualTo(View.GONE);
assertThat(holder.itemView.findViewById(R.id.silence).getVisibility()).isEqualTo(View.GONE);
assertThat(holder.itemView.findViewById(R.id.alert).getVisibility())
.isEqualTo(View.VISIBLE);
// other button
preference.setImportance(IMPORTANCE_LOW);
holder = PreferenceViewHolder.createInstanceForTests(
inflater.inflate(R.layout.notif_importance_preference, null));
preference.onBindViewHolder(holder);
assertThat(holder.itemView.findViewById(R.id.block).getVisibility()).isEqualTo(View.GONE);
assertThat(holder.itemView.findViewById(R.id.silence).getVisibility())
.isEqualTo(View.VISIBLE);
assertThat(holder.itemView.findViewById(R.id.alert).getVisibility())
.isEqualTo(View.GONE);
}
@Test
public void onBindViewHolder_selectButton() {
final ImportancePreference preference = new ImportancePreference(mContext);
final LayoutInflater inflater = LayoutInflater.from(mContext);
final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
inflater.inflate(R.layout.notif_importance_preference, null));
preference.setBlockable(true);
preference.setConfigurable(true);
preference.setImportance(IMPORTANCE_DEFAULT);
ImageButton blockButton = (ImageButton) holder.findViewById(R.id.block_icon);
ImageButton silenceButton = (ImageButton) holder.findViewById(R.id.silence_icon);
ImageButton alertButton = (ImageButton) holder.findViewById(R.id.alert_icon);
preference.onBindViewHolder(holder);
// selected has full color background. others are transparent
assertThat(getBackground(alertButton).getColor().getColors()[0]).isNotEqualTo(
Color.TRANSPARENT);
assertThat(getBackground(silenceButton).getColor().getColors()[0]).isEqualTo(
Color.TRANSPARENT);
assertThat(getBackground(blockButton).getColor().getColors()[0]).isEqualTo(
Color.TRANSPARENT);
}
@Test
public void onClick_changesUICallsListener() {
final ImportancePreference preference = spy(new ImportancePreference(mContext));
final LayoutInflater inflater = LayoutInflater.from(mContext);
final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
inflater.inflate(R.layout.notif_importance_preference, null));
preference.setBlockable(true);
preference.setConfigurable(true);
preference.setImportance(IMPORTANCE_DEFAULT);
preference.onBindViewHolder(holder);
ImageButton blockButton = (ImageButton) holder.findViewById(R.id.block_icon);
ImageButton silenceButton = (ImageButton) holder.findViewById(R.id.silence_icon);
ImageButton alertButton = (ImageButton) holder.findViewById(R.id.alert_icon);
silenceButton.callOnClick();
// selected has full color background. others are transparent
assertThat(getBackground(silenceButton).getColor().getColors()[0]).isNotEqualTo(
Color.TRANSPARENT);
assertThat(getBackground(alertButton).getColor().getColors()[0]).isEqualTo(
Color.TRANSPARENT);
assertThat(getBackground(blockButton).getColor().getColors()[0]).isEqualTo(
Color.TRANSPARENT);
verify(preference, times(1)).callChangeListener(IMPORTANCE_LOW);
}
@Test
public void onBindViewHolder_allButtonsVisible() {
final ImportancePreference preference = new ImportancePreference(mContext);
final LayoutInflater inflater = LayoutInflater.from(mContext);
final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
inflater.inflate(R.layout.notif_importance_preference, null));
preference.setBlockable(true);
preference.setConfigurable(true);
preference.onBindViewHolder(holder);
assertThat(holder.itemView.findViewById(R.id.block).getVisibility())
.isEqualTo(View.VISIBLE);
assertThat(holder.itemView.findViewById(R.id.silence).getVisibility())
.isEqualTo(View.VISIBLE);
assertThat(holder.itemView.findViewById(R.id.alert).getVisibility())
.isEqualTo(View.VISIBLE);
}
}

View File

@@ -0,0 +1,199 @@
/*
* 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_MIN;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
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.UserManager;
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.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadows.ShadowApplication;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
@RunWith(RobolectricTestRunner.class)
public class MinImportancePreferenceControllerTest {
private Context mContext;
@Mock
private NotificationManager mNm;
@Mock
private NotificationBackend mBackend;
@Mock
private NotificationSettingsBase.ImportanceListener mImportanceListener;
@Mock
private UserManager mUm;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private PreferenceScreen mScreen;
private MinImportancePreferenceController 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 = RuntimeEnvironment.application;
mController = spy(new MinImportancePreferenceController(
mContext, mImportanceListener, mBackend));
}
@Test
public void testNoCrashIfNoOnResume() {
mController.isAvailable();
mController.updateState(mock(Preference.class));
}
@Test
public void testIsAvailable_notIfNull() {
mController.onResume(null, null, null, null);
assertFalse(mController.isAvailable());
}
@Test
public void testIsAvailable_ifAppBlocked() {
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() {
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() {
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() {
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() {
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
RestrictedLockUtils.EnforcedAdmin.class));
Preference pref = new RestrictedSwitchPreference(mContext, null);
mController.updateState(pref);
assertFalse(pref.isEnabled());
}
@Test
public void testUpdateState_notConfigurable() {
String lockedId = "locked";
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.lockedChannelId = lockedId;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getId()).thenReturn(lockedId);
when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
mController.onResume(appRow, channel, null, null);
Preference pref = new RestrictedSwitchPreference(mContext, null);
mController.updateState(pref);
assertFalse(pref.isEnabled());
}
@Test
public void testUpdateState_min() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_MIN);
mController.onResume(appRow, channel, null, null);
RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
mController.updateState(pref);
assertTrue(pref.isChecked());
}
@Test
public void testUpdateState_low() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_LOW);
mController.onResume(appRow, channel, null, null);
RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
mController.updateState(pref);
assertFalse(pref.isChecked());
}
@Test
public void onPreferenceChange() {
NotificationChannel channel =
new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_LOW);
mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext, null);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
mController.displayPreference(mScreen);
mController.updateState(pref);
mController.onPreferenceChange(pref, true);
assertEquals(IMPORTANCE_MIN, channel.getImportance());
verify(mImportanceListener, times(1)).onImportanceChanged();
}
}