1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.settings.notification;
18
19import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
20import static android.app.NotificationManager.IMPORTANCE_HIGH;
21import static android.app.NotificationManager.IMPORTANCE_LOW;
22import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
23import static junit.framework.Assert.assertFalse;
24import static junit.framework.Assert.assertTrue;
25import static org.junit.Assert.assertEquals;
26import static org.mockito.ArgumentMatchers.any;
27import static org.mockito.ArgumentMatchers.anyInt;
28import static org.mockito.Mockito.mock;
29import static org.mockito.Mockito.spy;
30import static org.mockito.Mockito.times;
31import static org.mockito.Mockito.verify;
32import static org.mockito.Mockito.when;
33
34import android.app.NotificationChannel;
35import android.app.NotificationManager;
36import android.content.Context;
37import android.os.UserManager;
38import android.support.v7.preference.Preference;
39import android.support.v7.preference.PreferenceScreen;
40
41import com.android.settings.testutils.SettingsRobolectricTestRunner;
42import com.android.settingslib.RestrictedLockUtils;
43import com.android.settingslib.RestrictedSwitchPreference;
44
45import org.junit.Before;
46import org.junit.Test;
47import org.junit.runner.RunWith;
48import org.mockito.Answers;
49import org.mockito.Mock;
50import org.mockito.MockitoAnnotations;
51import org.robolectric.RuntimeEnvironment;
52import org.robolectric.shadows.ShadowApplication;
53
54@RunWith(SettingsRobolectricTestRunner.class)
55public class AllowSoundPreferenceControllerTest {
56
57    private Context mContext;
58    @Mock
59    private NotificationBackend mBackend;
60    @Mock
61    private NotificationManager mNm;
62    @Mock
63    private UserManager mUm;
64    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
65    private PreferenceScreen mScreen;
66
67    @Mock
68    private NotificationSettingsBase.ImportanceListener mImportanceListener;
69
70    private AllowSoundPreferenceController mController;
71
72    @Before
73    public void setUp() {
74        MockitoAnnotations.initMocks(this);
75        ShadowApplication shadowApplication = ShadowApplication.getInstance();
76        shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
77        shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
78        mContext = RuntimeEnvironment.application;
79        mController =
80                spy(new AllowSoundPreferenceController(mContext, mImportanceListener, mBackend));
81    }
82
83    @Test
84    public void testNoCrashIfNoOnResume() throws Exception {
85        mController.isAvailable();
86        mController.updateState(mock(RestrictedSwitchPreference.class));
87        mController.onPreferenceChange(mock(RestrictedSwitchPreference.class), true);
88    }
89
90    @Test
91    public void testIsAvailable_notIfNull() throws Exception {
92        mController.onResume(null, mock(NotificationChannel.class), null, null);
93        assertFalse(mController.isAvailable());
94
95        mController.onResume(mock(NotificationBackend.AppRow.class), null, null, null);
96        assertFalse(mController.isAvailable());
97    }
98
99    @Test
100    public void testIsAvailable_notIfAppBlocked() throws Exception {
101        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
102        appRow.banned = true;
103        mController.onResume(appRow, mock(NotificationChannel.class), null, null);
104        assertFalse(mController.isAvailable());
105    }
106
107    @Test
108    public void testIsAvailable_notIfAppCreatedChannel() throws Exception {
109        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
110        NotificationChannel channel = mock(NotificationChannel.class);
111        when(channel.getId()).thenReturn("something new");
112        mController.onResume(appRow, channel, null, null);
113        assertFalse(mController.isAvailable());
114    }
115
116    @Test
117    public void testIsAvailable() throws Exception {
118        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
119        NotificationChannel channel = mock(NotificationChannel.class);
120        when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
121        when(channel.getId()).thenReturn(DEFAULT_CHANNEL_ID);
122        mController.onResume(appRow, channel, null, null);
123        assertTrue(mController.isAvailable());
124    }
125
126    @Test
127    public void testUpdateState_disabledByAdmin() throws Exception {
128        NotificationChannel channel = mock(NotificationChannel.class);
129        when(channel.getId()).thenReturn("something");
130        mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
131                RestrictedLockUtils.EnforcedAdmin.class));
132
133        Preference pref = new RestrictedSwitchPreference(mContext);
134        mController.updateState(pref);
135
136        assertFalse(pref.isEnabled());
137    }
138
139    @Test
140    public void testUpdateState_notConfigurable() throws Exception {
141        String lockedId = "locked";
142        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
143        appRow.lockedChannelId = lockedId;
144        NotificationChannel channel = mock(NotificationChannel.class);
145        when(channel.getId()).thenReturn(lockedId);
146        mController.onResume(appRow, channel, null, null);
147
148        Preference pref = new RestrictedSwitchPreference(mContext);
149        mController.updateState(pref);
150
151        assertFalse(pref.isEnabled());
152    }
153
154    @Test
155    public void testUpdateState_configurable() throws Exception {
156        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
157        NotificationChannel channel = mock(NotificationChannel.class);
158        when(channel.getId()).thenReturn("something");
159        mController.onResume(appRow, channel, null, null);
160
161        Preference pref = new RestrictedSwitchPreference(mContext);
162        mController.updateState(pref);
163
164        assertTrue(pref.isEnabled());
165    }
166
167    @Test
168    public void testUpdateState_checkedForHighImportanceChannel() throws Exception {
169        NotificationChannel channel = mock(NotificationChannel.class);
170        when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
171        mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
172
173        RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
174        mController.updateState(pref);
175        assertTrue(pref.isChecked());
176    }
177
178    @Test
179    public void testUpdateState_checkedForUnspecifiedImportanceChannel() throws Exception {
180        NotificationChannel channel = mock(NotificationChannel.class);
181        when(channel.getImportance()).thenReturn(IMPORTANCE_UNSPECIFIED);
182        mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
183
184        RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
185        mController.updateState(pref);
186        assertTrue(pref.isChecked());
187    }
188
189    @Test
190    public void testUpdateState_notCheckedForLowImportanceChannel() throws Exception {
191        NotificationChannel channel = mock(NotificationChannel.class);
192        when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
193        mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
194
195        RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
196        mController.updateState(pref);
197        assertFalse(pref.isChecked());
198    }
199
200    @Test
201    public void testOnPreferenceChange_on() {
202        NotificationChannel channel =
203                new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_LOW);
204        mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
205
206        RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
207        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
208        mController.displayPreference(mScreen);
209        mController.updateState(pref);
210        pref.setChecked(true);
211        mController.onPreferenceChange(pref, true);
212
213        assertEquals(IMPORTANCE_UNSPECIFIED, mController.mChannel.getImportance());
214        verify(mImportanceListener, times(1)).onImportanceChanged();
215    }
216
217    @Test
218    public void testOnPreferenceChange_off() {
219        NotificationChannel channel =
220                new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_HIGH);
221        mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
222
223        RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
224        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
225        mController.displayPreference(mScreen);
226        mController.updateState(pref);
227
228        pref.setChecked(false);
229        mController.onPreferenceChange(pref, false);
230
231        verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());
232        assertEquals(IMPORTANCE_LOW, mController.mChannel.getImportance());
233        verify(mImportanceListener, times(1)).onImportanceChanged();
234    }
235}
236