diff --git a/res/layout/notif_priority_conversation_preference.xml b/res/layout/notif_priority_conversation_preference.xml new file mode 100644 index 00000000000..981cd693cfc --- /dev/null +++ b/res/layout/notif_priority_conversation_preference.xml @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index d01f8be555a..a480ff656fd 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -8415,6 +8415,12 @@ Let the app make sound, vibrate, and/or pop notifications on screen + + Priority + + + Shows at top of conversation section and appears as a bubble. + diff --git a/res/xml/conversation_notification_settings.xml b/res/xml/conversation_notification_settings.xml index d0db428f5bc..be1c980a05c 100644 --- a/res/xml/conversation_notification_settings.xml +++ b/res/xml/conversation_notification_settings.xml @@ -26,19 +26,11 @@ settings:allowDividerBelow="true"/> - - - - + settings:allowDividerAbove="true" + settings:allowDividerBelow="true"/> - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/src/com/android/settings/notification/app/BubblePreferenceController.java b/src/com/android/settings/notification/app/BubblePreferenceController.java index 879f17af9e7..d33ba7e1aa3 100644 --- a/src/com/android/settings/notification/app/BubblePreferenceController.java +++ b/src/com/android/settings/notification/app/BubblePreferenceController.java @@ -68,7 +68,7 @@ public class BubblePreferenceController extends NotificationPreferenceController if (isDefaultChannel()) { return true; } else { - return mAppRow != null && mAppRow.allowBubbles; + return mAppRow != null; } } return true; diff --git a/src/com/android/settings/notification/app/ConversationListSettings.java b/src/com/android/settings/notification/app/ConversationListSettings.java index aaeaa950c8b..1eb997a0db9 100644 --- a/src/com/android/settings/notification/app/ConversationListSettings.java +++ b/src/com/android/settings/notification/app/ConversationListSettings.java @@ -18,15 +18,8 @@ package com.android.settings.notification.app; import android.app.settings.SettingsEnums; import android.content.Context; -import android.os.Bundle; -import android.text.TextUtils; import android.util.Log; -import androidx.preference.Preference; -import androidx.preference.PreferenceGroup; -import androidx.preference.PreferenceScreen; - -import com.android.internal.widget.LockPatternUtils; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.notification.NotificationBackend; @@ -60,7 +53,7 @@ public class ConversationListSettings extends DashboardFragment { @Override protected List createPreferenceControllers(Context context) { mControllers = new ArrayList<>(); - mControllers.add(new ImportantConversationsPreferenceController(context, mBackend)); + mControllers.add(new PriorityConversationsPreferenceController(context, mBackend)); mControllers.add(new AllConversationsPreferenceController(context, mBackend)); return new ArrayList<>(mControllers); } diff --git a/src/com/android/settings/notification/app/ConversationNotificationSettings.java b/src/com/android/settings/notification/app/ConversationNotificationSettings.java index c5a8e6ee100..210af2086e6 100644 --- a/src/com/android/settings/notification/app/ConversationNotificationSettings.java +++ b/src/com/android/settings/notification/app/ConversationNotificationSettings.java @@ -79,18 +79,13 @@ public class ConversationNotificationSettings extends NotificationSettings { protected List createPreferenceControllers(Context context) { mControllers = new ArrayList<>(); mControllers.add(new ConversationHeaderPreferenceController(context, this)); - mControllers.add(new ConversationImportantPreferenceController( + mControllers.add(new ConversationPriorityPreferenceController( context, mBackend, mDependentFieldListener)); - mControllers.add(new DefaultImportancePreferenceController( - context, mDependentFieldListener, mBackend)); - mControllers.add(new AddToHomeScreenPreferenceController(context, mBackend)); mControllers.add(new HighImportancePreferenceController( context, mDependentFieldListener, mBackend)); mControllers.add(new SoundPreferenceController(context, this, mDependentFieldListener, mBackend)); mControllers.add(new VibrationPreferenceController(context, mBackend)); - mControllers.add(new AppLinkPreferenceController(context)); - mControllers.add(new DescriptionPreferenceController(context)); mControllers.add(new VisibilityPreferenceController(context, new LockPatternUtils(context), mBackend)); mControllers.add(new LightsPreferenceController(context, mBackend)); diff --git a/src/com/android/settings/notification/app/ConversationPriorityPreference.java b/src/com/android/settings/notification/app/ConversationPriorityPreference.java new file mode 100644 index 00000000000..ff1dc6c5d91 --- /dev/null +++ b/src/com/android/settings/notification/app/ConversationPriorityPreference.java @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.notification.app; + +import static android.app.NotificationManager.IMPORTANCE_DEFAULT; +import static android.app.NotificationManager.IMPORTANCE_LOW; +import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; +import static android.view.View.GONE; +import static android.view.View.VISIBLE; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.graphics.drawable.Drawable; +import android.transition.AutoTransition; +import android.transition.TransitionManager; +import android.util.AttributeSet; +import android.util.Pair; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.preference.Preference; +import androidx.preference.PreferenceViewHolder; + +import com.android.settings.Utils; +import com.android.settingslib.R; + +public class ConversationPriorityPreference extends Preference { + + private boolean mIsConfigurable = true; + private int mImportance; + private int mOriginalImportance; + private boolean mPriorityConversation; + private View mSilenceButton; + private View mAlertButton; + private View mPriorityButton; + private Context mContext; + Drawable selectedBackground; + Drawable unselectedBackground; + private static final int BUTTON_ANIM_TIME_MS = 100; + + public ConversationPriorityPreference(Context context, AttributeSet attrs, + int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(context); + } + + public ConversationPriorityPreference(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context); + } + + public ConversationPriorityPreference(Context context, AttributeSet attrs) { + super(context, attrs); + init(context); + } + + public ConversationPriorityPreference(Context context) { + super(context); + init(context); + } + + private void init(Context context) { + mContext = context; + selectedBackground = mContext.getDrawable(R.drawable.button_border_selected); + unselectedBackground = mContext.getDrawable(R.drawable.button_border_unselected); + setLayoutResource(R.layout.notif_priority_conversation_preference); + } + + public void setImportance(int importance) { + mImportance = importance; + } + + public void setConfigurable(boolean configurable) { + mIsConfigurable = configurable; + } + + public void setPriorityConversation(boolean priorityConversation) { + mPriorityConversation = priorityConversation; + } + + public void setOriginalImportance(int importance) { + mOriginalImportance = importance; + } + + @Override + public void onBindViewHolder(final PreferenceViewHolder holder) { + super.onBindViewHolder(holder); + holder.itemView.setClickable(false); + + mSilenceButton = holder.findViewById(R.id.silence); + mAlertButton = holder.findViewById(R.id.alert); + mPriorityButton = holder.findViewById(R.id.priority_group); + + if (!mIsConfigurable) { + mSilenceButton.setEnabled(false); + mAlertButton.setEnabled(false); + mPriorityButton.setEnabled(false); + } + + updateToggles((ViewGroup) holder.itemView, mImportance, mPriorityConversation, + false); + + mSilenceButton.setOnClickListener(v -> { + callChangeListener(new Pair(IMPORTANCE_LOW, false)); + updateToggles((ViewGroup) holder.itemView, IMPORTANCE_LOW, false, true); + }); + mAlertButton.setOnClickListener(v -> { + int newImportance = Math.max(mOriginalImportance, IMPORTANCE_DEFAULT); + callChangeListener(new Pair(newImportance, false)); + updateToggles((ViewGroup) holder.itemView, newImportance, false, true); + }); + mPriorityButton.setOnClickListener(v -> { + int newImportance = Math.max(mOriginalImportance, IMPORTANCE_DEFAULT); + callChangeListener(new Pair(newImportance, true)); + updateToggles((ViewGroup) holder.itemView, newImportance, true, true); + }); + } + + private ColorStateList getAccentTint() { + return Utils.getColorAccent(getContext()); + } + + private ColorStateList getRegularTint() { + return Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary); + } + + void updateToggles(ViewGroup parent, int importance, boolean isPriority, + boolean fromUser) { + if (fromUser) { + AutoTransition transition = new AutoTransition(); + transition.setDuration(BUTTON_ANIM_TIME_MS); + TransitionManager.beginDelayedTransition(parent, transition); + } + + ColorStateList colorAccent = getAccentTint(); + ColorStateList colorNormal = getRegularTint(); + ImageView silenceIcon = parent.findViewById(R.id.silence_icon); + TextView silenceLabel = parent.findViewById(R.id.silence_label); + TextView silenceSummary = parent.findViewById(R.id.silence_summary); + ImageView alertIcon = parent.findViewById(R.id.alert_icon); + TextView alertLabel = parent.findViewById(R.id.alert_label); + TextView alertSummary = parent.findViewById(R.id.alert_summary); + ImageView priorityIcon = parent.findViewById(R.id.priority_icon); + TextView priorityLabel = parent.findViewById(R.id.priority_label); + TextView prioritySummary = parent.findViewById(R.id.priority_summary); + + if (importance <= IMPORTANCE_LOW && importance > IMPORTANCE_UNSPECIFIED) { + alertSummary.setVisibility(GONE); + alertIcon.setImageTintList(colorNormal); + alertLabel.setTextColor(colorNormal); + + prioritySummary.setVisibility(GONE); + priorityIcon.setImageTintList(colorNormal); + priorityLabel.setTextColor(colorNormal); + + silenceIcon.setImageTintList(colorAccent); + silenceLabel.setTextColor(colorAccent); + silenceSummary.setVisibility(VISIBLE); + + mAlertButton.setBackground(unselectedBackground); + mPriorityButton.setBackground(unselectedBackground); + mSilenceButton.setBackground(selectedBackground); + // a11y service won't always read the newly appearing text in the right order if the + // selection happens too soon (readback happens on a different thread as layout). post + // the selection to make that conflict less likely + parent.post(() -> mSilenceButton.setSelected(true)); + } else { + if (isPriority) { + alertSummary.setVisibility(GONE); + alertIcon.setImageTintList(colorNormal); + alertLabel.setTextColor(colorNormal); + + prioritySummary.setVisibility(VISIBLE); + priorityIcon.setImageTintList(colorAccent); + priorityLabel.setTextColor(colorAccent); + + silenceIcon.setImageTintList(colorNormal); + silenceLabel.setTextColor(colorNormal); + silenceSummary.setVisibility(GONE); + + mAlertButton.setBackground(unselectedBackground); + mPriorityButton.setBackground(selectedBackground); + mSilenceButton.setBackground(unselectedBackground); + parent.post(() -> mPriorityButton.setSelected(true)); + } else { + alertSummary.setVisibility(VISIBLE); + alertIcon.setImageTintList(colorAccent); + alertLabel.setTextColor(colorAccent); + + prioritySummary.setVisibility(GONE); + priorityIcon.setImageTintList(colorNormal); + priorityLabel.setTextColor(colorNormal); + + silenceIcon.setImageTintList(colorNormal); + silenceLabel.setTextColor(colorNormal); + silenceSummary.setVisibility(GONE); + + mAlertButton.setBackground(selectedBackground); + mPriorityButton.setBackground(unselectedBackground); + mSilenceButton.setBackground(unselectedBackground); + parent.post(() -> mAlertButton.setSelected(true)); + } + } + } +} diff --git a/src/com/android/settings/notification/app/ConversationImportantPreferenceController.java b/src/com/android/settings/notification/app/ConversationPriorityPreferenceController.java similarity index 63% rename from src/com/android/settings/notification/app/ConversationImportantPreferenceController.java rename to src/com/android/settings/notification/app/ConversationPriorityPreferenceController.java index 0b1ee16e8a5..e59f277699f 100644 --- a/src/com/android/settings/notification/app/ConversationImportantPreferenceController.java +++ b/src/com/android/settings/notification/app/ConversationPriorityPreferenceController.java @@ -16,25 +16,22 @@ package com.android.settings.notification.app; -import static android.provider.Settings.Secure.BUBBLE_IMPORTANT_CONVERSATIONS; - import android.content.Context; -import android.provider.Settings; +import android.util.Pair; import androidx.preference.Preference; import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.notification.NotificationBackend; -import com.android.settingslib.RestrictedSwitchPreference; -public class ConversationImportantPreferenceController extends NotificationPreferenceController +public class ConversationPriorityPreferenceController extends NotificationPreferenceController implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener { - private static final String TAG = "ConvoImpPC"; - private static final String KEY = "important"; + private static final String TAG = "ConvoPriorityPC"; + private static final String KEY = "priority"; private final NotificationSettings.DependentFieldListener mDependentFieldListener; - public ConversationImportantPreferenceController(Context context, + public ConversationPriorityPreferenceController(Context context, NotificationBackend backend, NotificationSettings.DependentFieldListener listener) { super(context, backend); mDependentFieldListener = listener; @@ -58,10 +55,12 @@ public class ConversationImportantPreferenceController extends NotificationPrefe public void updateState(Preference preference) { if (mAppRow != null) { - RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference; - pref.setDisabledByAdmin(mAdmin); - pref.setChecked(mChannel.isImportantConversation()); - pref.setEnabled(!pref.isDisabledByAdmin()); + preference.setEnabled(mAdmin == null && !mChannel.isImportanceLockedByOEM()); + ConversationPriorityPreference pref = (ConversationPriorityPreference) preference; + pref.setConfigurable(!mChannel.isImportanceLockedByOEM()); + pref.setImportance(mChannel.getImportance()); + pref.setOriginalImportance(mChannel.getOriginalImportance()); + pref.setPriorityConversation(mChannel.isImportantConversation()); } } @@ -70,19 +69,21 @@ public class ConversationImportantPreferenceController extends NotificationPrefe if (mChannel == null) { return false; } - final boolean value = (Boolean) newValue; - mChannel.setImportantConversation(value); - if (value && bubbleImportantConversations()) { + boolean wasPriorityConversation = mChannel.isImportantConversation(); + + final Pair value = (Pair) newValue; + mChannel.setImportance(value.first); + mChannel.setImportantConversation(value.second); + + if (value.second) { mChannel.setAllowBubbles(true); + } else if (wasPriorityConversation) { + mChannel.setAllowBubbles(false); } + mDependentFieldListener.onFieldValueChanged(); saveChannel(); return true; } - - private boolean bubbleImportantConversations() { - return Settings.Secure.getInt(mContext.getContentResolver(), - BUBBLE_IMPORTANT_CONVERSATIONS, 1) == 1; - } } diff --git a/src/com/android/settings/notification/app/DefaultImportancePreferenceController.java b/src/com/android/settings/notification/app/DefaultImportancePreferenceController.java deleted file mode 100644 index 616d64a3b46..00000000000 --- a/src/com/android/settings/notification/app/DefaultImportancePreferenceController.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.notification.app; - -import static android.app.NotificationManager.IMPORTANCE_DEFAULT; -import static android.app.NotificationManager.IMPORTANCE_LOW; - -import android.app.NotificationChannel; -import android.content.Context; - -import androidx.preference.Preference; - -import com.android.settings.core.PreferenceControllerMixin; -import com.android.settings.notification.NotificationBackend; -import com.android.settingslib.RestrictedSwitchPreference; - -public class DefaultImportancePreferenceController extends NotificationPreferenceController - implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener { - - private static final String KEY = "alerting"; - private NotificationSettings.DependentFieldListener mDependentFieldListener; - - public DefaultImportancePreferenceController(Context context, - NotificationSettings.DependentFieldListener dependentFieldListener, - NotificationBackend backend) { - super(context, backend); - mDependentFieldListener = dependentFieldListener; - } - - @Override - public String getPreferenceKey() { - return KEY; - } - - @Override - public boolean isAvailable() { - if (!super.isAvailable()) { - return false; - } - if (mChannel == null) { - return false; - } - if (isDefaultChannel()) { - return false; - } - return true; - } - - @Override - public void updateState(Preference preference) { - if (mAppRow != null && mChannel != null) { - preference.setEnabled(mAdmin == null && !mChannel.isImportanceLockedByOEM()); - - RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference; - pref.setChecked(mChannel.getImportance() >= IMPORTANCE_DEFAULT); - } - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - if (mChannel != null) { - final boolean checked = (boolean) newValue; - - mChannel.setImportance(checked ? IMPORTANCE_DEFAULT : IMPORTANCE_LOW); - mChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE); - saveChannel(); - mDependentFieldListener.onFieldValueChanged(); - } - return true; - } -} diff --git a/src/com/android/settings/notification/app/ImportantConversationsPreferenceController.java b/src/com/android/settings/notification/app/PriorityConversationsPreferenceController.java similarity index 94% rename from src/com/android/settings/notification/app/ImportantConversationsPreferenceController.java rename to src/com/android/settings/notification/app/PriorityConversationsPreferenceController.java index 2089d9d3bbe..ed12d7dd7ed 100644 --- a/src/com/android/settings/notification/app/ImportantConversationsPreferenceController.java +++ b/src/com/android/settings/notification/app/PriorityConversationsPreferenceController.java @@ -28,14 +28,14 @@ import com.android.settings.notification.NotificationBackend; import java.util.Collections; import java.util.List; -public class ImportantConversationsPreferenceController extends +public class PriorityConversationsPreferenceController extends ConversationListPreferenceController { private static final String KEY = "important_conversations"; private static final String LIST_KEY = "important_conversations_list"; private List mConversations; - public ImportantConversationsPreferenceController(Context context, + public PriorityConversationsPreferenceController(Context context, NotificationBackend backend) { super(context, backend); } diff --git a/tests/robotests/src/com/android/settings/notification/app/BubblePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/BubblePreferenceControllerTest.java index 404625efde2..c2c45cb1707 100644 --- a/tests/robotests/src/com/android/settings/notification/app/BubblePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/app/BubblePreferenceControllerTest.java @@ -122,7 +122,7 @@ public class BubblePreferenceControllerTest { } @Test - public void testIsAvailable_channel_notIfAppOff() { + public void testIsAvailable_channel_yesIfAppOff() { Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON); NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); appRow.allowBubbles = false; @@ -130,7 +130,7 @@ public class BubblePreferenceControllerTest { when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH); mController.onResume(appRow, channel, null, null, null, null); - assertFalse(mController.isAvailable()); + assertTrue(mController.isAvailable()); } @Test @@ -199,18 +199,6 @@ public class BubblePreferenceControllerTest { assertTrue(mController.isAvailable()); } - @Test - public void testIsAvailable_channelAppOff() { - NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); - appRow.allowBubbles = false; - NotificationChannel channel = mock(NotificationChannel.class); - when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH); - mController.onResume(appRow, channel, null, null, null, null); - Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON); - - assertFalse(mController.isAvailable()); - } - @Test public void testUpdateState_disabledByAdmin() { NotificationChannel channel = mock(NotificationChannel.class); diff --git a/tests/robotests/src/com/android/settings/notification/app/ConversationImportantPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/ConversationImportantPreferenceControllerTest.java deleted file mode 100644 index 42b785976bd..00000000000 --- a/tests/robotests/src/com/android/settings/notification/app/ConversationImportantPreferenceControllerTest.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.notification.app; - -import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID; -import static android.app.NotificationManager.IMPORTANCE_DEFAULT; -import static android.app.NotificationManager.IMPORTANCE_HIGH; -import static android.provider.Settings.Secure.BUBBLE_IMPORTANT_CONVERSATIONS; - -import static org.junit.Assert.assertFalse; -import static org.junit.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.UserManager; -import android.provider.Settings; - -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; - -import com.android.settings.notification.NotificationBackend; -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; - -@RunWith(RobolectricTestRunner.class) -public class ConversationImportantPreferenceControllerTest { - - 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 NotificationSettings.DependentFieldListener mDependentFieldListener; - - private ConversationImportantPreferenceController 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 ConversationImportantPreferenceController( - mContext, mBackend, mDependentFieldListener)); - } - - @Test - public void testNoCrashIfNoOnResume() { - mController.isAvailable(); - mController.updateState(mock(Preference.class)); - mController.onPreferenceChange(mock(Preference.class), true); - } - - @Test - public void testIsAvailable_notChannelNull() { - NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); - mController.onResume(appRow, null, null, null, null, null); - assertFalse(mController.isAvailable()); - } - - @Test - public void testIsAvailable() { - NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); - NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT); - mController.onResume(appRow, channel, null, null, null, null); - assertTrue(mController.isAvailable()); - } - - @Test - public void testUpdateState_disabledByAdmin() { - NotificationChannel channel = mock(NotificationChannel.class); - when(channel.getId()).thenReturn("something"); - mController.onResume(new NotificationBackend.AppRow(), channel, null, null, null, mock( - RestrictedLockUtils.EnforcedAdmin.class)); - - Preference pref = new RestrictedSwitchPreference(RuntimeEnvironment.application); - mController.updateState(pref); - - assertFalse(pref.isEnabled()); - } - - @Test - public void testUpdateState() { - NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); - NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT); - channel.setImportantConversation(true); - mController.onResume(appRow, channel, null, null, null, null); - - RestrictedSwitchPreference pref = - new RestrictedSwitchPreference(RuntimeEnvironment.application); - mController.updateState(pref); - - assertTrue(pref.isChecked()); - - channel.setImportantConversation(false); - mController.onResume(appRow, channel, null, null, null, null); - mController.updateState(pref); - assertFalse(pref.isChecked()); - } - - @Test - public void testOnPreferenceChange_on() { - Settings.Secure.putInt(mContext.getContentResolver(), - BUBBLE_IMPORTANT_CONVERSATIONS, 0); - NotificationChannel channel = - new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_DEFAULT); - channel.setImportantConversation(false); - channel.setAllowBubbles(false); - mController.onResume(new NotificationBackend.AppRow(), channel, null, null, null, null); - - RestrictedSwitchPreference pref = - new RestrictedSwitchPreference(RuntimeEnvironment.application); - mController.updateState(pref); - - mController.onPreferenceChange(pref, true); - - assertTrue(channel.isImportantConversation()); - assertFalse(channel.canBubble()); - verify(mBackend, times(1)).updateChannel(any(), anyInt(), any()); - verify(mDependentFieldListener, times(1)).onFieldValueChanged(); - } - - @Test - public void testOnPreferenceChange_on_bubble() { - Settings.Secure.putInt(mContext.getContentResolver(), - BUBBLE_IMPORTANT_CONVERSATIONS, 1); - NotificationChannel channel = - new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_DEFAULT); - channel.setImportantConversation(false); - channel.setAllowBubbles(false); - mController.onResume(new NotificationBackend.AppRow(), channel, null, null, null, null); - - RestrictedSwitchPreference pref = - new RestrictedSwitchPreference(RuntimeEnvironment.application); - mController.updateState(pref); - - mController.onPreferenceChange(pref, true); - - assertTrue(channel.isImportantConversation()); - assertTrue(channel.canBubble()); - verify(mBackend, times(1)).updateChannel(any(), anyInt(), any()); - verify(mDependentFieldListener).onFieldValueChanged(); - } - - @Test - public void testOnPreferenceChange_off() { - Settings.Secure.putInt(mContext.getContentResolver(), - BUBBLE_IMPORTANT_CONVERSATIONS, 1); - NotificationChannel channel = - new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_HIGH); - channel.setImportantConversation(true); - channel.setAllowBubbles(false); - mController.onResume(new NotificationBackend.AppRow(), channel, null, 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(channel.isImportantConversation()); - assertFalse(channel.canBubble()); - verify(mBackend, times(1)).updateChannel(any(), anyInt(), any()); - verify(mDependentFieldListener, times(1)).onFieldValueChanged(); - } -} diff --git a/tests/robotests/src/com/android/settings/notification/app/DefaultImportancePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/ConversationPriorityPreferenceControllerTest.java similarity index 58% rename from tests/robotests/src/com/android/settings/notification/app/DefaultImportancePreferenceControllerTest.java rename to tests/robotests/src/com/android/settings/notification/app/ConversationPriorityPreferenceControllerTest.java index 5b853226c69..d74715c9da4 100644 --- a/tests/robotests/src/com/android/settings/notification/app/DefaultImportancePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/app/ConversationPriorityPreferenceControllerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,28 +20,32 @@ 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 org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +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; import android.app.NotificationChannel; import android.app.NotificationManager; import android.content.Context; import android.os.UserManager; +import android.util.Pair; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.notification.NotificationBackend; import com.android.settingslib.RestrictedLockUtils; -import com.android.settingslib.RestrictedSwitchPreference; import org.junit.Before; import org.junit.Test; @@ -54,21 +58,21 @@ import org.robolectric.RuntimeEnvironment; import org.robolectric.shadows.ShadowApplication; @RunWith(RobolectricTestRunner.class) -public class DefaultImportancePreferenceControllerTest { +public class ConversationPriorityPreferenceControllerTest { private Context mContext; @Mock - private NotificationManager mNm; - @Mock private NotificationBackend mBackend; @Mock - private NotificationSettings.DependentFieldListener mDependentFieldListener; + private NotificationManager mNm; @Mock private UserManager mUm; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private PreferenceScreen mScreen; + @Mock + private NotificationSettings.DependentFieldListener mDependentFieldListener; - private DefaultImportancePreferenceController mController; + private ConversationPriorityPreferenceController mController; @Before public void setUp() { @@ -77,54 +81,28 @@ public class DefaultImportancePreferenceControllerTest { shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm); shadowApplication.setSystemService(Context.USER_SERVICE, mUm); mContext = RuntimeEnvironment.application; - mController = spy(new DefaultImportancePreferenceController( - mContext, mDependentFieldListener, mBackend)); + mController = spy(new ConversationPriorityPreferenceController( + mContext, mBackend, mDependentFieldListener)); } @Test public void testNoCrashIfNoOnResume() { mController.isAvailable(); mController.updateState(mock(Preference.class)); + mController.onPreferenceChange(mock(Preference.class), true); } @Test - public void testIsAvailable_notIfNull() { - mController.onResume(null, null, null, null, null, null); - assertFalse(mController.isAvailable()); - } - - @Test - public void testIsAvailable_ifAppBlocked() { + public void testIsAvailable_notChannelNull() { NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); - appRow.banned = true; - mController.onResume(appRow, mock(NotificationChannel.class), null, null, 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, 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, null, null); + mController.onResume(appRow, null, null, null, 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); + NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT); mController.onResume(appRow, channel, null, null, null, null); assertTrue(mController.isAvailable()); } @@ -136,7 +114,7 @@ public class DefaultImportancePreferenceControllerTest { mController.onResume(new NotificationBackend.AppRow(), channel, null, null, null, mock( RestrictedLockUtils.EnforcedAdmin.class)); - Preference pref = new RestrictedSwitchPreference(mContext, null); + Preference pref = new ConversationPriorityPreference(mContext, null); mController.updateState(pref); assertFalse(pref.isEnabled()); @@ -150,7 +128,7 @@ public class DefaultImportancePreferenceControllerTest { when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH); mController.onResume(appRow, channel, null, null, null, null); - Preference pref = new RestrictedSwitchPreference(mContext, null); + Preference pref = new ConversationPriorityPreference(mContext, null); mController.updateState(pref); assertFalse(pref.isEnabled()); @@ -165,7 +143,7 @@ public class DefaultImportancePreferenceControllerTest { when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH); mController.onResume(appRow, channel, null, null, null, null); - Preference pref = new RestrictedSwitchPreference(mContext, null); + Preference pref = new ConversationPriorityPreference(mContext, null); mController.updateState(pref); assertTrue(pref.isEnabled()); @@ -180,67 +158,120 @@ public class DefaultImportancePreferenceControllerTest { when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH); mController.onResume(appRow, channel, null, null, null, null); - Preference pref = new RestrictedSwitchPreference(mContext, null); + Preference pref = new ConversationPriorityPreference(mContext, null); mController.updateState(pref); assertTrue(pref.isEnabled()); } @Test - public void testUpdateState_default() { + public void testUpdateState() { NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); - NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT); + NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_HIGH); + channel.setImportantConversation(true); + channel.setOriginalImportance(IMPORTANCE_DEFAULT); mController.onResume(appRow, channel, null, null, null, null); - RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext); + ConversationPriorityPreference pref = mock(ConversationPriorityPreference.class); mController.updateState(pref); - assertTrue(pref.isChecked()); + verify(pref, times(1)).setConfigurable(anyBoolean()); + verify(pref, times(1)).setImportance(IMPORTANCE_HIGH); + verify(pref, times(1)).setOriginalImportance(IMPORTANCE_DEFAULT); + verify(pref, times(1)).setPriorityConversation(true); } @Test - public void testUpdateState_low() { - NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); - NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_LOW); - mController.onResume(appRow, channel, null, null, null, null); - - RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext); - mController.updateState(pref); - - assertFalse(pref.isChecked()); - } - - @Test - public void onPreferenceChange_onToOff() { - NotificationChannel channel = - new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_HIGH); - mController.onResume(new NotificationBackend.AppRow(), channel, null, null, 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_LOW, channel.getImportance()); - verify(mDependentFieldListener, times(1)).onFieldValueChanged(); - } - - @Test - public void onPreferenceChange_offToOn() { + public void testImportanceLowToImportant() { NotificationChannel channel = new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_LOW); mController.onResume(new NotificationBackend.AppRow(), channel, null, null, null, null); - RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext, null); + ConversationPriorityPreference pref = new ConversationPriorityPreference(mContext, null); when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref); mController.displayPreference(mScreen); mController.updateState(pref); - mController.onPreferenceChange(pref, true); + mController.onPreferenceChange(pref, new Pair(IMPORTANCE_HIGH, true)); + + assertEquals(IMPORTANCE_HIGH, channel.getImportance()); + assertTrue(channel.canBubble()); + assertTrue(channel.isImportantConversation()); + } + @Test + public void testImportanceLowToDefault() { + NotificationChannel channel = + new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_LOW); + channel.setAllowBubbles(false); + mController.onResume(new NotificationBackend.AppRow(), channel, null, null, null, null); + + ConversationPriorityPreference pref = new ConversationPriorityPreference(mContext, null); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref); + mController.displayPreference(mScreen); + mController.updateState(pref); + + mController.onPreferenceChange(pref, new Pair(IMPORTANCE_HIGH, false)); + + assertEquals(IMPORTANCE_HIGH, channel.getImportance()); + assertFalse(channel.canBubble()); + assertFalse(channel.isImportantConversation()); + } + + @Test + public void testImportanceDefaultToLow() { + NotificationChannel channel = + new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_DEFAULT); + channel.setAllowBubbles(false); + mController.onResume(new NotificationBackend.AppRow(), channel, null, null, null, null); + + ConversationPriorityPreference pref = new ConversationPriorityPreference(mContext, null); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref); + mController.displayPreference(mScreen); + mController.updateState(pref); + + mController.onPreferenceChange(pref, new Pair(IMPORTANCE_LOW, false)); + + assertEquals(IMPORTANCE_LOW, channel.getImportance()); + assertFalse(channel.canBubble()); + assertFalse(channel.isImportantConversation()); + } + + @Test + public void testImportanceLowToDefault_bubblesMaintained() { + NotificationChannel channel = + new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_LOW); + channel.setAllowBubbles(true); + mController.onResume(new NotificationBackend.AppRow(), channel, null, null, null, null); + + ConversationPriorityPreference pref = new ConversationPriorityPreference(mContext, null); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref); + mController.displayPreference(mScreen); + mController.updateState(pref); + + mController.onPreferenceChange(pref, new Pair(IMPORTANCE_DEFAULT, false)); assertEquals(IMPORTANCE_DEFAULT, channel.getImportance()); - verify(mDependentFieldListener, times(1)).onFieldValueChanged(); + assertTrue(channel.canBubble()); + assertFalse(channel.isImportantConversation()); + } + + @Test + public void testImportancePriorityToDefault() { + NotificationChannel channel = + new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_HIGH); + channel.setAllowBubbles(true); + channel.setImportantConversation(true); + mController.onResume(new NotificationBackend.AppRow(), channel, null, null, null, null); + + ConversationPriorityPreference pref = new ConversationPriorityPreference(mContext, null); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref); + mController.displayPreference(mScreen); + mController.updateState(pref); + + mController.onPreferenceChange(pref, new Pair(IMPORTANCE_HIGH, false)); + + assertEquals(IMPORTANCE_HIGH, channel.getImportance()); + assertFalse(channel.canBubble()); + assertFalse(channel.isImportantConversation()); } } diff --git a/tests/robotests/src/com/android/settings/notification/app/ConversationPriorityPreferenceTest.java b/tests/robotests/src/com/android/settings/notification/app/ConversationPriorityPreferenceTest.java new file mode 100644 index 00000000000..12e1f35c767 --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/app/ConversationPriorityPreferenceTest.java @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.notification.app; + +import static android.app.NotificationManager.IMPORTANCE_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.drawable.Drawable; +import android.util.Pair; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; + +import androidx.preference.PreferenceViewHolder; + +import com.android.settings.R; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class ConversationPriorityPreferenceTest { + + private Context mContext; + + @Before + public void setUp() { + mContext = RuntimeEnvironment.application; + } + + @Test + public void createNewPreference_shouldSetLayout() { + final ConversationPriorityPreference preference = + new ConversationPriorityPreference(mContext); + assertThat(preference.getLayoutResource()).isEqualTo( + R.layout.notif_priority_conversation_preference); + } + + @Test + public void onBindViewHolder_nonConfigurable() { + final ConversationPriorityPreference preference = + new ConversationPriorityPreference(mContext); + final LayoutInflater inflater = LayoutInflater.from(mContext); + PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests( + inflater.inflate(preference.getLayoutResource(), null)); + Drawable unselected = mock(Drawable.class); + Drawable selected = mock(Drawable.class); + preference.selectedBackground = selected; + preference.unselectedBackground = unselected; + + preference.setConfigurable(false); + preference.setImportance(IMPORTANCE_DEFAULT); + preference.setPriorityConversation(true); + preference.onBindViewHolder(holder); + + assertThat(holder.itemView.findViewById(R.id.silence).isEnabled()).isFalse(); + assertThat(holder.itemView.findViewById(R.id.priority_group).isEnabled()).isFalse(); + assertThat(holder.itemView.findViewById(R.id.alert).isEnabled()).isFalse(); + + assertThat(holder.itemView.findViewById(R.id.priority_group).getBackground()) + .isEqualTo(selected); + assertThat(holder.itemView.findViewById(R.id.alert).getBackground()).isEqualTo(unselected); + assertThat(holder.itemView.findViewById(R.id.silence).getBackground()) + .isEqualTo(unselected); + + // other button + preference.setPriorityConversation(false); + holder = PreferenceViewHolder.createInstanceForTests( + inflater.inflate(preference.getLayoutResource(), null)); + preference.onBindViewHolder(holder); + + assertThat(holder.itemView.findViewById(R.id.alert).getBackground()).isEqualTo(selected); + assertThat(holder.itemView.findViewById(R.id.silence).getBackground()) + .isEqualTo(unselected); + assertThat(holder.itemView.findViewById(R.id.priority_group).getBackground()) + .isEqualTo(unselected); + + // other other button + preference.setImportance(IMPORTANCE_LOW); + holder = PreferenceViewHolder.createInstanceForTests( + inflater.inflate(preference.getLayoutResource(), null)); + preference.onBindViewHolder(holder); + + assertThat(holder.itemView.findViewById(R.id.priority_group).getBackground()) + .isEqualTo(unselected); + assertThat(holder.itemView.findViewById(R.id.alert).getBackground()).isEqualTo(unselected); + assertThat(holder.itemView.findViewById(R.id.silence).getBackground()).isEqualTo(selected); + } + + @Test + public void onBindViewHolder_selectButtonAndText() { + final ConversationPriorityPreference preference = + new ConversationPriorityPreference(mContext); + final LayoutInflater inflater = LayoutInflater.from(mContext); + final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests( + inflater.inflate(preference.getLayoutResource(), null)); + Drawable unselected = mock(Drawable.class); + Drawable selected = mock(Drawable.class); + preference.selectedBackground = selected; + preference.unselectedBackground = unselected; + + preference.setConfigurable(true); + preference.setImportance(IMPORTANCE_LOW); + preference.setPriorityConversation(true); + + preference.onBindViewHolder(holder); + + assertThat(holder.itemView.findViewById(R.id.priority_group).getBackground()) + .isEqualTo(unselected); + assertThat(holder.itemView.findViewById(R.id.alert).getBackground()).isEqualTo(unselected); + assertThat(holder.itemView.findViewById(R.id.silence).getBackground()) + .isEqualTo(selected); + assertThat(holder.itemView.findViewById(R.id.silence_summary).getVisibility()) + .isEqualTo(View.VISIBLE); + } + + @Test + public void onClick_changesUICallsListener() { + final ConversationPriorityPreference preference = + spy(new ConversationPriorityPreference(mContext)); + final LayoutInflater inflater = LayoutInflater.from(mContext); + final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests( + inflater.inflate(preference.getLayoutResource(), null)); + Drawable unselected = mock(Drawable.class); + Drawable selected = mock(Drawable.class); + preference.selectedBackground = selected; + preference.unselectedBackground = unselected; + + preference.setConfigurable(true); + preference.setImportance(IMPORTANCE_DEFAULT); + preference.setPriorityConversation(true); + preference.setOriginalImportance(IMPORTANCE_DEFAULT); + preference.onBindViewHolder(holder); + + View silenceButton = holder.itemView.findViewById(R.id.silence); + + silenceButton.callOnClick(); + + assertThat(holder.itemView.findViewById(R.id.alert).getBackground()).isEqualTo(unselected); + assertThat(holder.itemView.findViewById(R.id.priority_group).getBackground()) + .isEqualTo(unselected); + assertThat(holder.itemView.findViewById(R.id.silence).getBackground()) + .isEqualTo(selected); + + verify(preference, times(1)).callChangeListener(new Pair(IMPORTANCE_LOW, false)); + } +}