1 /*
2  * Copyright (C) 2020 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 
17 package com.android.settings.slices;
18 
19 import static com.android.settings.slices.CustomSliceRegistry.VOLUME_SLICES_URI;
20 
21 import static com.google.common.truth.Truth.assertThat;
22 
23 import static org.mockito.Mockito.never;
24 import static org.mockito.Mockito.spy;
25 import static org.mockito.Mockito.verify;
26 import static org.mockito.Mockito.when;
27 
28 import android.content.BroadcastReceiver;
29 import android.content.ContentResolver;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.IntentFilter;
33 import android.media.AudioManager;
34 import android.net.Uri;
35 
36 import com.android.settings.notification.MediaVolumePreferenceController;
37 import com.android.settings.notification.RingVolumePreferenceController;
38 import com.android.settings.notification.VolumeSeekBarPreferenceController;
39 import com.android.settingslib.SliceBroadcastRelay;
40 
41 import org.junit.After;
42 import org.junit.Before;
43 import org.junit.Test;
44 import org.junit.runner.RunWith;
45 import org.mockito.Mock;
46 import org.mockito.MockitoAnnotations;
47 import org.robolectric.RobolectricTestRunner;
48 import org.robolectric.RuntimeEnvironment;
49 import org.robolectric.annotation.Config;
50 import org.robolectric.annotation.Implementation;
51 import org.robolectric.annotation.Implements;
52 import org.robolectric.annotation.Resetter;
53 
54 @RunWith(RobolectricTestRunner.class)
55 @Config(shadows = VolumeSliceHelperTest.ShadowSliceBroadcastRelay.class)
56 public class VolumeSliceHelperTest {
57 
58     @Mock
59     private ContentResolver mResolver;
60 
61     private Context mContext;
62     private Intent mIntent;
63     private VolumeSeekBarPreferenceController mMediaController;
64     private VolumeSeekBarPreferenceController mRingController;
65 
66     @Before
setUp()67     public void setUp() {
68         MockitoAnnotations.initMocks(this);
69         mContext = spy(RuntimeEnvironment.application);
70         when(mContext.getContentResolver()).thenReturn(mResolver);
71 
72         mMediaController = new MediaVolumePreferenceController(mContext);
73         mRingController = new RingVolumePreferenceController(mContext);
74 
75         mIntent = createIntent(AudioManager.VOLUME_CHANGED_ACTION)
76                 .putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 1)
77                 .putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 2)
78                 .putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mMediaController.getAudioStream());
79     }
80 
81     @After
cleanUp()82     public void cleanUp() {
83         ShadowSliceBroadcastRelay.reset();
84         VolumeSliceHelper.sRegisteredUri.clear();
85         VolumeSliceHelper.sIntentFilter = null;
86     }
87 
88     @Test
registerIntentToUri_volumeController_shouldRegisterReceiver()89     public void registerIntentToUri_volumeController_shouldRegisterReceiver() {
90         registerIntentToUri(mMediaController);
91 
92         assertThat(ShadowSliceBroadcastRelay.getRegisteredCount()).isEqualTo(1);
93         assertThat(VolumeSliceHelper.sRegisteredUri)
94                 .containsKey((mMediaController.getSliceUri()));
95     }
96 
97     @Test
registerIntentToUri_doubleVolumeControllers_shouldRegisterReceiverOnce()98     public void registerIntentToUri_doubleVolumeControllers_shouldRegisterReceiverOnce() {
99         registerIntentToUri(mMediaController);
100 
101         registerIntentToUri(mRingController);
102 
103         assertThat(ShadowSliceBroadcastRelay.getRegisteredCount()).isEqualTo(1);
104         assertThat(VolumeSliceHelper.sRegisteredUri)
105                 .containsKey((mRingController.getSliceUri()));
106     }
107 
108     @Test
unregisterUri_notFinalUri_shouldNotUnregisterReceiver()109     public void unregisterUri_notFinalUri_shouldNotUnregisterReceiver() {
110         registerIntentToUri(mMediaController);
111         registerIntentToUri(mRingController);
112 
113         VolumeSliceHelper.unregisterUri(mContext, mMediaController.getSliceUri());
114 
115         assertThat(ShadowSliceBroadcastRelay.getRegisteredCount()).isEqualTo(1);
116         assertThat(VolumeSliceHelper.sRegisteredUri)
117                 .doesNotContainKey((mMediaController.getSliceUri()));
118     }
119 
120     @Test
unregisterUri_finalUri_shouldUnregisterReceiver()121     public void unregisterUri_finalUri_shouldUnregisterReceiver() {
122         registerIntentToUri(mMediaController);
123 
124         VolumeSliceHelper.unregisterUri(mContext, mMediaController.getSliceUri());
125 
126         assertThat(ShadowSliceBroadcastRelay.getRegisteredCount()).isEqualTo(0);
127         assertThat(VolumeSliceHelper.sRegisteredUri)
128                 .doesNotContainKey((mMediaController.getSliceUri()));
129     }
130 
131     @Test
unregisterUri_unregisterTwice_shouldUnregisterReceiverOnce()132     public void unregisterUri_unregisterTwice_shouldUnregisterReceiverOnce() {
133         registerIntentToUri(mMediaController);
134 
135         VolumeSliceHelper.unregisterUri(mContext, mMediaController.getSliceUri());
136         VolumeSliceHelper.unregisterUri(mContext, mMediaController.getSliceUri());
137 
138         assertThat(ShadowSliceBroadcastRelay.getRegisteredCount()).isEqualTo(0);
139     }
140 
141     @Test
unregisterUri_notRegistered_shouldNotUnregisterReceiver()142     public void unregisterUri_notRegistered_shouldNotUnregisterReceiver() {
143         registerIntentToUri(mMediaController);
144 
145         VolumeSliceHelper.unregisterUri(mContext, mRingController.getSliceUri());
146 
147         assertThat(ShadowSliceBroadcastRelay.getRegisteredCount()).isEqualTo(1);
148         assertThat(VolumeSliceHelper.sRegisteredUri)
149                 .containsKey((mMediaController.getSliceUri()));
150     }
151 
152     @Test
onReceive_audioStreamRegistered_shouldNotifyChange()153     public void onReceive_audioStreamRegistered_shouldNotifyChange() {
154         registerIntentToUri(mMediaController);
155 
156         VolumeSliceHelper.onReceive(mContext, mIntent);
157 
158         verify(mResolver).notifyChange(mMediaController.getSliceUri(), null);
159     }
160 
161     @Test
onReceive_audioStreamNotRegistered_shouldNotNotifyChange()162     public void onReceive_audioStreamNotRegistered_shouldNotNotifyChange() {
163         VolumeSliceHelper.onReceive(mContext, mIntent);
164 
165         verify(mResolver, never()).notifyChange(mMediaController.getSliceUri(), null);
166     }
167 
168     @Test
onReceive_audioStreamNotMatched_shouldNotNotifyChange()169     public void onReceive_audioStreamNotMatched_shouldNotNotifyChange() {
170         registerIntentToUri(mMediaController);
171         mIntent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, AudioManager.STREAM_DTMF);
172 
173         VolumeSliceHelper.onReceive(mContext, mIntent);
174 
175         verify(mResolver, never()).notifyChange(mMediaController.getSliceUri(), null);
176     }
177 
178     @Test
onReceive_mediaVolumeNotChanged_shouldNotNotifyChange()179     public void onReceive_mediaVolumeNotChanged_shouldNotNotifyChange() {
180         mIntent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 1)
181                 .putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 1);
182         registerIntentToUri(mMediaController);
183 
184         VolumeSliceHelper.onReceive(mContext, mIntent);
185 
186         verify(mResolver, never()).notifyChange(mMediaController.getSliceUri(), null);
187     }
188 
189     @Test
onReceive_streamVolumeMuted_shouldNotifyChange()190     public void onReceive_streamVolumeMuted_shouldNotifyChange() {
191         final Intent intent = createIntent(AudioManager.STREAM_MUTE_CHANGED_ACTION)
192                 .putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mMediaController.getAudioStream());
193         registerIntentToUri(mMediaController);
194         registerIntentToUri(mRingController);
195 
196         VolumeSliceHelper.onReceive(mContext, intent);
197 
198         verify(mResolver).notifyChange(mMediaController.getSliceUri(), null);
199     }
200 
201     @Test
onReceive_streamDevicesChanged_shouldNotifyChange()202     public void onReceive_streamDevicesChanged_shouldNotifyChange() {
203         final Intent intent = createIntent(AudioManager.STREAM_DEVICES_CHANGED_ACTION)
204                 .putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mRingController.getAudioStream());
205         registerIntentToUri(mMediaController);
206         registerIntentToUri(mRingController);
207 
208         VolumeSliceHelper.onReceive(mContext, intent);
209 
210         verify(mResolver).notifyChange(mRingController.getSliceUri(), null);
211     }
212 
213     @Test
onReceive_primaryMutedChanged_shouldNotifyChangeAll()214     public void onReceive_primaryMutedChanged_shouldNotifyChangeAll() {
215         final Intent intent = createIntent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
216         registerIntentToUri(mMediaController);
217         registerIntentToUri(mRingController);
218 
219         VolumeSliceHelper.onReceive(mContext, intent);
220 
221         verify(mResolver).notifyChange(mMediaController.getSliceUri(), null);
222         verify(mResolver).notifyChange(mRingController.getSliceUri(), null);
223     }
224 
registerIntentToUri(VolumeSeekBarPreferenceController controller)225     private void registerIntentToUri(VolumeSeekBarPreferenceController controller) {
226         VolumeSliceHelper.registerIntentToUri(mContext, controller.getIntentFilter(),
227                 controller.getSliceUri(), controller.getAudioStream());
228     }
229 
createIntent(String action)230     private Intent createIntent(String action) {
231         return new Intent(action)
232                 .putExtra(SliceBroadcastRelay.EXTRA_URI, VOLUME_SLICES_URI.toString());
233     }
234 
235     @Implements(SliceBroadcastRelay.class)
236     public static class ShadowSliceBroadcastRelay {
237 
238         private static int sRegisteredCount;
239 
240         @Implementation
registerReceiver(Context context, Uri sliceUri, Class<? extends BroadcastReceiver> receiver, IntentFilter filter)241         public static void registerReceiver(Context context, Uri sliceUri,
242                 Class<? extends BroadcastReceiver> receiver, IntentFilter filter) {
243             sRegisteredCount++;
244         }
245 
246         @Implementation
unregisterReceivers(Context context, Uri sliceUri)247         public static void unregisterReceivers(Context context, Uri sliceUri) {
248             sRegisteredCount--;
249         }
250 
251         @Resetter
reset()252         static void reset() {
253             sRegisteredCount = 0;
254         }
255 
getRegisteredCount()256         static int getRegisteredCount() {
257             return sRegisteredCount;
258         }
259     }
260 }
261