1 /* 2 * Copyright (C) 2018 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.ui; 18 19 import android.app.NotificationManager; 20 import android.content.ContentResolver; 21 import android.content.Context; 22 import android.os.Handler; 23 import android.os.SystemClock; 24 import android.provider.Settings; 25 import android.service.notification.ZenModeConfig; 26 import android.support.test.uiautomator.UiObject2; 27 import android.system.helpers.SettingsHelper; 28 import android.system.helpers.SettingsHelper.SettingsType; 29 import android.support.test.uiautomator.By; 30 import android.support.test.uiautomator.UiDevice; 31 import android.support.test.uiautomator.Until; 32 import android.test.InstrumentationTestCase; 33 import android.test.suitebuilder.annotation.MediumTest; 34 import android.test.suitebuilder.annotation.Suppress; 35 36 import java.util.HashMap; 37 38 public class SoundSettingsTest extends InstrumentationTestCase { 39 private static final String PAGE = Settings.ACTION_SOUND_SETTINGS; 40 private static final int TIMEOUT = 2000; 41 42 private UiDevice mDevice; 43 private ContentResolver mResolver; 44 private SettingsHelper mHelper; 45 46 47 private HashMap ringtoneSounds = new HashMap<String, String>() {{ 48 put("angler","Dione"); 49 put("bullhead","Dione"); 50 put("marlin","Spaceship"); 51 put("sailfish","Spaceship"); 52 put("walleye","Copycat"); 53 put("taimen","Copycat"); 54 }}; 55 56 private HashMap ringtoneCodes = new HashMap<String, String>() {{ 57 put("angler","38"); 58 put("bullhead","38"); 59 put("marlin","37"); 60 put("sailfish","37"); 61 put("walleye","26"); 62 put("taimen","26"); 63 }}; 64 65 private HashMap alarmSounds = new HashMap<String, String>() {{ 66 put("angler","Awaken"); 67 put("bullhead","Awaken"); 68 put("marlin","Bounce"); 69 put("sailfish","Bounce"); 70 put("walleye","Cuckoo clock"); 71 put("taimen","Cuckoo clock"); 72 }}; 73 74 private HashMap alarmCodes = new HashMap<String, String>() {{ 75 put("angler","6"); 76 put("bullhead","6"); 77 put("marlin","49"); 78 put("sailfish","49"); 79 put("walleye","15"); 80 put("taimen","15"); 81 }}; 82 83 private HashMap notificationSounds = new HashMap<String, String>() {{ 84 put("angler","Ceres"); 85 put("bullhead","Ceres"); 86 put("marlin","Trill"); 87 put("sailfish","Trill"); 88 put("walleye","Pipes"); 89 put("taimen","Pipes"); 90 }}; 91 92 93 private HashMap notificationCodes = new HashMap<String, String>() {{ 94 put("angler","26"); 95 put("bullhead","26"); 96 put("marlin","57"); 97 put("sailfish","57"); 98 put("walleye","69"); 99 put("taimen","69"); 100 }}; 101 102 @Override setUp()103 public void setUp() throws Exception { 104 super.setUp(); 105 mDevice = UiDevice.getInstance(getInstrumentation()); 106 mDevice.setOrientationNatural(); 107 mResolver = getInstrumentation().getContext().getContentResolver(); 108 mHelper = new SettingsHelper(); 109 } 110 111 @Override tearDown()112 public void tearDown() throws Exception { 113 mDevice.pressBack(); 114 mDevice.pressHome(); 115 mDevice.waitForIdle(); 116 mDevice.unfreezeRotation(); 117 super.tearDown(); 118 } 119 120 @MediumTest testCallVibrate()121 public void testCallVibrate() throws Exception { 122 assertTrue(mHelper.verifyToggleSetting(SettingsType.SYSTEM, PAGE, 123 "Also vibrate for calls", Settings.System.VIBRATE_WHEN_RINGING)); 124 assertTrue(mHelper.verifyToggleSetting(SettingsType.SYSTEM, PAGE, 125 "Also vibrate for calls", Settings.System.VIBRATE_WHEN_RINGING)); 126 } 127 128 @MediumTest testOtherSoundsDialPadTones()129 public void testOtherSoundsDialPadTones() throws Exception { 130 loadOtherSoundsPage(); 131 assertTrue("Dial pad tones not toggled", mHelper.verifyToggleSetting( 132 SettingsType.SYSTEM, PAGE, "Dial pad tones", 133 Settings.System.DTMF_TONE_WHEN_DIALING)); 134 } 135 136 @MediumTest testOtherSoundsScreenLocking()137 public void testOtherSoundsScreenLocking() throws Exception { 138 loadOtherSoundsPage(); 139 assertTrue("Screen locking sounds not toggled", 140 mHelper.verifyToggleSetting(SettingsType.SYSTEM, PAGE, 141 "Screen locking sounds", Settings.System.LOCKSCREEN_SOUNDS_ENABLED)); 142 } 143 144 @MediumTest testOtherSoundsCharging()145 public void testOtherSoundsCharging() throws Exception { 146 loadOtherSoundsPage(); 147 assertTrue("Charging sounds not toggled", 148 mHelper.verifyToggleSetting(SettingsType.GLOBAL, PAGE, 149 "Charging sounds", Settings.Global.CHARGING_SOUNDS_ENABLED)); 150 } 151 152 @MediumTest testOtherSoundsTouch()153 public void testOtherSoundsTouch() throws Exception { 154 loadOtherSoundsPage(); 155 assertTrue("Touch sounds not toggled", 156 mHelper.verifyToggleSetting(SettingsType.SYSTEM, PAGE, 157 "Touch sounds", Settings.System.SOUND_EFFECTS_ENABLED)); 158 } 159 160 @MediumTest testOtherSoundsVibrateOnTap()161 public void testOtherSoundsVibrateOnTap() throws Exception { 162 loadOtherSoundsPage(); 163 assertTrue("Vibrate on tap not toggled", 164 mHelper.verifyToggleSetting(SettingsType.SYSTEM, PAGE, 165 "Vibrate on tap", Settings.System.HAPTIC_FEEDBACK_ENABLED)); 166 } 167 loadOtherSoundsPage()168 private void loadOtherSoundsPage() throws Exception { 169 launchSoundSettings(); 170 mHelper.scrollVert(false); 171 Thread.sleep(1000); 172 } 173 launchSoundSettings()174 private void launchSoundSettings() throws Exception { 175 SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), PAGE); 176 mHelper.scrollVert(false); 177 clickMore(); 178 Thread.sleep(1000); 179 mHelper.scrollVert(true); 180 Thread.sleep(1000); 181 } 182 183 /* 184 * Rather than verifying every ringtone, verify the ones least likely to change 185 * (None and Hangouts) and an arbitrary one from the ringtone pool. 186 */ 187 @MediumTest testPhoneRingtoneNone()188 public void testPhoneRingtoneNone() throws Exception { 189 launchSoundSettings(); 190 mHelper.clickSetting("Phone ringtone"); 191 verifyRingtone(new RingtoneSetting("None", "null"), 192 Settings.System.RINGTONE); 193 } 194 195 @MediumTest 196 @Suppress testPhoneRingtoneHangouts()197 public void testPhoneRingtoneHangouts() throws Exception { 198 launchSoundSettings(); 199 mHelper.clickSetting("Phone ringtone"); 200 verifyRingtone(new RingtoneSetting("Hangouts Call", "31"), Settings.System.RINGTONE); 201 } 202 203 @MediumTest testPhoneRingtone()204 public void testPhoneRingtone() throws Exception { 205 launchSoundSettings(); 206 mHelper.clickSetting("Phone ringtone"); 207 String ringtone = ringtoneSounds.get(mDevice.getProductName()).toString(); 208 String ringtoneSettingValue = ringtoneCodes.get(mDevice.getProductName()).toString(); 209 verifyRingtone(new RingtoneSetting(ringtone, ringtoneSettingValue), 210 Settings.System.RINGTONE); 211 } 212 213 @MediumTest testNotificationRingtoneNone()214 public void testNotificationRingtoneNone() throws Exception { 215 launchSoundSettings(); 216 mHelper.clickSetting("Default notification sound"); 217 verifyRingtone(new RingtoneSetting("None", "null"), 218 Settings.System.NOTIFICATION_SOUND); 219 } 220 221 @MediumTest 222 @Suppress testNotificationRingtoneHangouts()223 public void testNotificationRingtoneHangouts() throws Exception { 224 launchSoundSettings(); 225 mHelper.clickSetting("Default notification sound"); 226 verifyRingtone(new RingtoneSetting("Hangouts Message", "30"), 227 Settings.System.NOTIFICATION_SOUND); 228 } 229 230 @MediumTest testNotificationRingtone()231 public void testNotificationRingtone() throws Exception { 232 launchSoundSettings(); 233 mHelper.clickSetting("Default notification sound"); 234 String notificationRingtone = notificationSounds.get(mDevice.getProductName()).toString(); 235 String notificationSettingValue = notificationCodes.get(mDevice.getProductName()).toString(); 236 verifyRingtone(new RingtoneSetting(notificationRingtone, notificationSettingValue), 237 Settings.System.NOTIFICATION_SOUND); 238 } 239 240 @MediumTest testAlarmRingtoneNone()241 public void testAlarmRingtoneNone() throws Exception { 242 launchSoundSettings(); 243 mHelper.clickSetting("Default alarm sound"); 244 verifyRingtone(new RingtoneSetting("None", "null"), 245 Settings.System.ALARM_ALERT); 246 } 247 248 @MediumTest testAlarmRingtone()249 public void testAlarmRingtone() throws Exception { 250 launchSoundSettings(); 251 String alarmRingtone = alarmSounds.get(mDevice.getProductName()).toString(); 252 String alarmSettingValue = alarmCodes.get(mDevice.getProductName()).toString(); 253 mHelper.clickSetting("Default alarm sound"); 254 verifyRingtone(new RingtoneSetting(alarmRingtone, alarmSettingValue), 255 Settings.System.ALARM_ALERT); 256 } 257 258 /* 259 * This method verifies that setting a custom ringtone changes the 260 * ringtone code setting on the system. Each ringtone sound corresponds 261 * to an arbitrary code. To see which ringtone code this is on your device, run 262 * adb shell settings get system ringtone 263 * The number you see at the end of the file path is the one you need. 264 * To see alarms and notifications ringtone codes, run the following: 265 * adb shell settings get system alarm_alert 266 * adb shell settings get system notification_sound 267 * @param r Ringtone setting - the name of the ringtone as displayed on device 268 * @param settingName - the code of the ringtone as explained above 269 * @param dir - the direction in which to scroll 270 */ verifyRingtone(RingtoneSetting r, String settingName)271 private void verifyRingtone(RingtoneSetting r, String settingName) throws Exception { 272 findRingtoneInList(r.getName()).click(); 273 if (mDevice.getProductName().equals("walleye") || mDevice.getProductName().equals("taimen")) { 274 mDevice.wait(Until.findObject(By.text("SAVE")), TIMEOUT).click(); 275 } 276 else { 277 mDevice.wait(Until.findObject(By.text("OK")), TIMEOUT).click(); 278 } 279 SystemClock.sleep(1000); 280 if (r.getVal().equals("null")) { 281 assertEquals(null, 282 Settings.System.getString(mResolver, settingName)); 283 } else if (r.getName().contains("Hangouts")) { 284 assertEquals("content://media/external/audio/media/" + r.getVal(), 285 Settings.System.getString(mResolver, settingName)); 286 } else { 287 assertEquals("content://media/internal/audio/media/" + r.getVal(), 288 Settings.System.getString(mResolver, settingName)); 289 } 290 } 291 292 private enum ScrollDir { 293 UP, 294 DOWN, 295 NOSCROLL 296 } 297 298 class RingtoneSetting { 299 private final String mName; 300 private final String mMediaVal; RingtoneSetting(String name, String fname)301 public RingtoneSetting(String name, String fname) { 302 mName = name; 303 mMediaVal = fname; 304 } getName()305 public String getName() { 306 return mName; 307 } getVal()308 public String getVal() { 309 return mMediaVal; 310 } 311 } 312 clickMore()313 private void clickMore() throws InterruptedException { 314 UiObject2 more = mDevice.wait(Until.findObject(By.text("Advanced")), TIMEOUT); 315 if (more != null) { 316 more.click(); 317 Thread.sleep(TIMEOUT); 318 } 319 } 320 findRingtoneInList(String ringtone)321 private UiObject2 findRingtoneInList(String ringtone) throws Exception { 322 mHelper.scrollVert(false); 323 SystemClock.sleep(1000); 324 UiObject2 ringToneObject = mDevice.wait(Until.findObject(By.text(ringtone)), TIMEOUT); 325 int count = 0; 326 while (ringToneObject == null && count < 5) { 327 mHelper.scrollVert(true); 328 SystemClock.sleep(1000); 329 ringToneObject = mDevice.wait(Until.findObject(By.text(ringtone)), TIMEOUT); 330 count++; 331 } 332 return ringToneObject; 333 } 334 } 335