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.deskclock.ringtone;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.content.SharedPreferences;
22 import android.net.Uri;
23 import android.preference.PreferenceManager;
24 
25 import androidx.recyclerview.widget.RecyclerView;
26 import androidx.test.InstrumentationRegistry;
27 import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
28 import androidx.test.rule.ActivityTestRule;
29 
30 import com.android.deskclock.ItemAdapter;
31 import com.android.deskclock.ItemAdapter.ItemHolder;
32 import com.android.deskclock.R;
33 import com.android.deskclock.Utils;
34 import com.android.deskclock.data.DataModel;
35 import com.android.deskclock.provider.Alarm;
36 
37 import org.junit.After;
38 import org.junit.Before;
39 import org.junit.Rule;
40 import org.junit.Test;
41 import org.junit.runner.RunWith;
42 
43 import java.util.Iterator;
44 import java.util.List;
45 
46 import static org.junit.Assert.assertEquals;
47 
48 /**
49  * Exercise the user interface that adjusts the selected ringtone.
50  */
51 @RunWith(AndroidJUnit4ClassRunner.class)
52 public class RingtonePickerActivityTest {
53 
54     private RingtonePickerActivity activity;
55     private RecyclerView ringtoneList;
56     private ItemAdapter<ItemHolder<Uri>> ringtoneAdapter;
57 
58     public static final Uri ALERT = Uri.parse("content://settings/system/alarm_alert");
59     public static final Uri CUSTOM_RINGTONE_1 = Uri.parse("content://media/external/audio/one.ogg");
60 
61     @Rule
62     public ActivityTestRule<RingtonePickerActivity> rule =
63             new ActivityTestRule<>(RingtonePickerActivity.class, true, false);
64 
65     @Before
66     @After
setUp()67     public void setUp() {
68         Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
69         SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
70         prefs.edit().clear().commit();
71     }
72 
73     @Test
validateDefaultState_TimerRingtonePicker()74     public void validateDefaultState_TimerRingtonePicker() {
75         createTimerRingtonePickerActivity();
76 
77         final List<ItemHolder<Uri>> systemRingtoneHolders = ringtoneAdapter.getItems();
78         final Iterator<ItemHolder<Uri>> itemsIter = systemRingtoneHolders.iterator();
79 
80         final HeaderHolder filesHeaderHolder = (HeaderHolder) itemsIter.next();
81         assertEquals(R.string.your_sounds, filesHeaderHolder.getTextResId());
82         assertEquals(HeaderViewHolder.VIEW_TYPE_ITEM_HEADER, filesHeaderHolder.getItemViewType());
83 
84         final AddCustomRingtoneHolder addNewHolder = (AddCustomRingtoneHolder) itemsIter.next();
85         assertEquals(AddCustomRingtoneViewHolder.VIEW_TYPE_ADD_NEW, addNewHolder.getItemViewType());
86 
87         final HeaderHolder systemHeaderHolder = (HeaderHolder) itemsIter.next();
88         assertEquals(R.string.device_sounds, systemHeaderHolder.getTextResId());
89         assertEquals(HeaderViewHolder.VIEW_TYPE_ITEM_HEADER, systemHeaderHolder.getItemViewType());
90 
91         final RingtoneHolder silentHolder = (RingtoneHolder) itemsIter.next();
92         assertEquals(Utils.RINGTONE_SILENT, silentHolder.getUri());
93         assertEquals(RingtoneViewHolder.VIEW_TYPE_SYSTEM_SOUND, silentHolder.getItemViewType());
94 
95         final RingtoneHolder defaultHolder = (RingtoneHolder) itemsIter.next();
96         assertEquals(RingtoneViewHolder.VIEW_TYPE_SYSTEM_SOUND, defaultHolder.getItemViewType());
97 
98         Runnable assertRunnable = () -> {
99             assertEquals("Silent", silentHolder.getName());
100             assertEquals("Timer Expired", defaultHolder.getName());
101             assertEquals(DataModel.getDataModel().getDefaultTimerRingtoneUri(),
102                     defaultHolder.getUri());
103             // Verify initial selection.
104             assertEquals(
105                     DataModel.getDataModel().getTimerRingtoneUri(),
106                     DataModel.getDataModel().getDefaultTimerRingtoneUri());
107         };
108         InstrumentationRegistry.getInstrumentation().runOnMainSync(assertRunnable);
109     }
110 
111     @Test
validateDefaultState_AlarmRingtonePicker()112     public void validateDefaultState_AlarmRingtonePicker() {
113         createAlarmRingtonePickerActivity(ALERT);
114 
115         final List<ItemHolder<Uri>> systemRingtoneHolders = ringtoneAdapter.getItems();
116         final Iterator<ItemHolder<Uri>> itemsIter = systemRingtoneHolders.iterator();
117 
118         final HeaderHolder filesHeaderHolder = (HeaderHolder) itemsIter.next();
119         assertEquals(R.string.your_sounds, filesHeaderHolder.getTextResId());
120         assertEquals(HeaderViewHolder.VIEW_TYPE_ITEM_HEADER, filesHeaderHolder.getItemViewType());
121 
122         final AddCustomRingtoneHolder addNewHolder = (AddCustomRingtoneHolder) itemsIter.next();
123         assertEquals(AddCustomRingtoneViewHolder.VIEW_TYPE_ADD_NEW, addNewHolder.getItemViewType());
124 
125         final HeaderHolder systemHeaderHolder = (HeaderHolder) itemsIter.next();
126         assertEquals(R.string.device_sounds, systemHeaderHolder.getTextResId());
127         assertEquals(HeaderViewHolder.VIEW_TYPE_ITEM_HEADER, systemHeaderHolder.getItemViewType());
128 
129         final RingtoneHolder silentHolder = (RingtoneHolder) itemsIter.next();
130         assertEquals(Utils.RINGTONE_SILENT, silentHolder.getUri());
131         assertEquals(RingtoneViewHolder.VIEW_TYPE_SYSTEM_SOUND, silentHolder.getItemViewType());
132 
133         final RingtoneHolder defaultHolder = (RingtoneHolder) itemsIter.next();
134         assertEquals(RingtoneViewHolder.VIEW_TYPE_SYSTEM_SOUND, defaultHolder.getItemViewType());
135 
136         Runnable assertRunnable = () -> {
137             assertEquals("Silent", silentHolder.getName());
138             assertEquals("Default alarm sound", defaultHolder.getName());
139             assertEquals(DataModel.getDataModel().getDefaultAlarmRingtoneUri(),
140                     defaultHolder.getUri());
141         };
142         InstrumentationRegistry.getInstrumentation().runOnMainSync(assertRunnable);
143     }
144 
145     @Test
validateDefaultState_TimerRingtonePicker_WithCustomRingtones()146     public void validateDefaultState_TimerRingtonePicker_WithCustomRingtones() {
147         Runnable customRingtoneRunnable = () -> {
148             DataModel.getDataModel().addCustomRingtone(CUSTOM_RINGTONE_1, "CustomSound");
149         };
150         InstrumentationRegistry.getInstrumentation().runOnMainSync(customRingtoneRunnable);
151         createTimerRingtonePickerActivity();
152 
153         final List<ItemHolder<Uri>> systemRingtoneHolders = ringtoneAdapter.getItems();
154         final Iterator<ItemHolder<Uri>> itemsIter = systemRingtoneHolders.iterator();
155 
156         final HeaderHolder filesHeaderHolder = (HeaderHolder) itemsIter.next();
157         assertEquals(R.string.your_sounds, filesHeaderHolder.getTextResId());
158         assertEquals(HeaderViewHolder.VIEW_TYPE_ITEM_HEADER, filesHeaderHolder.getItemViewType());
159 
160         final CustomRingtoneHolder customRingtoneHolder = (CustomRingtoneHolder) itemsIter.next();
161         assertEquals("CustomSound", customRingtoneHolder.getName());
162         assertEquals(CUSTOM_RINGTONE_1, customRingtoneHolder.getUri());
163         assertEquals(RingtoneViewHolder.VIEW_TYPE_CUSTOM_SOUND,
164                 customRingtoneHolder.getItemViewType());
165 
166         final AddCustomRingtoneHolder addNewHolder = (AddCustomRingtoneHolder) itemsIter.next();
167         assertEquals(AddCustomRingtoneViewHolder.VIEW_TYPE_ADD_NEW, addNewHolder.getItemViewType());
168 
169         final HeaderHolder systemHeaderHolder = (HeaderHolder) itemsIter.next();
170         assertEquals(R.string.device_sounds, systemHeaderHolder.getTextResId());
171         assertEquals(HeaderViewHolder.VIEW_TYPE_ITEM_HEADER, systemHeaderHolder.getItemViewType());
172 
173         final RingtoneHolder silentHolder = (RingtoneHolder) itemsIter.next();
174         assertEquals(Utils.RINGTONE_SILENT, silentHolder.getUri());
175         assertEquals(RingtoneViewHolder.VIEW_TYPE_SYSTEM_SOUND, silentHolder.getItemViewType());
176 
177         final RingtoneHolder defaultHolder = (RingtoneHolder) itemsIter.next();
178         assertEquals(RingtoneViewHolder.VIEW_TYPE_SYSTEM_SOUND, defaultHolder.getItemViewType());
179 
180         Runnable assertRunnable = () -> {
181             assertEquals("Silent", silentHolder.getName());
182             assertEquals("Timer Expired", defaultHolder.getName());
183             assertEquals(DataModel.getDataModel().getDefaultTimerRingtoneUri(),
184                     defaultHolder.getUri());
185             // Verify initial selection.
186             assertEquals(
187                     DataModel.getDataModel().getTimerRingtoneUri(),
188                     DataModel.getDataModel().getDefaultTimerRingtoneUri());
189         };
190         InstrumentationRegistry.getInstrumentation().runOnMainSync(assertRunnable);
191 
192         Runnable removeCustomRingtoneRunnable = () -> {
193             DataModel.getDataModel().removeCustomRingtone(CUSTOM_RINGTONE_1);
194         };
195         InstrumentationRegistry.getInstrumentation().runOnMainSync(removeCustomRingtoneRunnable);
196     }
197 
198     @Test
validateDefaultState_AlarmRingtonePicker_WithCustomRingtones()199     public void validateDefaultState_AlarmRingtonePicker_WithCustomRingtones() {
200         Runnable customRingtoneRunnable = () -> {
201             DataModel.getDataModel().addCustomRingtone(CUSTOM_RINGTONE_1, "CustomSound");
202         };
203         InstrumentationRegistry.getInstrumentation().runOnMainSync(customRingtoneRunnable);
204         createAlarmRingtonePickerActivity(ALERT);
205 
206         final List<ItemHolder<Uri>> systemRingtoneHolders = ringtoneAdapter.getItems();
207         final Iterator<ItemHolder<Uri>> itemsIter = systemRingtoneHolders.iterator();
208 
209         final HeaderHolder filesHeaderHolder = (HeaderHolder) itemsIter.next();
210         assertEquals(R.string.your_sounds, filesHeaderHolder.getTextResId());
211         assertEquals(HeaderViewHolder.VIEW_TYPE_ITEM_HEADER, filesHeaderHolder.getItemViewType());
212 
213         final CustomRingtoneHolder customRingtoneHolder = (CustomRingtoneHolder) itemsIter.next();
214         assertEquals("CustomSound", customRingtoneHolder.getName());
215         assertEquals(CUSTOM_RINGTONE_1, customRingtoneHolder.getUri());
216         assertEquals(RingtoneViewHolder.VIEW_TYPE_CUSTOM_SOUND,
217                 customRingtoneHolder.getItemViewType());
218 
219         final AddCustomRingtoneHolder addNewHolder = (AddCustomRingtoneHolder) itemsIter.next();
220         assertEquals(AddCustomRingtoneViewHolder.VIEW_TYPE_ADD_NEW, addNewHolder.getItemViewType());
221 
222         final HeaderHolder systemHeaderHolder = (HeaderHolder) itemsIter.next();
223         assertEquals(R.string.device_sounds, systemHeaderHolder.getTextResId());
224         assertEquals(HeaderViewHolder.VIEW_TYPE_ITEM_HEADER, systemHeaderHolder.getItemViewType());
225 
226         final RingtoneHolder silentHolder = (RingtoneHolder) itemsIter.next();
227         assertEquals(Utils.RINGTONE_SILENT, silentHolder.getUri());
228         assertEquals(RingtoneViewHolder.VIEW_TYPE_SYSTEM_SOUND, silentHolder.getItemViewType());
229 
230         final RingtoneHolder defaultHolder = (RingtoneHolder) itemsIter.next();
231         assertEquals(RingtoneViewHolder.VIEW_TYPE_SYSTEM_SOUND, defaultHolder.getItemViewType());
232 
233         Runnable assertRunnable = () -> {
234             assertEquals("Silent", silentHolder.getName());
235             assertEquals("Default alarm sound", defaultHolder.getName());
236             assertEquals(DataModel.getDataModel().getDefaultAlarmRingtoneUri(),
237                     defaultHolder.getUri());
238         };
239         InstrumentationRegistry.getInstrumentation().runOnMainSync(assertRunnable);
240 
241         Runnable removeCustomRingtoneRunnable = () -> {
242             DataModel.getDataModel().removeCustomRingtone(CUSTOM_RINGTONE_1);
243         };
244         InstrumentationRegistry.getInstrumentation().runOnMainSync(removeCustomRingtoneRunnable);
245     }
246 
createTimerRingtonePickerActivity()247     private void createTimerRingtonePickerActivity() {
248         final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
249         final Intent newIntent = new Intent();
250 
251         Runnable createIntentRunnable = () -> {
252             final Intent intent = RingtonePickerActivity.createTimerRingtonePickerIntent(context);
253             newIntent.fillIn(intent, 0);
254         };
255         InstrumentationRegistry.getInstrumentation().runOnMainSync(createIntentRunnable);
256 
257         createRingtonePickerActivity(newIntent);
258     }
259 
createAlarmRingtonePickerActivity(Uri ringtone)260     private void createAlarmRingtonePickerActivity(Uri ringtone) {
261         final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
262         final Intent newIntent = new Intent();
263 
264         Runnable createIntentRunnable = () -> {
265             // Use the custom ringtone in some alarms.
266             final Alarm alarm = new Alarm(1, 1);
267             alarm.enabled = true;
268             alarm.vibrate = true;
269             alarm.alert = ringtone;
270             alarm.deleteAfterUse = true;
271 
272             final Intent intent =
273                     RingtonePickerActivity.createAlarmRingtonePickerIntent(context, alarm);
274             newIntent.fillIn(intent, 0);
275         };
276         InstrumentationRegistry.getInstrumentation().runOnMainSync(createIntentRunnable);
277 
278         createRingtonePickerActivity(newIntent);
279     }
280 
281     @SuppressWarnings("unchecked")
createRingtonePickerActivity(Intent intent)282     private void createRingtonePickerActivity(Intent intent) {
283         activity = rule.launchActivity(intent);
284         ringtoneList = activity.findViewById(R.id.ringtone_content);
285         ringtoneAdapter = (ItemAdapter<ItemHolder<Uri>>) ringtoneList.getAdapter();
286     }
287 }
288