1 /* 2 * Copyright (C) 2009 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 android.media.audio.cts; 18 19 import static android.media.AudioManager.ADJUST_LOWER; 20 import static android.media.AudioManager.ADJUST_RAISE; 21 import static android.media.AudioManager.ADJUST_SAME; 22 import static android.media.AudioManager.MODE_IN_CALL; 23 import static android.media.AudioManager.MODE_IN_COMMUNICATION; 24 import static android.media.AudioManager.MODE_NORMAL; 25 import static android.media.AudioManager.MODE_RINGTONE; 26 import static android.media.AudioManager.RINGER_MODE_NORMAL; 27 import static android.media.AudioManager.RINGER_MODE_SILENT; 28 import static android.media.AudioManager.RINGER_MODE_VIBRATE; 29 import static android.media.AudioManager.STREAM_ACCESSIBILITY; 30 import static android.media.AudioManager.STREAM_ALARM; 31 import static android.media.AudioManager.STREAM_DTMF; 32 import static android.media.AudioManager.STREAM_MUSIC; 33 import static android.media.AudioManager.STREAM_NOTIFICATION; 34 import static android.media.AudioManager.STREAM_RING; 35 import static android.media.AudioManager.STREAM_SYSTEM; 36 import static android.media.AudioManager.STREAM_VOICE_CALL; 37 import static android.media.AudioManager.VIBRATE_SETTING_OFF; 38 import static android.media.AudioManager.VIBRATE_SETTING_ON; 39 import static android.media.AudioManager.VIBRATE_SETTING_ONLY_SILENT; 40 import static android.media.AudioManager.VIBRATE_TYPE_NOTIFICATION; 41 import static android.media.AudioManager.VIBRATE_TYPE_RINGER; 42 import static android.media.audio.cts.AudioTestUtil.resetVolumeIndex; 43 import static android.provider.Settings.Global.APPLY_RAMPING_RINGER; 44 import static android.provider.Settings.System.SOUND_EFFECTS_ENABLED; 45 46 import static com.android.media.mediatestutils.TestUtils.getFutureForIntent; 47 import static com.android.media.mediatestutils.TestUtils.getFutureForListener; 48 49 import static com.google.common.truth.Truth.assertThat; 50 import static com.google.common.truth.Truth.assertWithMessage; 51 52 import static org.junit.Assert.assertEquals; 53 import static org.junit.Assert.assertFalse; 54 import static org.junit.Assert.assertNotEquals; 55 import static org.junit.Assert.assertNotNull; 56 import static org.junit.Assert.assertNull; 57 import static org.junit.Assert.assertThrows; 58 import static org.junit.Assert.assertTrue; 59 import static org.junit.Assert.fail; 60 import static org.junit.Assume.assumeFalse; 61 import static org.junit.Assume.assumeTrue; 62 63 import android.Manifest; 64 import android.app.AutomaticZenRule; 65 import android.app.Instrumentation; 66 import android.app.NotificationChannel; 67 import android.app.NotificationManager; 68 import android.content.Context; 69 import android.content.Intent; 70 import android.content.pm.PackageManager; 71 import android.content.res.Resources; 72 import android.media.AudioAttributes; 73 import android.media.AudioDescriptor; 74 import android.media.AudioDeviceAttributes; 75 import android.media.AudioDeviceCallback; 76 import android.media.AudioDeviceInfo; 77 import android.media.AudioFormat; 78 import android.media.AudioHalVersionInfo; 79 import android.media.AudioManager; 80 import android.media.AudioMixerAttributes; 81 import android.media.AudioProfile; 82 import android.media.AudioTrack; 83 import android.media.MediaPlayer; 84 import android.media.MediaRecorder; 85 import android.media.MicrophoneInfo; 86 import android.media.audio.Flags; 87 import android.media.audiopolicy.AudioProductStrategy; 88 import android.media.audiopolicy.AudioVolumeGroup; 89 import android.media.cts.Utils; 90 import android.os.Build; 91 import android.os.HandlerThread; 92 import android.os.SystemClock; 93 import android.os.Vibrator; 94 import android.platform.test.annotations.AppModeFull; 95 import android.platform.test.annotations.AppModeSdkSandbox; 96 import android.platform.test.annotations.RequiresFlagsEnabled; 97 import android.provider.Settings; 98 import android.provider.Settings.System; 99 import android.util.Log; 100 import android.view.SoundEffectConstants; 101 102 import androidx.test.InstrumentationRegistry; 103 import androidx.test.runner.AndroidJUnit4; 104 105 import com.android.compatibility.common.util.AmUtils; 106 import com.android.compatibility.common.util.ApiLevelUtil; 107 import com.android.compatibility.common.util.CddTest; 108 import com.android.compatibility.common.util.MediaUtils; 109 import com.android.compatibility.common.util.NonMainlineTest; 110 import com.android.compatibility.common.util.SettingsStateKeeperRule; 111 import com.android.compatibility.common.util.SystemUtil; 112 import com.android.compatibility.common.util.UserHelper; 113 import com.android.compatibility.common.util.UserSettings.Namespace; 114 import com.android.internal.annotations.GuardedBy; 115 import com.android.media.mediatestutils.CancelAllFuturesRule; 116 117 import com.google.common.util.concurrent.Futures; 118 import com.google.common.util.concurrent.ListenableFuture; 119 import com.google.common.util.concurrent.MoreExecutors; 120 121 import org.junit.After; 122 import org.junit.Before; 123 import org.junit.ClassRule; 124 import org.junit.Rule; 125 import org.junit.Test; 126 import org.junit.runner.RunWith; 127 128 import java.util.ArrayList; 129 import java.util.Arrays; 130 import java.util.HashMap; 131 import java.util.HashSet; 132 import java.util.List; 133 import java.util.Map; 134 import java.util.Objects; 135 import java.util.Set; 136 import java.util.concurrent.Executors; 137 import java.util.concurrent.TimeUnit; 138 import java.util.function.BooleanSupplier; 139 import java.util.function.Predicate; 140 import java.util.stream.Collectors; 141 import java.util.stream.IntStream; 142 143 @NonMainlineTest 144 @AppModeFull(reason = "Waiting for volume/zen mode changes requires receiving intents. " + 145 "Several API calls require MODIFY_AUDIO_SETTINGS.") 146 @AppModeSdkSandbox(reason = "Allow test in the SDK sandbox (does not prevent other modes).") 147 @RunWith(AndroidJUnit4.class) 148 public class AudioManagerTest { 149 private static final String TAG = "AudioManagerTest"; 150 151 private static final int INIT_VOL = 1; 152 private static final int MP3_TO_PLAY = R.raw.testmp3; // ~ 5 second mp3 153 private static final long POLL_TIME_PLAY_MUSIC = 2000; 154 private static final long TIME_TO_PLAY = 2000; 155 private static final long TIME_TO_WAIT_CALLBACK_MS = 1000; 156 private static final String APPOPS_OP_STR = "android:write_settings"; 157 private static final Set<Integer> ALL_KNOWN_ENCAPSULATION_TYPES = Set.of( 158 AudioProfile.AUDIO_ENCAPSULATION_TYPE_IEC61937, 159 AudioProfile.AUDIO_ENCAPSULATION_TYPE_PCM); 160 private static final Set<Integer> ALL_ENCAPSULATION_TYPES = Set.of( 161 AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE, 162 AudioProfile.AUDIO_ENCAPSULATION_TYPE_IEC61937, 163 AudioProfile.AUDIO_ENCAPSULATION_TYPE_PCM); 164 private static final Set<Integer> ALL_AUDIO_STANDARDS = Set.of( 165 AudioDescriptor.STANDARD_NONE, 166 AudioDescriptor.STANDARD_EDID, 167 AudioDescriptor.STANDARD_SADB, 168 AudioDescriptor.STANDARD_VSADB); 169 private static final Map<Integer, Integer> DIRECT_OFFLOAD_MAP = Map.of( 170 AudioManager.PLAYBACK_OFFLOAD_NOT_SUPPORTED, 171 AudioManager.DIRECT_PLAYBACK_NOT_SUPPORTED, 172 AudioManager.PLAYBACK_OFFLOAD_SUPPORTED, 173 AudioManager.DIRECT_PLAYBACK_OFFLOAD_SUPPORTED, 174 AudioManager.PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED, 175 AudioManager.DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED); 176 private static final Set<Integer> ALL_MIXER_BEHAVIORS = Set.of( 177 AudioMixerAttributes.MIXER_BEHAVIOR_DEFAULT, 178 AudioMixerAttributes.MIXER_BEHAVIOR_BIT_PERFECT); 179 private static final int[] PUBLIC_STREAM_TYPES = { STREAM_VOICE_CALL, 180 STREAM_SYSTEM, STREAM_RING, STREAM_MUSIC, 181 STREAM_ALARM, STREAM_NOTIFICATION, 182 STREAM_DTMF, STREAM_ACCESSIBILITY }; 183 184 private static final int FUTURE_WAIT_SECS = 5; // Should never timeout; early fail 185 // How long to wait to verify that something that shouldn't happen doesn't happen 186 private static final int PROVE_NEGATIVE_DURATION_MS = 300; 187 188 private static final int INVALID_DIRECT_PLAYBACK_MODE = -1; 189 private AudioManager mAudioManager; 190 private NotificationManager mNm; 191 private boolean mHasVibrator; 192 private boolean mUseFixedVolume; 193 private boolean mIsTelevision; 194 private boolean mIsSingleVolume; 195 private boolean mSkipRingerTests; 196 private boolean mSkipAutoVolumeTests = false; 197 // From N onwards, ringer mode adjustments that toggle DND are not allowed unless 198 // package has DND access. Many tests in this package toggle DND access in order 199 // to get device out of the DND state for the test to proceed correctly. 200 // But DND access is disabled completely on low ram devices, 201 // so completely skip those tests here. 202 // These tests are migrated to CTS verifier tests to ensure test coverage. 203 private Context mContext; 204 private int mOriginalRingerMode; 205 private Map<Integer, Integer> mOriginalStreamVolumes = new HashMap<>(); 206 private NotificationManager.Policy mOriginalNotificationPolicy; 207 private int mOriginalZen; 208 private boolean mDoNotCheckUnmute; 209 private boolean mAppsBypassingDnd; 210 211 private UserHelper mUserHelper; 212 213 @ClassRule 214 public static final SettingsStateKeeperRule mSurroundSoundFormatsSettingsKeeper = 215 new SettingsStateKeeperRule(InstrumentationRegistry.getTargetContext(), 216 Namespace.GLOBAL, Settings.Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS); 217 218 @ClassRule 219 public static final SettingsStateKeeperRule mSurroundSoundModeSettingsKeeper = 220 new SettingsStateKeeperRule(InstrumentationRegistry.getTargetContext(), 221 Namespace.GLOBAL, Settings.Global.ENCODED_SURROUND_OUTPUT); 222 223 @Rule 224 public final CancelAllFuturesRule mCancelRule = new CancelAllFuturesRule(); 225 getInstrumentation()226 private static Instrumentation getInstrumentation() { 227 return InstrumentationRegistry.getInstrumentation(); 228 } 229 230 @Before setUp()231 public void setUp() throws Exception { 232 mContext = getInstrumentation().getContext(); 233 Utils.enableAppOps(mContext.getPackageName(), APPOPS_OP_STR, getInstrumentation()); 234 mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 235 Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); 236 mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); 237 mAppsBypassingDnd = NotificationManager.getService().areChannelsBypassingDnd(); 238 mHasVibrator = (vibrator != null) && vibrator.hasVibrator(); 239 mUseFixedVolume = mContext.getResources().getBoolean( 240 Resources.getSystem().getIdentifier("config_useFixedVolume", "bool", "android")); 241 PackageManager packageManager = mContext.getPackageManager(); 242 mIsTelevision = packageManager != null 243 && (packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK) 244 || packageManager.hasSystemFeature(PackageManager.FEATURE_TELEVISION)); 245 mIsSingleVolume = mContext.getResources().getBoolean( 246 Resources.getSystem().getIdentifier("config_single_volume", "bool", "android")); 247 mSkipRingerTests = mUseFixedVolume || mIsTelevision || mIsSingleVolume; 248 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { 249 // setRingerMode is a no-op 250 mSkipRingerTests = true; 251 // volume SDK APIs are no-ops 252 mSkipAutoVolumeTests = true; 253 } 254 255 mUserHelper = new UserHelper(mContext); 256 257 // TODO (b/294941969) pull out volume/ringer/zen state setting/resetting into test rule 258 // Store the original volumes that that they can be recovered in tearDown(). 259 final int[] streamTypes = { 260 STREAM_VOICE_CALL, 261 STREAM_SYSTEM, 262 STREAM_RING, 263 STREAM_MUSIC, 264 STREAM_ALARM, 265 STREAM_NOTIFICATION, 266 STREAM_DTMF, 267 STREAM_ACCESSIBILITY, 268 }; 269 mOriginalRingerMode = mAudioManager.getRingerMode(); 270 for (int streamType : streamTypes) { 271 mOriginalStreamVolumes.put(streamType, mAudioManager.getStreamVolume(streamType)); 272 } 273 274 // Tests require the known state of volumes set to INIT_VOL and zen mode 275 // turned off. 276 try { 277 Utils.toggleNotificationPolicyAccess( 278 mContext.getPackageName(), getInstrumentation(), true); 279 280 SystemUtil.runWithShellPermissionIdentity( 281 () -> { 282 mOriginalNotificationPolicy = mNm.getNotificationPolicy(); 283 mOriginalZen = mNm.getCurrentInterruptionFilter(); 284 mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); 285 setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL); 286 }, 287 Manifest.permission.STATUS_BAR_SERVICE); 288 } finally { 289 Utils.toggleNotificationPolicyAccess( 290 mContext.getPackageName(), getInstrumentation(), false); 291 } 292 293 for (int streamType : streamTypes) { 294 mAudioManager.setStreamVolume(streamType, INIT_VOL, 0 /* flags */); 295 } 296 297 // Check original microphone mute/unmute status 298 mDoNotCheckUnmute = false; 299 if (mAudioManager.isMicrophoneMute()) { 300 mAudioManager.setMicrophoneMute(false); 301 if (mAudioManager.isMicrophoneMute()) { 302 Log.w(TAG, "Mic seems muted by hardware! Please unmute and rerrun the test."); 303 mDoNotCheckUnmute = true; 304 } 305 } 306 // Reduce flake due to late intent delivery 307 AmUtils.waitForBroadcastIdle(); 308 } 309 310 @After tearDown()311 public void tearDown() throws Exception { 312 try { 313 Utils.toggleNotificationPolicyAccess( 314 mContext.getPackageName(), getInstrumentation(), true); 315 mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); 316 317 SystemUtil.runWithShellPermissionIdentity( 318 () -> { 319 mNm.setNotificationPolicy(mOriginalNotificationPolicy); 320 setInterruptionFilter(mOriginalZen); 321 }, 322 Manifest.permission.STATUS_BAR_SERVICE); 323 324 Map<String, AutomaticZenRule> rules = mNm.getAutomaticZenRules(); 325 for (String ruleId : rules.keySet()) { 326 mNm.removeAutomaticZenRule(ruleId); 327 } 328 329 // Recover the volume and the ringer mode that the test may have overwritten. 330 for (Map.Entry<Integer, Integer> e : mOriginalStreamVolumes.entrySet()) { 331 mAudioManager.setStreamVolume(e.getKey(), e.getValue(), 332 AudioManager.FLAG_ALLOW_RINGER_MODES); 333 } 334 mAudioManager.setRingerMode(mOriginalRingerMode); 335 } finally { 336 Utils.toggleNotificationPolicyAccess( 337 mContext.getPackageName(), getInstrumentation(), false); 338 } 339 } 340 341 @AppModeFull(reason = "Instant apps cannot hold android.permission.MODIFY_AUDIO_SETTINGS") 342 @Test testMicrophoneMute()343 public void testMicrophoneMute() throws Exception { 344 assumeFalse("Microphone is not supported on a visible background user", 345 mUserHelper.isVisibleBackgroundUser()); 346 mAudioManager.setMicrophoneMute(true); 347 assertTrue(mAudioManager.isMicrophoneMute()); 348 mAudioManager.setMicrophoneMute(false); 349 assertFalse(mAudioManager.isMicrophoneMute() && !mDoNotCheckUnmute); 350 } 351 352 @AppModeFull(reason = "Instant apps cannot hold android.permission.MODIFY_AUDIO_SETTINGS") 353 @Test testMicrophoneMuteIntent()354 public void testMicrophoneMuteIntent() throws Exception { 355 assumeFalse("Microphone is not supported on a visible background user", 356 mUserHelper.isVisibleBackgroundUser()); 357 assumeFalse(mDoNotCheckUnmute); 358 359 final boolean initialMicMute = mAudioManager.isMicrophoneMute(); 360 var future = mCancelRule.registerFuture(getFutureForIntent( 361 mContext, 362 AudioManager.ACTION_MICROPHONE_MUTE_CHANGED, 363 i -> true)); 364 try { 365 // change the mic mute state 366 mAudioManager.setMicrophoneMute(!initialMicMute); 367 // verify a change was reported 368 future.get(FUTURE_WAIT_SECS, TimeUnit.SECONDS); 369 // verify the mic mute state is expected 370 assertWithMessage("New mic mute should be changed after intent") 371 .that(mAudioManager.isMicrophoneMute()) 372 .isNotEqualTo(initialMicMute); 373 } finally { 374 mAudioManager.setMicrophoneMute(initialMicMute); 375 } 376 } 377 378 @AppModeFull(reason = "Instant apps cannot hold android.permission.MODIFY_AUDIO_SETTINGS") 379 @Test testSpeakerphoneIntent()380 public void testSpeakerphoneIntent() throws Exception { 381 // Speaker Phone Not supported in Automotive 382 assumeFalse(mContext.getPackageManager().hasSystemFeature( 383 PackageManager.FEATURE_AUTOMOTIVE)); 384 385 assumeTrue(hasBuiltinSpeaker()); 386 387 var future = mCancelRule.registerFuture(getFutureForIntent( 388 mContext, 389 AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED, 390 i -> true)); 391 392 final boolean initialSpeakerphoneState = mAudioManager.isSpeakerphoneOn(); 393 try { 394 getInstrumentation().getUiAutomation().adoptShellPermissionIdentity( 395 Manifest.permission.MODIFY_PHONE_STATE); 396 397 // change the speakerphone state 398 mAudioManager.setSpeakerphoneOn(!initialSpeakerphoneState); 399 future.get(FUTURE_WAIT_SECS, TimeUnit.SECONDS); 400 401 // verify the speakerphone state is expected 402 assertWithMessage("New speakerphone state should be changed after intent") 403 .that(mAudioManager.isSpeakerphoneOn()) 404 .isNotEqualTo(initialSpeakerphoneState); 405 } finally { 406 mAudioManager.setSpeakerphoneOn(initialSpeakerphoneState); 407 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 408 } 409 } 410 hasBuiltinSpeaker()411 private boolean hasBuiltinSpeaker() { 412 AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS); 413 for (AudioDeviceInfo device : devices) { 414 final int type = device.getType(); 415 if (type == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER 416 || type == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER_SAFE) { 417 return true; 418 } 419 } 420 return false; 421 } 422 423 @AppModeFull( 424 reason = 425 "ACTION_VOLUME_CHANGED is not sent to Instant apps (no" 426 + " FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS)") 427 @Test testVolumeChangedIntent()428 public void testVolumeChangedIntent() throws Exception { 429 if (mAudioManager.isVolumeFixed()) { 430 return; 431 } 432 if (mSkipAutoVolumeTests) { 433 // setStreamVolume is a no-op 434 return; 435 } 436 // safe media can block the raising the volume, disable it 437 getInstrumentation().getUiAutomation() 438 .adoptShellPermissionIdentity(Manifest.permission.STATUS_BAR_SERVICE); 439 mAudioManager.disableSafeMediaVolume(); 440 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 441 442 var future = mCancelRule.registerFuture(getFutureForIntent( 443 mContext, 444 AudioManager.ACTION_VOLUME_CHANGED, 445 i -> (i != null) 446 && (i.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, 447 Integer.MIN_VALUE) == STREAM_MUSIC))); 448 449 int mediaVol = mAudioManager.getStreamVolume(STREAM_MUSIC); 450 final int origVol = mediaVol; 451 final int maxMediaVol = mAudioManager.getStreamMaxVolume(STREAM_MUSIC); 452 // change media volume from current value 453 mAudioManager.setStreamVolume(STREAM_MUSIC, 454 mediaVol == maxMediaVol ? --mediaVol : ++mediaVol, 455 0 /*flags*/); 456 // verify a change was reported 457 final Intent intent = future.get(FUTURE_WAIT_SECS, TimeUnit.SECONDS); 458 459 assertWithMessage("Not an intent for STREAM_MUSIC") 460 .that(intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1)) 461 .isEqualTo(STREAM_MUSIC); 462 assertWithMessage("New STREAM_MUSIC volume not as expected") 463 .that(intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1)) 464 .isEqualTo(mediaVol); 465 assertWithMessage("Previous STREAM_MUSIC volume not as expected") 466 .that(intent.getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, -1)) 467 .isEqualTo(origVol); 468 } 469 470 private static final class MyBlockingRunnableListener { 471 private final SafeWaitObject mLock = new SafeWaitObject(); 472 @GuardedBy("mLock") 473 private boolean mEventReceived = false; 474 onSomeEventThatsExpected()475 public void onSomeEventThatsExpected() { 476 synchronized (mLock) { 477 mEventReceived = true; 478 mLock.notify(); 479 } 480 } 481 waitForExpectedEvent(long timeOutMs)482 public boolean waitForExpectedEvent(long timeOutMs) { 483 synchronized (mLock) { 484 return mLock.waitFor(timeOutMs, () -> mEventReceived); 485 } 486 } 487 } 488 489 @Test testSoundEffects()490 public void testSoundEffects() throws Exception { 491 Settings.System.putInt(mContext.getContentResolver(), SOUND_EFFECTS_ENABLED, 1); 492 493 // should hear sound after loadSoundEffects() called. 494 mAudioManager.loadSoundEffects(); 495 Thread.sleep(TIME_TO_PLAY); 496 float volume = 0.5f; // volume should be between 0.f to 1.f (or -1). 497 mAudioManager.playSoundEffect(SoundEffectConstants.CLICK); 498 mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP); 499 mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN); 500 mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT); 501 mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT); 502 503 mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP, volume); 504 mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN, volume); 505 mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT, volume); 506 mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT, volume); 507 508 // won't hear sound after unloadSoundEffects() called(); 509 mAudioManager.unloadSoundEffects(); 510 mAudioManager.playSoundEffect(AudioManager.FX_KEY_CLICK); 511 mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP); 512 mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN); 513 mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT); 514 mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT); 515 516 mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP, volume); 517 mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN, volume); 518 mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT, volume); 519 mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT, volume); 520 } 521 522 @Test testCheckingZenModeBlockDoesNotRequireNotificationPolicyAccess()523 public void testCheckingZenModeBlockDoesNotRequireNotificationPolicyAccess() throws Exception { 524 // set zen mode to priority only, so playSoundEffect will check notification policy 525 assumeFalse("Skipping zen mode test", mSkipRingerTests); 526 Utils.toggleNotificationPolicyAccess(mContext.getPackageName(), getInstrumentation(), 527 true); 528 setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY); 529 Settings.System.putInt(mContext.getContentResolver(), SOUND_EFFECTS_ENABLED, 1); 530 531 // take away write-notification policy access from the package 532 Utils.toggleNotificationPolicyAccess(mContext.getPackageName(), getInstrumentation(), 533 false); 534 535 // playSoundEffect should NOT throw a security exception; all apps have read-access 536 mAudioManager.playSoundEffect(SoundEffectConstants.CLICK); 537 } 538 539 @Test testMusicActive()540 public void testMusicActive() throws Exception { 541 if (mAudioManager.isMusicActive()) { 542 return; 543 } 544 MediaPlayer mp = MediaPlayer.create(mContext, MP3_TO_PLAY); 545 assertNotNull(mp); 546 mp.setAudioStreamType(STREAM_MUSIC); 547 mp.start(); 548 assertMusicActive(true); 549 mp.stop(); 550 mp.release(); 551 assertMusicActive(false); 552 } 553 554 @AppModeFull(reason = "Instant apps cannot hold android.permission.MODIFY_AUDIO_SETTINGS") 555 @Test testAccessMode()556 public void testAccessMode() throws Exception { 557 mAudioManager.setMode(MODE_RINGTONE); 558 assertEquals(MODE_RINGTONE, mAudioManager.getMode()); 559 mAudioManager.setMode(MODE_IN_COMMUNICATION); 560 assertEquals(MODE_IN_COMMUNICATION, mAudioManager.getMode()); 561 mAudioManager.setMode(MODE_NORMAL); 562 assertEquals(MODE_NORMAL, mAudioManager.getMode()); 563 } 564 565 @Test testSetSurroundFormatEnabled()566 public void testSetSurroundFormatEnabled() throws Exception { 567 getInstrumentation().getUiAutomation().adoptShellPermissionIdentity( 568 Manifest.permission.WRITE_SETTINGS); 569 570 int audioFormat = AudioFormat.ENCODING_DTS; 571 572 mAudioManager.setSurroundFormatEnabled(audioFormat, true /*enabled*/); 573 assertTrue(mAudioManager.isSurroundFormatEnabled(audioFormat)); 574 575 mAudioManager.setSurroundFormatEnabled(audioFormat, false /*enabled*/); 576 assertFalse(mAudioManager.isSurroundFormatEnabled(audioFormat)); 577 578 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 579 } 580 581 @AppModeFull(reason = "Instant apps cannot hold android.permission.WRITE_SETTINGS") 582 @Test testSetEncodedSurroundMode()583 public void testSetEncodedSurroundMode() throws Exception { 584 getInstrumentation().getUiAutomation().adoptShellPermissionIdentity( 585 Manifest.permission.WRITE_SETTINGS); 586 587 int expectedSurroundFormatsMode = Settings.Global.ENCODED_SURROUND_OUTPUT_MANUAL; 588 mAudioManager.setEncodedSurroundMode(expectedSurroundFormatsMode); 589 assertEquals(expectedSurroundFormatsMode, mAudioManager.getEncodedSurroundMode()); 590 591 expectedSurroundFormatsMode = Settings.Global.ENCODED_SURROUND_OUTPUT_NEVER; 592 mAudioManager.setEncodedSurroundMode(expectedSurroundFormatsMode); 593 assertEquals(expectedSurroundFormatsMode, mAudioManager.getEncodedSurroundMode()); 594 595 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 596 } 597 598 @SuppressWarnings("deprecation") 599 @AppModeFull(reason = "Instant apps cannot hold android.permission.MODIFY_AUDIO_SETTINGS") 600 @Test testRouting()601 public void testRouting() throws Exception { 602 // setBluetoothA2dpOn is a no-op, and getRouting should always return -1 603 boolean oldA2DP = mAudioManager.isBluetoothA2dpOn(); 604 mAudioManager.setBluetoothA2dpOn(true); 605 assertEquals(oldA2DP, mAudioManager.isBluetoothA2dpOn()); 606 mAudioManager.setBluetoothA2dpOn(false); 607 assertEquals(oldA2DP, mAudioManager.isBluetoothA2dpOn()); 608 609 assertEquals(-1, mAudioManager.getRouting(MODE_RINGTONE)); 610 assertEquals(-1, mAudioManager.getRouting(MODE_NORMAL)); 611 assertEquals(-1, mAudioManager.getRouting(MODE_IN_CALL)); 612 assertEquals(-1, mAudioManager.getRouting(MODE_IN_COMMUNICATION)); 613 614 mAudioManager.setBluetoothScoOn(true); 615 assertTrueCheckTimeout(mAudioManager, p -> p.isBluetoothScoOn(), 616 DEFAULT_ASYNC_CALL_TIMEOUT_MS, "isBluetoothScoOn returned false"); 617 618 mAudioManager.setBluetoothScoOn(false); 619 assertTrueCheckTimeout(mAudioManager, p -> !p.isBluetoothScoOn(), 620 DEFAULT_ASYNC_CALL_TIMEOUT_MS, "isBluetoothScoOn returned true"); 621 622 // Speaker Phone Not supported in Automotive 623 if (isAutomotive()) { 624 return; 625 } 626 627 try { 628 getInstrumentation().getUiAutomation().adoptShellPermissionIdentity( 629 Manifest.permission.MODIFY_PHONE_STATE); 630 631 mAudioManager.setSpeakerphoneOn(true); 632 assertTrueCheckTimeout(mAudioManager, p -> p.isSpeakerphoneOn(), 633 DEFAULT_ASYNC_CALL_TIMEOUT_MS, "isSpeakerPhoneOn() returned false"); 634 635 mAudioManager.setSpeakerphoneOn(false); 636 assertTrueCheckTimeout(mAudioManager, p -> !p.isSpeakerphoneOn(), 637 DEFAULT_ASYNC_CALL_TIMEOUT_MS, "isSpeakerPhoneOn() returned true"); 638 639 } finally { 640 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 641 } 642 } 643 644 @Test testVibrateNotification()645 public void testVibrateNotification() throws Exception { 646 if (mUseFixedVolume || !mHasVibrator) { 647 return; 648 } 649 if (mSkipAutoVolumeTests) { 650 // setRingerMode is a no-op 651 return; 652 } 653 Utils.toggleNotificationPolicyAccess( 654 mContext.getPackageName(), getInstrumentation(), true); 655 // VIBRATE_SETTING_ON 656 mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_ON); 657 assertEquals(mHasVibrator ? VIBRATE_SETTING_ON : VIBRATE_SETTING_OFF, 658 mAudioManager.getVibrateSetting(VIBRATE_TYPE_NOTIFICATION)); 659 mAudioManager.setRingerMode(RINGER_MODE_NORMAL); 660 assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION)); 661 662 mAudioManager.setRingerMode(RINGER_MODE_SILENT); 663 assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION)); 664 665 mAudioManager.setRingerMode(RINGER_MODE_VIBRATE); 666 assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT, 667 mAudioManager.getRingerMode()); 668 assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION)); 669 670 // VIBRATE_SETTING_OFF 671 mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_OFF); 672 assertEquals(VIBRATE_SETTING_OFF, 673 mAudioManager.getVibrateSetting(VIBRATE_TYPE_NOTIFICATION)); 674 mAudioManager.setRingerMode(RINGER_MODE_NORMAL); 675 assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION)); 676 677 mAudioManager.setRingerMode(RINGER_MODE_SILENT); 678 assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION)); 679 680 mAudioManager.setRingerMode(RINGER_MODE_VIBRATE); 681 assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT, 682 mAudioManager.getRingerMode()); 683 assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION)); 684 685 // VIBRATE_SETTING_ONLY_SILENT 686 mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_ONLY_SILENT); 687 assertEquals(mHasVibrator ? VIBRATE_SETTING_ONLY_SILENT : VIBRATE_SETTING_OFF, 688 mAudioManager.getVibrateSetting(VIBRATE_TYPE_NOTIFICATION)); 689 mAudioManager.setRingerMode(RINGER_MODE_NORMAL); 690 assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION)); 691 692 mAudioManager.setRingerMode(RINGER_MODE_SILENT); 693 assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION)); 694 695 mAudioManager.setRingerMode(RINGER_MODE_VIBRATE); 696 assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT, 697 mAudioManager.getRingerMode()); 698 assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION)); 699 700 // VIBRATE_TYPE_NOTIFICATION 701 mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_ON); 702 assertEquals(mHasVibrator ? VIBRATE_SETTING_ON : VIBRATE_SETTING_OFF, 703 mAudioManager.getVibrateSetting(VIBRATE_TYPE_NOTIFICATION)); 704 mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_OFF); 705 assertEquals(VIBRATE_SETTING_OFF, mAudioManager 706 .getVibrateSetting(VIBRATE_TYPE_NOTIFICATION)); 707 mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_ONLY_SILENT); 708 assertEquals(mHasVibrator ? VIBRATE_SETTING_ONLY_SILENT : VIBRATE_SETTING_OFF, 709 mAudioManager.getVibrateSetting(VIBRATE_TYPE_NOTIFICATION)); 710 } 711 712 @Test testVibrateRinger()713 public void testVibrateRinger() throws Exception { 714 if (mUseFixedVolume || !mHasVibrator) { 715 return; 716 } 717 if (mSkipAutoVolumeTests) { 718 // setRingerMode is a no-op 719 return; 720 } 721 Utils.toggleNotificationPolicyAccess( 722 mContext.getPackageName(), getInstrumentation(), true); 723 // VIBRATE_TYPE_RINGER 724 mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_ON); 725 assertEquals(mHasVibrator ? VIBRATE_SETTING_ON : VIBRATE_SETTING_OFF, 726 mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER)); 727 mAudioManager.setRingerMode(RINGER_MODE_NORMAL); 728 assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER)); 729 730 mAudioManager.setRingerMode(RINGER_MODE_SILENT); 731 assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER)); 732 733 mAudioManager.setRingerMode(RINGER_MODE_VIBRATE); 734 assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT, 735 mAudioManager.getRingerMode()); 736 assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER)); 737 738 // VIBRATE_SETTING_OFF 739 mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_OFF); 740 assertEquals(VIBRATE_SETTING_OFF, mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER)); 741 mAudioManager.setRingerMode(RINGER_MODE_NORMAL); 742 assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER)); 743 744 mAudioManager.setRingerMode(RINGER_MODE_SILENT); 745 assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER)); 746 747 mAudioManager.setRingerMode(RINGER_MODE_VIBRATE); 748 assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT, 749 mAudioManager.getRingerMode()); 750 // Note: as of Froyo, if VIBRATE_TYPE_RINGER is set to OFF, it will 751 // not vibrate, even in RINGER_MODE_VIBRATE. This allows users to 752 // disable the vibration for incoming calls only. 753 assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER)); 754 755 // VIBRATE_SETTING_ONLY_SILENT 756 mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_ONLY_SILENT); 757 assertEquals(mHasVibrator ? VIBRATE_SETTING_ONLY_SILENT : VIBRATE_SETTING_OFF, 758 mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER)); 759 mAudioManager.setRingerMode(RINGER_MODE_NORMAL); 760 assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER)); 761 762 mAudioManager.setRingerMode(RINGER_MODE_SILENT); 763 assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER)); 764 765 mAudioManager.setRingerMode(RINGER_MODE_VIBRATE); 766 assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT, 767 mAudioManager.getRingerMode()); 768 assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER)); 769 770 // VIBRATE_TYPE_NOTIFICATION 771 mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_ON); 772 assertEquals(mHasVibrator ? VIBRATE_SETTING_ON : VIBRATE_SETTING_OFF, 773 mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER)); 774 mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_OFF); 775 assertEquals(VIBRATE_SETTING_OFF, mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER)); 776 mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_ONLY_SILENT); 777 assertEquals(mHasVibrator ? VIBRATE_SETTING_ONLY_SILENT : VIBRATE_SETTING_OFF, 778 mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER)); 779 } 780 781 @Test testAccessRingMode()782 public void testAccessRingMode() throws Exception { 783 Utils.toggleNotificationPolicyAccess( 784 mContext.getPackageName(), getInstrumentation(), true); 785 mAudioManager.setRingerMode(RINGER_MODE_NORMAL); 786 assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode()); 787 788 mAudioManager.setRingerMode(RINGER_MODE_SILENT); 789 // AudioService#setRingerMode() has: 790 // if (isTelevision) return; 791 if (mSkipRingerTests) { 792 assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode()); 793 } else { 794 assertEquals(RINGER_MODE_SILENT, mAudioManager.getRingerMode()); 795 } 796 797 mAudioManager.setRingerMode(RINGER_MODE_VIBRATE); 798 if (mSkipRingerTests) { 799 assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode()); 800 } else { 801 assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT, 802 mAudioManager.getRingerMode()); 803 } 804 } 805 806 // TODO explain the intended behavior in this test 807 /** 808 * Test that in RINGER_MODE_VIBRATE we observe: 809 * if NOTIFICATION & RING are not aliased: 810 * ADJUST_UNMUTE NOTIFICATION -> no change (no mode change, NOTIF still muted) 811 * ADJUST_UNMUTE NOTIFICATION + FLAG_ALLOW_RINGER_MODES -> MODE_NORMAL 812 * if NOTIFICATION & RING are aliased: 813 * ADJUST_UNMUTE NOTIFICATION -> MODE_NORMAL 814 * ADJUST_UNMUTE NOTIFICATION + FLAG_ALLOW_RINGER_MODES -> MODE_NORMAL 815 * @throws Exception 816 */ 817 @Test testAdjustUnmuteNotificationInVibrate()818 public void testAdjustUnmuteNotificationInVibrate() throws Exception { 819 Log.i(TAG, "starting testAdjustUnmuteNotificationInVibrate"); 820 if (mSkipRingerTests) { 821 Log.i(TAG, "skipping testAdjustUnmuteNotificationInVibrate"); 822 return; 823 } 824 if (!mHasVibrator) { 825 Log.i(TAG, "skipping testAdjustUnmuteNotificationInVibrate, no vibrator"); 826 return; 827 } 828 // set mode to VIBRATE 829 Utils.toggleNotificationPolicyAccess( 830 mContext.getPackageName(), getInstrumentation(), true); 831 832 Map<Integer, MuteStateTransition> expectedVibrateTransitions = Map.of( 833 STREAM_MUSIC, new MuteStateTransition(false, false), 834 STREAM_RING, new MuteStateTransition(false, true), 835 STREAM_NOTIFICATION, new MuteStateTransition(false, true), 836 STREAM_ALARM, new MuteStateTransition(false, false)); 837 838 assertStreamMuteStateChange(() -> mAudioManager.setRingerMode(RINGER_MODE_VIBRATE), 839 expectedVibrateTransitions, 840 "RING and NOTIF should be muted in MODE_VIBRATE"); 841 842 assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode()); 843 Utils.toggleNotificationPolicyAccess( 844 mContext.getPackageName(), getInstrumentation(), false); 845 846 getInstrumentation().getUiAutomation() 847 .adoptShellPermissionIdentity(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED); 848 final int notifiAliasedStream = mAudioManager.getStreamTypeAlias(STREAM_NOTIFICATION); 849 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 850 851 Map<Integer, MuteStateTransition> unmuteRingerTransitions = Map.of( 852 STREAM_MUSIC, new MuteStateTransition(false, false), 853 STREAM_RING, new MuteStateTransition(true , false), 854 STREAM_NOTIFICATION, new MuteStateTransition(true, false), 855 STREAM_ALARM, new MuteStateTransition(false, false)); 856 857 if (notifiAliasedStream == STREAM_NOTIFICATION) { 858 Log.i(TAG, "testAdjustUnmuteNotificationInVibrate: NOTIF independent"); 859 860 Map<Integer, MuteStateTransition> noMuteTransitions = Map.of( 861 STREAM_MUSIC, new MuteStateTransition(false, false), 862 STREAM_RING, new MuteStateTransition(true , true), 863 STREAM_NOTIFICATION, new MuteStateTransition(true, true), 864 STREAM_ALARM, new MuteStateTransition(false, false)); 865 866 // unmute NOTIFICATION 867 assertStreamMuteStateChange(() -> mAudioManager.adjustStreamVolume( 868 STREAM_NOTIFICATION, AudioManager.ADJUST_UNMUTE, 0), 869 noMuteTransitions, 870 "NOTIFICATION should not unmute"); 871 // unmuting NOTIFICATION should not have exited RINGER_MODE_VIBRATE 872 assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode()); 873 874 875 assertStreamMuteStateChange(() -> mAudioManager.adjustStreamVolume( 876 STREAM_NOTIFICATION, 877 AudioManager.ADJUST_UNMUTE, AudioManager.FLAG_ALLOW_RINGER_MODES), 878 unmuteRingerTransitions, 879 "NOTIFICATION(+FLAG_ALLOW_RINGER_MODES) should unmute RING/NOTIF"); 880 // unmuting NOTIFICATION w/ FLAG_ALLOW_RINGER_MODES should have exited MODE_VIBRATE 881 assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode()); 882 } else if (notifiAliasedStream == STREAM_RING) { 883 Log.i(TAG, "testAdjustUnmuteNotificationInVibrate: NOTIF/RING aliased"); 884 // unmute NOTIFICATION (should be just like unmuting RING) 885 assertStreamMuteStateChange(() -> mAudioManager.adjustStreamVolume( 886 STREAM_NOTIFICATION, AudioManager.ADJUST_UNMUTE, 0), 887 unmuteRingerTransitions, 888 "when aliased NOTIF/RING should be unmuted"); 889 890 assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode()); 891 892 // test again with FLAG_ALLOW_RINGER_MODES 893 Utils.toggleNotificationPolicyAccess( 894 mContext.getPackageName(), getInstrumentation(), true); 895 mAudioManager.setRingerMode(RINGER_MODE_VIBRATE); 896 assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode()); 897 Utils.toggleNotificationPolicyAccess( 898 mContext.getPackageName(), getInstrumentation(), false); 899 900 // unmute NOTIFICATION (should be just like unmuting RING) 901 assertStreamMuteStateChange(() -> mAudioManager.adjustStreamVolume( 902 STREAM_NOTIFICATION, 903 AudioManager.ADJUST_UNMUTE, AudioManager.FLAG_ALLOW_RINGER_MODES), 904 unmuteRingerTransitions, 905 "when aliased NOTIF/RING should be unmuted"); 906 907 // unmuting NOTIFICATION should have exited RINGER_MODE_VIBRATE 908 assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode()); 909 } 910 } 911 912 /** 913 * Test that: 914 * - in RINGER_MODE_SILENT 915 * - when volume policy volumeUpToExitSilent is false 916 * - when STREAM_NOTIFICATION is not aliased to STREAM_RING 917 * we observe: 918 * ADJUST_UNMUTE NOTIFICATION -> no change (no mode change, NOTIF still muted) 919 * 920 * TODO add more tests for different VolumePolicy configurations in MODE_SILENT: 921 * ADJUST_UNMUTE NOTIFICATION + FLAG_ALLOW_RINGER_MODE -> 922 * no change if VolumePolicy.volumeUpToExitSilent false (default?) 923 * ADJUST_UNMUTE NOTIFICATION + FLAG_ALLOW_RINGER_MODE -> 924 * MODE_NORMAL if VolumePolicy.volumeUpToExitSilent true 925 * @throws Exception 926 */ 927 @Test testAdjustUnmuteNotificationInSilent()928 public void testAdjustUnmuteNotificationInSilent() throws Exception { 929 assumeFalse(mSkipRingerTests); 930 931 android.media.VolumePolicy vp = mAudioManager.getVolumePolicy(); 932 assumeFalse(vp.volumeUpToExitSilent); 933 getInstrumentation().getUiAutomation() 934 .adoptShellPermissionIdentity(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED); 935 assumeTrue(mAudioManager.getStreamTypeAlias(STREAM_NOTIFICATION) == STREAM_NOTIFICATION); 936 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 937 938 Map<Integer, MuteStateTransition> expectedTransitionsSilentMode = Map.of( 939 STREAM_MUSIC, new MuteStateTransition(false, false), 940 STREAM_NOTIFICATION, new MuteStateTransition(false, true), 941 STREAM_RING, new MuteStateTransition(false, true), 942 STREAM_ALARM, new MuteStateTransition(false, false)); 943 944 945 // set mode to SILENT 946 Utils.toggleNotificationPolicyAccess( 947 mContext.getPackageName(), getInstrumentation(), true); 948 mNm.setNotificationPolicy( 949 new NotificationManager.Policy( 950 mOriginalNotificationPolicy.priorityCategories 951 | NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS 952 | NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA, 953 mOriginalNotificationPolicy.priorityCallSenders, 954 mOriginalNotificationPolicy.priorityMessageSenders)); 955 assertStreamMuteStateChange(() -> mAudioManager.setRingerMode(RINGER_MODE_SILENT), 956 expectedTransitionsSilentMode, 957 "RING/NOTIF should mute in SILENT"); 958 assertEquals(RINGER_MODE_SILENT, mAudioManager.getRingerMode()); 959 Utils.toggleNotificationPolicyAccess( 960 mContext.getPackageName(), getInstrumentation(), false); 961 962 Map<Integer, MuteStateTransition> expectedTransitionsRemainSilentMode = Map.of( 963 STREAM_MUSIC, new MuteStateTransition(false, false), 964 STREAM_NOTIFICATION, new MuteStateTransition(true, true), 965 STREAM_RING, new MuteStateTransition(true, true), 966 STREAM_ALARM, new MuteStateTransition(false, false)); 967 968 969 // unmute NOTIFICATION 970 assertStreamMuteStateChange(() -> mAudioManager.adjustStreamVolume( 971 STREAM_NOTIFICATION, AudioManager.ADJUST_UNMUTE, 0), 972 expectedTransitionsRemainSilentMode, 973 "Unmute NOTIF should have no effect in SILENT"); 974 975 // unmuting NOTIFICATION should not have exited RINGER_MODE_SILENT 976 assertEquals(RINGER_MODE_SILENT, mAudioManager.getRingerMode()); 977 } 978 979 @Test testSetRingerModePolicyAccess()980 public void testSetRingerModePolicyAccess() throws Exception { 981 assumeFalse(mSkipRingerTests); 982 // Apps without policy access cannot change silent -> normal or silent -> vibrate. 983 Utils.toggleNotificationPolicyAccess( 984 mContext.getPackageName(), getInstrumentation(), true); 985 mAudioManager.setRingerMode(RINGER_MODE_SILENT); 986 assertEquals(RINGER_MODE_SILENT, mAudioManager.getRingerMode()); 987 Utils.toggleNotificationPolicyAccess( 988 mContext.getPackageName(), getInstrumentation(), false); 989 990 try { 991 mAudioManager.setRingerMode(RINGER_MODE_NORMAL); 992 fail("Apps without notification policy access cannot change ringer mode"); 993 } catch (SecurityException e) { 994 } 995 996 try { 997 mAudioManager.setRingerMode(RINGER_MODE_VIBRATE); 998 fail("Apps without notification policy access cannot change ringer mode"); 999 } catch (SecurityException e) { 1000 } 1001 1002 // Apps without policy access cannot change normal -> silent. 1003 Utils.toggleNotificationPolicyAccess( 1004 mContext.getPackageName(), getInstrumentation(), true); 1005 mAudioManager.setRingerMode(RINGER_MODE_NORMAL); 1006 assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode()); 1007 Utils.toggleNotificationPolicyAccess( 1008 mContext.getPackageName(), getInstrumentation(), false); 1009 1010 try { 1011 mAudioManager.setRingerMode(RINGER_MODE_SILENT); 1012 fail("Apps without notification policy access cannot change ringer mode"); 1013 } catch (SecurityException e) { 1014 } 1015 assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode()); 1016 1017 if (mHasVibrator) { 1018 // Apps without policy access cannot change vibrate -> silent. 1019 Utils.toggleNotificationPolicyAccess( 1020 mContext.getPackageName(), getInstrumentation(), true); 1021 mAudioManager.setRingerMode(RINGER_MODE_VIBRATE); 1022 assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode()); 1023 Utils.toggleNotificationPolicyAccess( 1024 mContext.getPackageName(), getInstrumentation(), false); 1025 1026 try { 1027 mAudioManager.setRingerMode(RINGER_MODE_SILENT); 1028 fail("Apps without notification policy access cannot change ringer mode"); 1029 } catch (SecurityException e) { 1030 } 1031 1032 // Apps without policy access can change vibrate -> normal and vice versa. 1033 assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode()); 1034 mAudioManager.setRingerMode(RINGER_MODE_NORMAL); 1035 assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode()); 1036 mAudioManager.setRingerMode(RINGER_MODE_VIBRATE); 1037 assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode()); 1038 } 1039 } 1040 1041 @Test testAccessRampingRinger()1042 public void testAccessRampingRinger() { 1043 boolean originalEnabledState = mAudioManager.isRampingRingerEnabled(); 1044 try { 1045 mAudioManager.setRampingRingerEnabled(false); 1046 assertFalse(mAudioManager.isRampingRingerEnabled()); 1047 1048 mAudioManager.setRampingRingerEnabled(true); 1049 assertTrue(mAudioManager.isRampingRingerEnabled()); 1050 } finally { 1051 mAudioManager.setRampingRingerEnabled(originalEnabledState); 1052 } 1053 } 1054 1055 @Test testRampingRingerSetting()1056 public void testRampingRingerSetting() { 1057 boolean originalEnabledState = mAudioManager.isRampingRingerEnabled(); 1058 try { 1059 // Deprecated public setting should still be supported and affect the setting getter. 1060 Settings.Global.putInt(mContext.getContentResolver(), APPLY_RAMPING_RINGER, 0); 1061 assertFalse(mAudioManager.isRampingRingerEnabled()); 1062 1063 Settings.Global.putInt(mContext.getContentResolver(), APPLY_RAMPING_RINGER, 1); 1064 assertTrue(mAudioManager.isRampingRingerEnabled()); 1065 } finally { 1066 mAudioManager.setRampingRingerEnabled(originalEnabledState); 1067 } 1068 } 1069 1070 @Test testVolume()1071 public void testVolume() throws Exception { 1072 if (MediaUtils.check(mIsTelevision, "No volume test due to fixed/full vol devices")) 1073 return; 1074 if (mSkipAutoVolumeTests) { 1075 // setStreamVolume/adjustVolume are no-op 1076 return; 1077 } 1078 Utils.toggleNotificationPolicyAccess( 1079 mContext.getPackageName(), getInstrumentation(), true); 1080 int volume, volumeDelta; 1081 int[] streams = {STREAM_ALARM, 1082 STREAM_MUSIC, 1083 STREAM_VOICE_CALL, 1084 STREAM_RING}; 1085 1086 int maxMusicVolume = mAudioManager.getStreamMaxVolume(STREAM_MUSIC); 1087 1088 for (int stream : streams) { 1089 if (mIsSingleVolume && stream != STREAM_MUSIC) { 1090 continue; 1091 } 1092 1093 // set ringer mode to back normal to not interfere with volume tests 1094 mAudioManager.setRingerMode(RINGER_MODE_NORMAL); 1095 1096 int maxVolume = mAudioManager.getStreamMaxVolume(stream); 1097 int minVolume = mAudioManager.getStreamMinVolume(stream); 1098 1099 // validate min 1100 assertTrue(String.format("minVolume(%d) must be >= 0", minVolume), minVolume >= 0); 1101 assertTrue(String.format("minVolume(%d) must be < maxVolume(%d)", minVolume, 1102 maxVolume), 1103 minVolume < maxVolume); 1104 1105 final int minNonZeroVolume = Math.max(minVolume, 1); 1106 mAudioManager.setStreamVolume(stream, minNonZeroVolume, 0); 1107 if (mUseFixedVolume) { 1108 assertEquals(maxVolume, mAudioManager.getStreamVolume(stream)); 1109 continue; 1110 } 1111 assertEquals(String.format("stream=%d", stream), 1112 minNonZeroVolume, mAudioManager.getStreamVolume(stream)); 1113 1114 if (stream == STREAM_MUSIC && mAudioManager.isWiredHeadsetOn()) { 1115 // due to new regulations, music sent over a wired headset may be volume limited 1116 // until the user explicitly increases the limit, so we can't rely on being able 1117 // to set the volume to getStreamMaxVolume(). Instead, determine the current limit 1118 // by increasing the volume until it won't go any higher, then use that volume as 1119 // the maximum for the purposes of this test 1120 int curvol = 0; 1121 int prevvol = 0; 1122 do { 1123 prevvol = curvol; 1124 mAudioManager.adjustStreamVolume(stream, ADJUST_RAISE, 0); 1125 curvol = mAudioManager.getStreamVolume(stream); 1126 } while (curvol != prevvol); 1127 maxVolume = maxMusicVolume = curvol; 1128 } 1129 waitForStreamVolumeSet(stream, maxVolume); 1130 assertCallDoesNotChangeStreamVolume( 1131 () -> mAudioManager.adjustStreamVolume(stream, ADJUST_RAISE, 0), 1132 stream, 1133 "No change expected at max volume"); 1134 1135 if (stream == STREAM_VOICE_CALL) { 1136 // TODO(b/362836517): add API to check the adjust volume delta for voice call based 1137 // on ratio between index UI steps and voice call range 1138 continue; 1139 } 1140 1141 volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(stream)); 1142 assertCallChangesStreamVolume( 1143 () -> mAudioManager.adjustSuggestedStreamVolume(ADJUST_LOWER, stream, 0), 1144 stream, maxVolume - volumeDelta, 1145 "Vol ADJUST_LOWER suggested stream:" + stream + " maxVol:" + maxVolume); 1146 1147 // volume lower 1148 mAudioManager.setStreamVolume(stream, maxVolume, 0); 1149 volume = mAudioManager.getStreamVolume(stream); 1150 while (volume > minVolume) { 1151 volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(stream)); 1152 assertCallChangesStreamVolume( 1153 () -> mAudioManager.adjustStreamVolume(stream, ADJUST_LOWER, 0), 1154 stream, Math.max(0, volume - volumeDelta), 1155 "Vol ADJUST_LOWER on stream:" + stream + " vol:" + volume 1156 + " minVol:" + minVolume + " volDelta:" + volumeDelta); 1157 volume = mAudioManager.getStreamVolume(stream); 1158 } 1159 1160 mAudioManager.adjustStreamVolume(stream, ADJUST_SAME, 0); 1161 1162 // volume raise 1163 mAudioManager.setStreamVolume(stream, minNonZeroVolume, 0); 1164 volume = mAudioManager.getStreamVolume(stream); 1165 while (volume < maxVolume) { 1166 volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(stream)); 1167 assertCallChangesStreamVolume( 1168 () -> mAudioManager.adjustStreamVolume(stream, ADJUST_RAISE, 0), 1169 stream, Math.min(volume + volumeDelta, maxVolume), 1170 "Vol ADJUST_RAISE on stream:" + stream + " vol:" + volume 1171 + " maxVol:" + maxVolume + " volDelta:" + volumeDelta); 1172 volume = mAudioManager.getStreamVolume(stream); 1173 } 1174 1175 // volume same 1176 waitForStreamVolumeSet(stream, maxVolume); 1177 assertCallDoesNotChangeStreamVolume( 1178 () -> mAudioManager.adjustStreamVolume(stream, ADJUST_SAME, 0), 1179 stream, 1180 "Vol ADJUST_RAISE onADJUST_SAME stream:" + stream); 1181 mAudioManager.setStreamVolume(stream, maxVolume, 0); 1182 } 1183 1184 if (mUseFixedVolume) { 1185 return; 1186 } 1187 1188 boolean isMusicPlayingBeforeTest = false; 1189 if (mAudioManager.isMusicActive()) { 1190 isMusicPlayingBeforeTest = true; 1191 } 1192 1193 // TODO this doesn't test anything now that STREAM_MUSIC is the default 1194 MediaPlayer mp = MediaPlayer.create(mContext, MP3_TO_PLAY); 1195 assertNotNull(mp); 1196 mp.setAudioStreamType(STREAM_MUSIC); 1197 mp.setLooping(true); 1198 mp.start(); 1199 assertMusicActive(true); 1200 1201 waitForStreamVolumeSet(STREAM_MUSIC, maxMusicVolume - 1); 1202 // adjust volume as ADJUST_SAME 1203 assertCallDoesNotChangeStreamVolume( 1204 () -> mAudioManager.adjustVolume(ADJUST_SAME, 0), 1205 STREAM_MUSIC); 1206 1207 // adjust volume as ADJUST_RAISE 1208 waitForStreamVolumeSet(STREAM_MUSIC, 0); 1209 volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(STREAM_MUSIC)); 1210 assertCallChangesStreamVolume( 1211 () -> mAudioManager.adjustVolume(ADJUST_RAISE, 0), 1212 STREAM_MUSIC, 1213 volumeDelta); 1214 1215 // adjust volume as ADJUST_LOWER 1216 waitForStreamVolumeSet(STREAM_MUSIC, maxMusicVolume); 1217 volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(STREAM_MUSIC)); 1218 assertCallChangesStreamVolume( 1219 () -> mAudioManager.adjustVolume(ADJUST_LOWER, 0), 1220 STREAM_MUSIC, 1221 maxMusicVolume - volumeDelta); 1222 1223 mp.stop(); 1224 mp.release(); 1225 if (!isMusicPlayingBeforeTest) { 1226 assertMusicActive(false); 1227 } 1228 } 1229 1230 @Test testAccessibilityVolume()1231 public void testAccessibilityVolume() throws Exception { 1232 // TODO this does not test the positive case (having permissions) 1233 assumeFalse("AudioManagerTest testAccessibilityVolume() skipped: fixed volume", 1234 mUseFixedVolume); 1235 1236 final int maxA11yVol = mAudioManager.getStreamMaxVolume(STREAM_ACCESSIBILITY); 1237 assertWithMessage("Max a11yVol must be strictly positive") 1238 .that(maxA11yVol) 1239 .isGreaterThan(0); 1240 1241 // changing STREAM_ACCESSIBILITY is subject to permission 1242 assertCallDoesNotChangeStreamVolume( 1243 () -> mAudioManager.setStreamVolume(STREAM_ACCESSIBILITY, INIT_VOL + 1, 0), 1244 STREAM_ACCESSIBILITY, 1245 "Setting accessibility vol requires perms"); 1246 assertCallDoesNotChangeStreamVolume( 1247 () -> mAudioManager.adjustStreamVolume(STREAM_ACCESSIBILITY, ADJUST_LOWER, 0), 1248 STREAM_ACCESSIBILITY, 1249 "Setting accessibility vol requires perms"); 1250 1251 assertCallDoesNotChangeStreamVolume( 1252 () -> mAudioManager.adjustStreamVolume(STREAM_ACCESSIBILITY, ADJUST_RAISE, 0), 1253 STREAM_ACCESSIBILITY, 1254 "Setting accessibility vol requires perms"); 1255 } 1256 1257 @Test testSetVoiceCallVolumeToZeroPermission()1258 public void testSetVoiceCallVolumeToZeroPermission() { 1259 // Verify that only apps with MODIFY_PHONE_STATE can set VOICE_CALL_STREAM to 0 1260 mAudioManager.setStreamVolume(STREAM_VOICE_CALL, 0, 0); 1261 assertTrue("MODIFY_PHONE_STATE is required in order to set voice call volume to 0", 1262 mAudioManager.getStreamVolume(STREAM_VOICE_CALL) != 0); 1263 } 1264 1265 @Test testMuteFixedVolume()1266 public void testMuteFixedVolume() throws Exception { 1267 if (mSkipAutoVolumeTests) { 1268 // adjustStreamVolume is a no-op 1269 return; 1270 } 1271 int[] streams = { 1272 STREAM_VOICE_CALL, 1273 STREAM_MUSIC, 1274 STREAM_RING, 1275 STREAM_ALARM, 1276 STREAM_NOTIFICATION, 1277 STREAM_SYSTEM}; 1278 if (mUseFixedVolume) { 1279 for (int stream : streams) { 1280 mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_MUTE, 0); 1281 assertFalse("Muting should not affect a fixed volume device.", 1282 mAudioManager.isStreamMute(stream)); 1283 1284 mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_TOGGLE_MUTE, 0); 1285 assertFalse("Toggling mute should not affect a fixed volume device.", 1286 mAudioManager.isStreamMute(stream)); 1287 1288 mAudioManager.setStreamMute(stream, true); 1289 assertFalse("Muting should not affect a fixed volume device.", 1290 mAudioManager.isStreamMute(stream)); 1291 } 1292 } 1293 } 1294 1295 @Test testMuteDndAffectedStreams()1296 public void testMuteDndAffectedStreams() throws Exception { 1297 assumeFalse(mSkipRingerTests); 1298 int[] streams = { STREAM_RING }; 1299 // Mute streams 1300 Utils.toggleNotificationPolicyAccess( 1301 mContext.getPackageName(), getInstrumentation(), true); 1302 mAudioManager.setRingerMode(RINGER_MODE_SILENT); 1303 Utils.toggleNotificationPolicyAccess( 1304 mContext.getPackageName(), getInstrumentation(), false); 1305 // Verify streams cannot be unmuted without policy access. 1306 for (int stream : streams) { 1307 try { 1308 mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_UNMUTE, 0); 1309 assertEquals("Apps without Notification policy access can't change ringer mode", 1310 RINGER_MODE_SILENT, mAudioManager.getRingerMode()); 1311 } catch (SecurityException e) { 1312 } 1313 1314 try { 1315 mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_TOGGLE_MUTE, 1316 0); 1317 assertEquals("Apps without Notification policy access can't change ringer mode", 1318 RINGER_MODE_SILENT, mAudioManager.getRingerMode()); 1319 } catch (SecurityException e) { 1320 } 1321 1322 try { 1323 mAudioManager.setStreamMute(stream, false); 1324 assertEquals("Apps without Notification policy access can't change ringer mode", 1325 RINGER_MODE_SILENT, mAudioManager.getRingerMode()); 1326 } catch (SecurityException e) { 1327 } 1328 } 1329 1330 // This ensures we're out of vibrate or silent modes. 1331 Utils.toggleNotificationPolicyAccess( 1332 mContext.getPackageName(), getInstrumentation(), true); 1333 mAudioManager.setRingerMode(RINGER_MODE_NORMAL); 1334 for (int stream : streams) { 1335 // ensure each stream is on and turned up. 1336 mAudioManager.setStreamVolume(stream, 1337 mAudioManager.getStreamMaxVolume(stream), 1338 0); 1339 1340 Utils.toggleNotificationPolicyAccess( 1341 mContext.getPackageName(), getInstrumentation(), false); 1342 try { 1343 mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_MUTE, 0); 1344 assertEquals("Apps without Notification policy access can't change ringer mode", 1345 RINGER_MODE_NORMAL, mAudioManager.getRingerMode()); 1346 } catch (SecurityException e) { 1347 } 1348 try { 1349 mAudioManager.adjustStreamVolume( 1350 stream, AudioManager.ADJUST_TOGGLE_MUTE, 0); 1351 assertEquals("Apps without Notification policy access can't change ringer mode", 1352 RINGER_MODE_NORMAL, mAudioManager.getRingerMode()); 1353 } catch (SecurityException e) { 1354 } 1355 1356 try { 1357 mAudioManager.setStreamMute(stream, true); 1358 assertEquals("Apps without Notification policy access can't change ringer mode", 1359 RINGER_MODE_NORMAL, mAudioManager.getRingerMode()); 1360 } catch (SecurityException e) { 1361 } 1362 Utils.toggleNotificationPolicyAccess( 1363 mContext.getPackageName(), getInstrumentation(), true); 1364 testStreamMuting(stream); 1365 } 1366 } 1367 1368 @Test testMuteDndUnaffectedStreams()1369 public void testMuteDndUnaffectedStreams() throws Exception { 1370 assumeFalse(mSkipRingerTests); 1371 int[] streams = { 1372 STREAM_VOICE_CALL, 1373 STREAM_MUSIC, 1374 STREAM_ALARM 1375 }; 1376 1377 int muteAffectedStreams = System.getInt(mContext.getContentResolver(), 1378 System.MUTE_STREAMS_AFFECTED, 1379 // same defaults as in AudioService. Should be kept in sync. 1380 (1 << STREAM_MUSIC) | 1381 (1 << STREAM_RING) | 1382 (1 << STREAM_NOTIFICATION) | 1383 (1 << STREAM_SYSTEM) | 1384 (1 << STREAM_VOICE_CALL)); 1385 1386 Utils.toggleNotificationPolicyAccess( 1387 mContext.getPackageName(), getInstrumentation(), true); 1388 // This ensures we're out of vibrate or silent modes. 1389 mAudioManager.setRingerMode(RINGER_MODE_NORMAL); 1390 Utils.toggleNotificationPolicyAccess( 1391 mContext.getPackageName(), getInstrumentation(), false); 1392 for (int stream : streams) { 1393 // ensure each stream is on and turned up. 1394 mAudioManager.setStreamVolume(stream, 1395 mAudioManager.getStreamMaxVolume(stream), 1396 0); 1397 if (((1 << stream) & muteAffectedStreams) == 0) { 1398 mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_MUTE, 0); 1399 assertFalse("Stream " + stream + " should not be affected by mute.", 1400 mAudioManager.isStreamMute(stream)); 1401 mAudioManager.setStreamMute(stream, true); 1402 assertFalse("Stream " + stream + " should not be affected by mute.", 1403 mAudioManager.isStreamMute(stream)); 1404 mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_TOGGLE_MUTE, 1405 0); 1406 assertFalse("Stream " + stream + " should not be affected by mute.", 1407 mAudioManager.isStreamMute(stream)); 1408 continue; 1409 } 1410 testStreamMuting(stream); 1411 } 1412 } 1413 testStreamMuting(int stream)1414 private void testStreamMuting(int stream) { 1415 if (mSkipAutoVolumeTests) { 1416 // adjustStreamVolume is a no-op 1417 return; 1418 } 1419 getInstrumentation().getUiAutomation() 1420 .adoptShellPermissionIdentity(Manifest.permission.QUERY_AUDIO_STATE); 1421 1422 final int streamVolume = mAudioManager.getLastAudibleStreamVolume(stream); 1423 1424 // Voice call requires MODIFY_PHONE_STATE, so we should not be able to mute 1425 if (stream == STREAM_VOICE_CALL) { 1426 mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_MUTE, 0); 1427 assertFalse("Muting voice call stream (" + stream + ") should require " 1428 + "MODIFY_PHONE_STATE.", mAudioManager.isStreamMute(stream)); 1429 } else { 1430 mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_MUTE, 0); 1431 assertTrue("Muting stream " + stream + " failed.", 1432 mAudioManager.isStreamMute(stream)); 1433 1434 assertEquals(streamVolume, mAudioManager.getLastAudibleStreamVolume(stream)); 1435 1436 mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_UNMUTE, 0); 1437 assertFalse("Unmuting stream " + stream + " failed.", 1438 mAudioManager.isStreamMute(stream)); 1439 1440 assertEquals(streamVolume, mAudioManager.getLastAudibleStreamVolume(stream)); 1441 1442 mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_TOGGLE_MUTE, 0); 1443 assertTrue("Toggling mute on stream " + stream + " failed.", 1444 mAudioManager.isStreamMute(stream)); 1445 1446 assertEquals(streamVolume, mAudioManager.getLastAudibleStreamVolume(stream)); 1447 1448 mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_TOGGLE_MUTE, 0); 1449 assertFalse("Toggling mute on stream " + stream + " failed.", 1450 mAudioManager.isStreamMute(stream)); 1451 1452 assertEquals(streamVolume, mAudioManager.getLastAudibleStreamVolume(stream)); 1453 1454 mAudioManager.setStreamMute(stream, true); 1455 assertTrue("Muting stream " + stream + " using setStreamMute failed", 1456 mAudioManager.isStreamMute(stream)); 1457 1458 assertEquals(streamVolume, mAudioManager.getLastAudibleStreamVolume(stream)); 1459 1460 // mute it three more times to verify the ref counting is gone. 1461 mAudioManager.setStreamMute(stream, true); 1462 mAudioManager.setStreamMute(stream, true); 1463 mAudioManager.setStreamMute(stream, true); 1464 1465 mAudioManager.setStreamMute(stream, false); 1466 assertFalse("Unmuting stream " + stream + " using setStreamMute failed.", 1467 mAudioManager.isStreamMute(stream)); 1468 } 1469 assertEquals(streamVolume, mAudioManager.getLastAudibleStreamVolume(stream)); 1470 1471 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 1472 } 1473 1474 @Test testSetInvalidRingerMode()1475 public void testSetInvalidRingerMode() { 1476 int ringerMode = mAudioManager.getRingerMode(); 1477 mAudioManager.setRingerMode(-1337); 1478 assertEquals(ringerMode, mAudioManager.getRingerMode()); 1479 1480 mAudioManager.setRingerMode(-3007); 1481 assertEquals(ringerMode, mAudioManager.getRingerMode()); 1482 } 1483 1484 /** 1485 * Ensure adjusting volume when total silence zen mode is enabled does not affect 1486 * stream volumes. 1487 */ 1488 @Test testAdjustVolumeInTotalSilenceMode()1489 public void testAdjustVolumeInTotalSilenceMode() throws Exception { 1490 if (mSkipAutoVolumeTests) { 1491 // adjustStreamVolume is a no-op 1492 return; 1493 } 1494 assumeFalse(mSkipRingerTests); 1495 1496 final int SILENCE_VOL = 0; 1497 final int prevVol = mAudioManager.getStreamVolume(STREAM_MUSIC); 1498 Utils.toggleNotificationPolicyAccess(mContext.getPackageName(), getInstrumentation(), true); 1499 1500 // Set to silence 1501 setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_NONE); 1502 assertThat(mAudioManager.getStreamVolume(STREAM_MUSIC)).isEqualTo(SILENCE_VOL); 1503 1504 // Raise shouldn't work when silenced 1505 assertCallDoesNotChangeStreamVolume( 1506 () -> mAudioManager.adjustStreamVolume(STREAM_MUSIC, ADJUST_RAISE, 0 /* flags */), 1507 STREAM_MUSIC); 1508 1509 // Set the mode out of silence 1510 setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL); 1511 1512 // Volume should be back to normal 1513 assertThat(mAudioManager.getStreamVolume(STREAM_MUSIC)).isEqualTo(INIT_VOL); 1514 1515 final int MEDIA_DELTA = getVolumeDelta(mAudioManager.getStreamVolume(STREAM_MUSIC)); 1516 assertCallChangesStreamVolume( 1517 () -> mAudioManager.adjustStreamVolume(STREAM_MUSIC, ADJUST_RAISE, 0 /* flags */), 1518 STREAM_MUSIC, 1519 INIT_VOL + MEDIA_DELTA); 1520 } 1521 1522 @Test testAdjustVolumeInAlarmsOnlyMode()1523 public void testAdjustVolumeInAlarmsOnlyMode() throws Exception { 1524 assumeFalse(mSkipRingerTests); 1525 1526 Utils.toggleNotificationPolicyAccess( 1527 mContext.getPackageName(), getInstrumentation(), true); 1528 1529 setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALARMS); 1530 1531 int volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(STREAM_MUSIC)); 1532 1533 // Why should this go through? This call doesn't exit zen mode, for reasons... 1534 assertCallChangesStreamVolume( 1535 () -> mAudioManager.adjustStreamVolume(STREAM_MUSIC, ADJUST_RAISE, 0), 1536 STREAM_MUSIC, 1537 INIT_VOL + volumeDelta, 1538 "Changing music volume should work when in alarm only mode"); 1539 } 1540 1541 @Test testSetStreamVolumeInTotalSilenceMode()1542 public void testSetStreamVolumeInTotalSilenceMode() throws Exception { 1543 assumeFalse(mSkipRingerTests); 1544 Utils.toggleNotificationPolicyAccess( 1545 mContext.getPackageName(), getInstrumentation(), true); 1546 1547 setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_NONE); 1548 1549 // cannot adjust music, can adjust ringer since it could exit DND 1550 assertCallDoesNotChangeStreamVolume( 1551 () -> mAudioManager.setStreamVolume(STREAM_MUSIC, 7, 0), 1552 STREAM_MUSIC, 1553 "Should not be able to adjust media volume in Zen mode"); 1554 assertCallChangesStreamVolume( 1555 () -> mAudioManager.setStreamVolume(STREAM_RING, 7, 0), 1556 STREAM_RING, 1557 7, 1558 "Should be able to adjust ring volume in Zen mode"); 1559 } 1560 1561 @Test testSetStreamVolumeInAlarmsOnlyMode()1562 public void testSetStreamVolumeInAlarmsOnlyMode() throws Exception { 1563 assumeFalse(mSkipRingerTests); 1564 Utils.toggleNotificationPolicyAccess( 1565 mContext.getPackageName(), getInstrumentation(), true); 1566 1567 setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALARMS); 1568 1569 // can still adjust music and ring volume 1570 assertCallChangesStreamVolume( 1571 () -> mAudioManager.setStreamVolume(STREAM_MUSIC, 3, 0), 1572 STREAM_MUSIC, 1573 3, 1574 "Stream volume settable in alarm only zen"); 1575 assertCallChangesStreamVolume( 1576 () -> mAudioManager.setStreamVolume(STREAM_RING, 7, 0), 1577 STREAM_RING, 1578 7, 1579 "Stream volume settable in alarm only zen"); 1580 1581 } 1582 1583 @Test testSetStreamVolumeInPriorityOnlyMode()1584 public void testSetStreamVolumeInPriorityOnlyMode() throws Exception { 1585 assumeFalse(mSkipRingerTests); 1586 Utils.toggleNotificationPolicyAccess( 1587 mContext.getPackageName(), getInstrumentation(), true); 1588 1589 final int testRingerVol = getTestRingerVol(); 1590 1591 // disallow all sounds in priority only, turn on priority only DND 1592 mNm.setNotificationPolicy(new NotificationManager.Policy(0, 0 , 0)); 1593 setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY); 1594 1595 // attempt to change volume 1596 assertCallDoesNotChangeStreamVolume( 1597 () -> mAudioManager.setStreamVolume(STREAM_MUSIC, 3, 0), 1598 STREAM_MUSIC, 1599 "Should not be able to change MUSIC volume in priority zen"); 1600 assertCallDoesNotChangeStreamVolume( 1601 () -> mAudioManager.setStreamVolume(STREAM_ALARM, 5, 0), 1602 STREAM_ALARM, 1603 "Should not be able to change ALARM volume in priority zen"); 1604 1605 assertCallChangesStreamVolume( 1606 () -> mAudioManager.setStreamVolume(STREAM_RING, testRingerVol, 0), 1607 STREAM_RING, 1608 testRingerVol, 1609 "Should be able to set ring volume in zen"); 1610 1611 1612 // Turn off zen to evaluate stream vols following zen 1613 setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL); 1614 1615 assertEquals(INIT_VOL, mAudioManager.getStreamVolume(STREAM_MUSIC)); 1616 assertEquals(INIT_VOL, mAudioManager.getStreamVolume(STREAM_ALARM)); 1617 assertEquals(testRingerVol, mAudioManager.getStreamVolume(STREAM_RING)); 1618 } 1619 1620 @Test testAdjustVolumeInPriorityOnly()1621 public void testAdjustVolumeInPriorityOnly() throws Exception { 1622 assumeFalse(mSkipRingerTests); 1623 Utils.toggleNotificationPolicyAccess( 1624 mContext.getPackageName(), getInstrumentation(), true); 1625 1626 // disallow all sounds in priority only, turn on priority only DND, try to change volume 1627 mNm.setNotificationPolicy(new NotificationManager.Policy(0, 0, 0)); 1628 setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY); 1629 1630 1631 int volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(STREAM_RING)); 1632 assertCallDoesNotChangeStreamVolume( 1633 () -> mAudioManager.adjustStreamVolume(STREAM_MUSIC, ADJUST_RAISE, 0), 1634 STREAM_MUSIC, 1635 "Should not be able to set music vol in zen"); 1636 1637 assertCallDoesNotChangeStreamVolume( 1638 () -> mAudioManager.adjustStreamVolume(STREAM_ALARM, ADJUST_RAISE, 0), 1639 STREAM_ALARM, 1640 "Should not be able to set alarm vol in zen"); 1641 1642 assertCallChangesStreamVolume( 1643 () -> mAudioManager.adjustStreamVolume(STREAM_RING, ADJUST_RAISE, 0), 1644 STREAM_RING, 1645 INIT_VOL + volumeDelta, 1646 "Should be able to set ring volume in zen"); 1647 1648 // Turn off zen and make sure stream levels are still the same prior to zen 1649 // aside from ringer since ringer can exit dnd 1650 setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL); 1651 1652 assertEquals(INIT_VOL, mAudioManager.getStreamVolume(STREAM_MUSIC)); 1653 assertEquals(INIT_VOL, mAudioManager.getStreamVolume(STREAM_ALARM)); 1654 assertEquals(INIT_VOL + volumeDelta, mAudioManager.getStreamVolume(STREAM_RING)); 1655 } 1656 1657 @Test testPriorityOnlyMuteAll()1658 public void testPriorityOnlyMuteAll() throws Exception { 1659 assumeFalse(mSkipRingerTests); 1660 Utils.toggleNotificationPolicyAccess( 1661 mContext.getPackageName(), getInstrumentation(), true); 1662 Map<Integer, MuteStateTransition> expectedTransitions = Map.of( 1663 STREAM_MUSIC, new MuteStateTransition(false, true), 1664 STREAM_SYSTEM, new MuteStateTransition(false, true), 1665 STREAM_ALARM, new MuteStateTransition(false, true), 1666 // if channels cannot bypass DND, the Ringer stream should be muted, else it 1667 // shouldn't be muted 1668 STREAM_RING, new MuteStateTransition(false, !mAppsBypassingDnd)); 1669 1670 assertStreamMuteStateChange(() -> { 1671 // disallow all sounds in priority only, turn on priority only DND 1672 mNm.setNotificationPolicy(new NotificationManager.Policy(0, 0, 0)); 1673 setInterruptionFilter( NotificationManager.INTERRUPTION_FILTER_PRIORITY); 1674 }, 1675 expectedTransitions, 1676 "Priority mute all should mute all streams including ringer if" + 1677 "channels cannot bypass DND"); 1678 } 1679 1680 @Test testPriorityOnlyMediaAllowed()1681 public void testPriorityOnlyMediaAllowed() throws Exception { 1682 assumeFalse(mSkipRingerTests); 1683 Utils.toggleNotificationPolicyAccess( 1684 mContext.getPackageName(), getInstrumentation(), true); 1685 1686 Map<Integer, MuteStateTransition> expectedTransitions = Map.of( 1687 STREAM_MUSIC, new MuteStateTransition(false, false), 1688 STREAM_SYSTEM, new MuteStateTransition(false, true), 1689 STREAM_ALARM, new MuteStateTransition(false, true), 1690 STREAM_RING, new MuteStateTransition(false, !mAppsBypassingDnd)); 1691 assertStreamMuteStateChange(() -> { 1692 // allow only media in priority only 1693 mNm.setNotificationPolicy(new NotificationManager.Policy( 1694 NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA, 0, 0)); 1695 setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY); 1696 }, 1697 expectedTransitions, 1698 "Priority category media should leave media unmuted, and rest muted"); 1699 } 1700 1701 @Test testPriorityOnlySystemAllowed()1702 public void testPriorityOnlySystemAllowed() throws Exception { 1703 assumeFalse(mSkipRingerTests); 1704 Utils.toggleNotificationPolicyAccess( 1705 mContext.getPackageName(), getInstrumentation(), true); 1706 1707 Map<Integer, MuteStateTransition> expectedTransitions = Map.of( 1708 STREAM_MUSIC, new MuteStateTransition(false, true), 1709 STREAM_SYSTEM, new MuteStateTransition(false, false), 1710 STREAM_ALARM, new MuteStateTransition(false, true), 1711 STREAM_RING, new MuteStateTransition(false, false)); 1712 1713 assertStreamMuteStateChange(() -> { 1714 // allow only system in priority only 1715 mNm.setNotificationPolicy(new NotificationManager.Policy( 1716 NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM, 0, 0)); 1717 setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY); 1718 }, 1719 expectedTransitions, 1720 "PRIORITY_CATEGORY_SYSTEM should leave RING and SYSTEM unmuted"); 1721 } 1722 1723 @Test testPriorityOnlySystemDisallowedWithRingerMuted()1724 public void testPriorityOnlySystemDisallowedWithRingerMuted() throws Exception { 1725 assumeFalse(mSkipRingerTests); 1726 1727 Utils.toggleNotificationPolicyAccess( 1728 mContext.getPackageName(), getInstrumentation(), true); 1729 mNm.setNotificationPolicy( 1730 new NotificationManager.Policy( 1731 mOriginalNotificationPolicy.priorityCategories 1732 | NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS 1733 | NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA, 1734 mOriginalNotificationPolicy.priorityCallSenders, 1735 mOriginalNotificationPolicy.priorityMessageSenders)); 1736 1737 Map<Integer, MuteStateTransition> expectedSilentTransition = Map.of( 1738 STREAM_MUSIC, new MuteStateTransition(false, false), 1739 STREAM_SYSTEM, new MuteStateTransition(false, true), 1740 STREAM_ALARM, new MuteStateTransition(false, false), 1741 STREAM_RING, new MuteStateTransition(false, true)); 1742 1743 assertStreamMuteStateChange(() -> { 1744 mAudioManager.setStreamVolume(STREAM_RING, 0, 0); 1745 mAudioManager.setRingerMode(RINGER_MODE_SILENT); 1746 }, 1747 expectedSilentTransition, 1748 "RING/SYSTEM should be silenced by RINGER_MODE"); 1749 1750 Map<Integer, MuteStateTransition> expectedTransitions = Map.of( 1751 STREAM_MUSIC, new MuteStateTransition(false, true), 1752 STREAM_SYSTEM, new MuteStateTransition(true, true), 1753 STREAM_ALARM, new MuteStateTransition(false, true), 1754 STREAM_RING, new MuteStateTransition(true, true)); 1755 1756 assertStreamMuteStateChange(() -> { 1757 // allow only system in priority only 1758 mNm.setNotificationPolicy(new NotificationManager.Policy( 1759 NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM, 0, 0)); 1760 setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY); 1761 }, 1762 expectedTransitions, 1763 "SYSTEM/RING should stay muted if RINGER_MODE_SILENT entering zen"); 1764 } 1765 1766 @Test testPriorityOnlyAlarmsAllowed()1767 public void testPriorityOnlyAlarmsAllowed() throws Exception { 1768 assumeFalse(mSkipRingerTests); 1769 1770 Utils.toggleNotificationPolicyAccess( 1771 mContext.getPackageName(), getInstrumentation(), true); 1772 1773 Map<Integer, MuteStateTransition> expectedTransitions = Map.of( 1774 STREAM_MUSIC, new MuteStateTransition(false, true), 1775 STREAM_SYSTEM, new MuteStateTransition(false, true), 1776 STREAM_ALARM, new MuteStateTransition(false, false), 1777 // if channels cannot bypass DND, the Ringer stream should be muted, else it 1778 // shouldn't be muted 1779 STREAM_RING, new MuteStateTransition(false, !mAppsBypassingDnd)); 1780 1781 1782 assertStreamMuteStateChange(() -> { 1783 // allow only alarms in priority only 1784 mNm.setNotificationPolicy(new NotificationManager.Policy( 1785 NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS, 0, 0)); 1786 setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY); 1787 }, 1788 expectedTransitions, 1789 "Alarm stream should be unmuted, all others muted"); 1790 } 1791 1792 @Test testPriorityOnlyRingerAllowed()1793 public void testPriorityOnlyRingerAllowed() throws Exception { 1794 assumeFalse(mSkipRingerTests); 1795 1796 Utils.toggleNotificationPolicyAccess( 1797 mContext.getPackageName(), getInstrumentation(), true); 1798 1799 Map<Integer, MuteStateTransition> expectedTransitions = Map.of( 1800 STREAM_MUSIC, new MuteStateTransition(false, true), 1801 STREAM_SYSTEM, new MuteStateTransition(false, true), 1802 STREAM_ALARM, new MuteStateTransition(false, true), 1803 STREAM_RING, new MuteStateTransition(false, false)); 1804 1805 assertStreamMuteStateChange(() -> { 1806 // allow only reminders in priority only 1807 mNm.setNotificationPolicy(new NotificationManager.Policy( 1808 NotificationManager.Policy.PRIORITY_CATEGORY_REMINDERS, 0, 0)); 1809 setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY); 1810 }, 1811 expectedTransitions, 1812 "All streams except ring should be unmuted"); 1813 } 1814 1815 @Test testPriorityOnlyChannelsCanBypassDnd()1816 public void testPriorityOnlyChannelsCanBypassDnd() throws Exception { 1817 assumeFalse(mSkipRingerTests); 1818 1819 Utils.toggleNotificationPolicyAccess( 1820 mContext.getPackageName(), getInstrumentation(), true); 1821 1822 final String NOTIFICATION_CHANNEL_ID = "test_id_" + SystemClock.uptimeMillis(); 1823 NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "TEST", 1824 NotificationManager.IMPORTANCE_DEFAULT); 1825 try { 1826 1827 // create a channel that can bypass dnd 1828 channel.setBypassDnd(true); 1829 mNm.createNotificationChannel(channel); 1830 Map<Integer, MuteStateTransition> expectedTransitions = Map.of( 1831 STREAM_MUSIC, new MuteStateTransition(false, true), 1832 STREAM_SYSTEM, new MuteStateTransition(false, true), 1833 STREAM_ALARM, new MuteStateTransition(false, true), 1834 STREAM_RING, new MuteStateTransition(false, false)); 1835 1836 // allow nothing 1837 assertStreamMuteStateChange(() -> { 1838 mNm.setNotificationPolicy(new NotificationManager.Policy(0,0, 0)); 1839 setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY); 1840 }, 1841 expectedTransitions, 1842 "Ringer stream should not be muted." 1843 + " areChannelsBypassing=" 1844 + NotificationManager.getService().areChannelsBypassingDnd()); 1845 1846 // delete the channel that can bypass dnd 1847 Map<Integer, MuteStateTransition> expectedTransitionsDeleteChannel = Map.of( 1848 STREAM_MUSIC, new MuteStateTransition(true, true), 1849 STREAM_SYSTEM, new MuteStateTransition(true, true), 1850 STREAM_ALARM, new MuteStateTransition(true, true), 1851 // if channels cannot bypass DND, the Ringer stream should be muted, else it 1852 // shouldn't be muted 1853 STREAM_RING, new MuteStateTransition(false, !mAppsBypassingDnd)); 1854 1855 assertStreamMuteStateChange(() -> mNm.deleteNotificationChannel( 1856 NOTIFICATION_CHANNEL_ID), 1857 expectedTransitionsDeleteChannel, 1858 "Ringer stream should be muted if apps are not bypassing dnd" 1859 + " areChannelsBypassing=" 1860 + NotificationManager.getService().areChannelsBypassingDnd()); 1861 } finally { 1862 mNm.deleteNotificationChannel(NOTIFICATION_CHANNEL_ID); 1863 } 1864 } 1865 1866 @Test testAdjustVolumeWithIllegalDirection()1867 public void testAdjustVolumeWithIllegalDirection() throws Exception { 1868 if (mSkipAutoVolumeTests) { 1869 // adjustVolume is a no-op 1870 return; 1871 } 1872 // Call the method with illegal direction. System should not reboot. 1873 mAudioManager.adjustVolume(37, 0); 1874 } 1875 1876 @Test testGetStreamVolumeDbWithIllegalArguments()1877 public void testGetStreamVolumeDbWithIllegalArguments() throws Exception { 1878 Exception ex = null; 1879 // invalid stream type 1880 try { 1881 float gain = mAudioManager.getStreamVolumeDb(-100 /*streamType*/, 0, 1882 AudioDeviceInfo.TYPE_BUILTIN_SPEAKER); 1883 } catch (Exception e) { 1884 ex = e; // expected 1885 } 1886 assertNotNull("No exception was thrown for an invalid stream type", ex); 1887 assertEquals("Wrong exception thrown for invalid stream type", 1888 ex.getClass(), IllegalArgumentException.class); 1889 1890 // invalid volume index 1891 ex = null; 1892 try { 1893 float gain = mAudioManager.getStreamVolumeDb(STREAM_MUSIC, -101 /*volume*/, 1894 AudioDeviceInfo.TYPE_BUILTIN_SPEAKER); 1895 } catch (Exception e) { 1896 ex = e; // expected 1897 } 1898 assertNotNull("No exception was thrown for an invalid volume index", ex); 1899 assertEquals("Wrong exception thrown for invalid volume index", 1900 ex.getClass(), IllegalArgumentException.class); 1901 1902 // invalid out of range volume index 1903 ex = null; 1904 try { 1905 final int maxVol = mAudioManager.getStreamMaxVolume(STREAM_MUSIC); 1906 float gain = mAudioManager.getStreamVolumeDb(STREAM_MUSIC, maxVol + 1, 1907 AudioDeviceInfo.TYPE_BUILTIN_SPEAKER); 1908 } catch (Exception e) { 1909 ex = e; // expected 1910 } 1911 assertNotNull("No exception was thrown for an invalid out of range volume index", ex); 1912 assertEquals("Wrong exception thrown for invalid out of range volume index", 1913 ex.getClass(), IllegalArgumentException.class); 1914 1915 // invalid device type 1916 ex = null; 1917 try { 1918 float gain = mAudioManager.getStreamVolumeDb(STREAM_MUSIC, 0, 1919 -102 /*deviceType*/); 1920 } catch (Exception e) { 1921 ex = e; // expected 1922 } 1923 assertNotNull("No exception was thrown for an invalid device type", ex); 1924 assertEquals("Wrong exception thrown for invalid device type", 1925 ex.getClass(), IllegalArgumentException.class); 1926 1927 // invalid input device type 1928 ex = null; 1929 try { 1930 float gain = mAudioManager.getStreamVolumeDb(STREAM_MUSIC, 0, 1931 AudioDeviceInfo.TYPE_BUILTIN_MIC); 1932 } catch (Exception e) { 1933 ex = e; // expected 1934 } 1935 assertNotNull("No exception was thrown for an invalid input device type", ex); 1936 assertEquals("Wrong exception thrown for invalid input device type", 1937 ex.getClass(), IllegalArgumentException.class); 1938 } 1939 1940 @Test testGetStreamVolumeDb()1941 public void testGetStreamVolumeDb() throws Exception { 1942 for (int streamType : PUBLIC_STREAM_TYPES) { 1943 // verify mininum index is strictly inferior to maximum index 1944 final int minIndex = mAudioManager.getStreamMinVolume(streamType); 1945 final int maxIndex = mAudioManager.getStreamMaxVolume(streamType); 1946 assertTrue("Min vol index (" + minIndex + ") for stream " + streamType + " not inferior" 1947 + " to max vol index (" + maxIndex + ")", minIndex <= maxIndex); 1948 float prevGain = Float.NEGATIVE_INFINITY; 1949 // verify gain increases with the volume indices 1950 for (int idx = minIndex ; idx <= maxIndex ; idx++) { 1951 float gain = mAudioManager.getStreamVolumeDb(streamType, idx, 1952 AudioDeviceInfo.TYPE_BUILTIN_SPEAKER); 1953 assertTrue("Non-monotonically increasing gain at index " + idx + " for stream" 1954 + streamType, prevGain <= gain); 1955 prevGain = gain; 1956 } 1957 } 1958 } 1959 1960 @Test testAdjustSuggestedStreamVolumeWithIllegalArguments()1961 public void testAdjustSuggestedStreamVolumeWithIllegalArguments() throws Exception { 1962 // Call the method with illegal direction. System should not reboot. 1963 mAudioManager.adjustSuggestedStreamVolume(37, STREAM_MUSIC, 0); 1964 1965 // Call the method with illegal stream. System should not reboot. 1966 mAudioManager.adjustSuggestedStreamVolume(ADJUST_RAISE, 66747, 0); 1967 } 1968 1969 @CddTest(requirement="5.4.1/C-1-4") 1970 @Test testGetMicrophones()1971 public void testGetMicrophones() throws Exception { 1972 if (!mContext.getPackageManager().hasSystemFeature( 1973 PackageManager.FEATURE_MICROPHONE)) { 1974 return; 1975 } 1976 List<MicrophoneInfo> microphones = mAudioManager.getMicrophones(); 1977 assertTrue(microphones.size() > 0); 1978 for (int i = 0; i < microphones.size(); i++) { 1979 MicrophoneInfo microphone = microphones.get(i); 1980 Log.i(TAG, "deviceId:" + microphone.getDescription()); 1981 Log.i(TAG, "portId:" + microphone.getId()); 1982 Log.i(TAG, "type:" + microphone.getType()); 1983 Log.i(TAG, "address:" + microphone.getAddress()); 1984 Log.i(TAG, "deviceLocation:" + microphone.getLocation()); 1985 Log.i(TAG, "deviceGroup:" + microphone.getGroup() 1986 + " index:" + microphone.getIndexInTheGroup()); 1987 MicrophoneInfo.Coordinate3F position = microphone.getPosition(); 1988 Log.i(TAG, "position:" + position.x + " " + position.y + " " + position.z); 1989 MicrophoneInfo.Coordinate3F orientation = microphone.getOrientation(); 1990 Log.i(TAG, "orientation:" + orientation.x + " " 1991 + orientation.y + " " + orientation.z); 1992 Log.i(TAG, "frequencyResponse:" + microphone.getFrequencyResponse()); 1993 Log.i(TAG, "channelMapping:" + microphone.getChannelMapping()); 1994 Log.i(TAG, "sensitivity:" + microphone.getSensitivity()); 1995 Log.i(TAG, "max spl:" + microphone.getMaxSpl()); 1996 Log.i(TAG, "min spl:" + microphone.getMinSpl()); 1997 Log.i(TAG, "directionality:" + microphone.getDirectionality()); 1998 Log.i(TAG, "--------------"); 1999 } 2000 } 2001 2002 @Test testIsHapticPlaybackSupported()2003 public void testIsHapticPlaybackSupported() { 2004 // Calling the API to make sure it doesn't crash. 2005 Log.i(TAG, "isHapticPlaybackSupported: " + AudioManager.isHapticPlaybackSupported()); 2006 } 2007 2008 @Test testIsUltrasoundSupported()2009 public void testIsUltrasoundSupported() { 2010 // Calling the API to make sure it must crash due to no permission. 2011 try { 2012 mAudioManager.isUltrasoundSupported(); 2013 fail("isUltrasoundSupported must fail due to no permission"); 2014 } catch (SecurityException e) { 2015 } 2016 } 2017 2018 @Test testIsHotwordStreamSupported()2019 public void testIsHotwordStreamSupported() { 2020 // Validate API requires permission 2021 assertThrows(SecurityException.class, () -> mAudioManager.isHotwordStreamSupported(false)); 2022 assertThrows(SecurityException.class, () -> mAudioManager.isHotwordStreamSupported(true)); 2023 // Validate functionality when caller holds appropriate permissions 2024 InstrumentationRegistry.getInstrumentation() 2025 .getUiAutomation() 2026 .adoptShellPermissionIdentity( 2027 Manifest.permission.CAPTURE_AUDIO_HOTWORD); 2028 boolean result1 = mAudioManager.isHotwordStreamSupported(false); 2029 boolean result2 = mAudioManager.isHotwordStreamSupported(true); 2030 2031 InstrumentationRegistry.getInstrumentation() 2032 .getUiAutomation() 2033 .dropShellPermissionIdentity(); 2034 } 2035 2036 @Test testGetAudioHwSyncForSession()2037 public void testGetAudioHwSyncForSession() { 2038 // AudioManager.getAudioHwSyncForSession is not supported before S 2039 if (ApiLevelUtil.isAtMost(Build.VERSION_CODES.R)) { 2040 Log.i(TAG, "testGetAudioHwSyncForSession skipped, release: " + Build.VERSION.SDK_INT); 2041 return; 2042 } 2043 try { 2044 int sessionId = mAudioManager.generateAudioSessionId(); 2045 assertNotEquals("testGetAudioHwSyncForSession cannot get audio session ID", 2046 AudioManager.ERROR, sessionId); 2047 int hwSyncId = mAudioManager.getAudioHwSyncForSession(sessionId); 2048 Log.i(TAG, "getAudioHwSyncForSession: " + hwSyncId); 2049 } catch (UnsupportedOperationException e) { 2050 Log.i(TAG, "getAudioHwSyncForSession not supported"); 2051 } catch (Exception e) { 2052 fail("Unexpected exception thrown by getAudioHwSyncForSession: " + e); 2053 } 2054 } 2055 setInterruptionFilter(int filter)2056 private void setInterruptionFilter(int filter) throws Exception { 2057 // TODO (b/294941884) investigate uncommenting this 2058 /* 2059 assertWithMessage("Setting interruption filter relies on unset ringer mode") 2060 .that(mAudioManager.getRingerMode()) 2061 .isEqualTo(AudioManager.RINGER_MODE_NORMAL); 2062 */ 2063 2064 if (mNm.getCurrentInterruptionFilter() == filter) { 2065 return; 2066 } 2067 final int expectedRingerMode = switch(filter) { 2068 case NotificationManager.INTERRUPTION_FILTER_NONE, 2069 NotificationManager.INTERRUPTION_FILTER_PRIORITY, 2070 NotificationManager.INTERRUPTION_FILTER_ALARMS 2071 -> AudioManager.RINGER_MODE_SILENT; 2072 case NotificationManager.INTERRUPTION_FILTER_ALL -> AudioManager.RINGER_MODE_NORMAL; 2073 default -> throw new AssertionError("Unexpected notification type"); 2074 }; 2075 2076 2077 var future = mCancelRule.registerFuture(getFutureForIntent( 2078 mContext, 2079 AudioManager.RINGER_MODE_CHANGED_ACTION, 2080 i -> (i != null) 2081 && i.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1) 2082 == expectedRingerMode)); 2083 mNm.setInterruptionFilter(filter); 2084 var intent = future.get(FUTURE_WAIT_SECS, TimeUnit.SECONDS); 2085 } 2086 getVolumeDelta(int volume)2087 private int getVolumeDelta(int volume) { 2088 return 1; 2089 } 2090 getTestRingerVol()2091 private int getTestRingerVol() { 2092 final int currentRingVol = mAudioManager.getStreamVolume(STREAM_RING); 2093 final int maxRingVol = mAudioManager.getStreamMaxVolume(STREAM_RING); 2094 if (currentRingVol != maxRingVol) { 2095 return maxRingVol; 2096 } else { 2097 return maxRingVol - 1; 2098 } 2099 } 2100 2101 @Test testAllowedCapturePolicy()2102 public void testAllowedCapturePolicy() throws Exception { 2103 final int policy = mAudioManager.getAllowedCapturePolicy(); 2104 assertEquals("Wrong default capture policy", AudioAttributes.ALLOW_CAPTURE_BY_ALL, policy); 2105 2106 for (int setPolicy : new int[] { AudioAttributes.ALLOW_CAPTURE_BY_NONE, 2107 AudioAttributes.ALLOW_CAPTURE_BY_SYSTEM, 2108 AudioAttributes.ALLOW_CAPTURE_BY_ALL}) { 2109 mAudioManager.setAllowedCapturePolicy(setPolicy); 2110 final int getPolicy = mAudioManager.getAllowedCapturePolicy(); 2111 assertEquals("Allowed capture policy doesn't match", setPolicy, getPolicy); 2112 } 2113 } 2114 2115 @Test testIsHdmiSystemAudidoSupported()2116 public void testIsHdmiSystemAudidoSupported() { 2117 // just make sure the call works 2118 boolean isSupported = mAudioManager.isHdmiSystemAudioSupported(); 2119 Log.d(TAG, "isHdmiSystemAudioSupported() = " + isSupported); 2120 } 2121 2122 @Test testIsBluetoothScoAvailableOffCall()2123 public void testIsBluetoothScoAvailableOffCall() { 2124 // just make sure the call works 2125 boolean isSupported = mAudioManager.isBluetoothScoAvailableOffCall(); 2126 Log.d(TAG, "isBluetoothScoAvailableOffCall() = " + isSupported); 2127 } 2128 2129 @Test testStartStopBluetoothSco()2130 public void testStartStopBluetoothSco() { 2131 mAudioManager.startBluetoothSco(); 2132 mAudioManager.stopBluetoothSco(); 2133 } 2134 2135 @Test testStartStopBluetoothScoVirtualCall()2136 public void testStartStopBluetoothScoVirtualCall() { 2137 mAudioManager.startBluetoothScoVirtualCall(); 2138 mAudioManager.stopBluetoothSco(); 2139 } 2140 2141 @Test testGetAdditionalOutputDeviceDelay()2142 public void testGetAdditionalOutputDeviceDelay() { 2143 AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL); 2144 for (AudioDeviceInfo device : devices) { 2145 long delay = mAudioManager.getAdditionalOutputDeviceDelay(device); 2146 assertTrue("getAdditionalOutputDeviceDelay() = " + delay +" (should be >= 0)", 2147 delay >= 0); 2148 delay = mAudioManager.getMaxAdditionalOutputDeviceDelay(device); 2149 assertTrue("getMaxAdditionalOutputDeviceDelay() = " + delay +" (should be >= 0)", 2150 delay >= 0); 2151 } 2152 } 2153 2154 static class MyPrevDevForStrategyListener implements 2155 AudioManager.OnPreferredDevicesForStrategyChangedListener { 2156 @Override onPreferredDevicesForStrategyChanged(AudioProductStrategy strategy, List<AudioDeviceAttributes> devices)2157 public void onPreferredDevicesForStrategyChanged(AudioProductStrategy strategy, 2158 List<AudioDeviceAttributes> devices) { 2159 fail("onPreferredDevicesForStrategyChanged must not be called"); 2160 } 2161 } 2162 2163 @Test testPreferredDevicesForStrategy()2164 public void testPreferredDevicesForStrategy() { 2165 // setPreferredDeviceForStrategy 2166 AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS); 2167 if (devices.length <= 0) { 2168 Log.i(TAG, "Skip testPreferredDevicesForStrategy as there is no output device"); 2169 return; 2170 } 2171 final AudioDeviceAttributes ada = new AudioDeviceAttributes(devices[0]); 2172 2173 final AudioAttributes mediaAttr = new AudioAttributes.Builder().setUsage( 2174 AudioAttributes.USAGE_MEDIA).build(); 2175 final List<AudioProductStrategy> strategies = 2176 AudioProductStrategy.getAudioProductStrategies(); 2177 AudioProductStrategy strategyForMedia = null; 2178 for (AudioProductStrategy strategy : strategies) { 2179 if (strategy.supportsAudioAttributes(mediaAttr)) { 2180 strategyForMedia = strategy; 2181 break; 2182 } 2183 } 2184 if (strategyForMedia == null) { 2185 Log.i(TAG, "Skip testPreferredDevicesForStrategy as there is no strategy for media"); 2186 return; 2187 } 2188 Log.i(TAG, "Found strategy " + strategyForMedia.getName() + " for media"); 2189 try { 2190 mAudioManager.setPreferredDeviceForStrategy(strategyForMedia, ada); 2191 fail("setPreferredDeviceForStrategy must fail due to no permission"); 2192 } catch (SecurityException e) { 2193 } 2194 try { 2195 mAudioManager.getPreferredDeviceForStrategy(strategyForMedia); 2196 fail("getPreferredDeviceForStrategy must fail due to no permission"); 2197 } catch (SecurityException e) { 2198 } 2199 final List<AudioDeviceAttributes> adas = new ArrayList<>(); 2200 adas.add(ada); 2201 try { 2202 mAudioManager.setPreferredDevicesForStrategy(strategyForMedia, adas); 2203 fail("setPreferredDevicesForStrategy must fail due to no permission"); 2204 } catch (SecurityException e) { 2205 } 2206 try { 2207 mAudioManager.getPreferredDevicesForStrategy(strategyForMedia); 2208 fail("getPreferredDevicesForStrategy must fail due to no permission"); 2209 } catch (SecurityException e) { 2210 } 2211 MyPrevDevForStrategyListener listener = new MyPrevDevForStrategyListener(); 2212 try { 2213 mAudioManager.addOnPreferredDevicesForStrategyChangedListener( 2214 Executors.newSingleThreadExecutor(), listener); 2215 fail("addOnPreferredDevicesForStrategyChangedListener must fail due to no permission"); 2216 } catch (SecurityException e) { 2217 } 2218 try { 2219 // removeOnPreferredDevicesForStrategyChangedListener should throw on non-registered 2220 // listener. 2221 mAudioManager.removeOnPreferredDevicesForStrategyChangedListener(listener); 2222 fail("removeOnPreferredDevicesForStrategyChangedListener must fail on bad listener"); 2223 } catch (IllegalArgumentException e) { 2224 } 2225 } 2226 2227 static class MyPrevDevicesForCapturePresetChangedListener implements 2228 AudioManager.OnPreferredDevicesForCapturePresetChangedListener { 2229 @Override onPreferredDevicesForCapturePresetChanged( int capturePreset, List<AudioDeviceAttributes> devices)2230 public void onPreferredDevicesForCapturePresetChanged( 2231 int capturePreset, List<AudioDeviceAttributes> devices) { 2232 fail("onPreferredDevicesForCapturePresetChanged must not be called"); 2233 } 2234 } 2235 2236 @Test testPreferredDeviceForCapturePreset()2237 public void testPreferredDeviceForCapturePreset() { 2238 AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS); 2239 if (devices.length <= 0) { 2240 Log.i(TAG, "Skip testPreferredDevicesForStrategy as there is no input device"); 2241 return; 2242 } 2243 final AudioDeviceAttributes ada = new AudioDeviceAttributes(devices[0]); 2244 2245 try { 2246 mAudioManager.setPreferredDeviceForCapturePreset(MediaRecorder.AudioSource.MIC, ada); 2247 fail("setPreferredDeviceForCapturePreset must fail due to no permission"); 2248 } catch (SecurityException e) { 2249 } 2250 try { 2251 mAudioManager.getPreferredDevicesForCapturePreset(MediaRecorder.AudioSource.MIC); 2252 fail("getPreferredDevicesForCapturePreset must fail due to no permission"); 2253 } catch (SecurityException e) { 2254 } 2255 try { 2256 mAudioManager.clearPreferredDevicesForCapturePreset(MediaRecorder.AudioSource.MIC); 2257 fail("clearPreferredDevicesForCapturePreset must fail due to no permission"); 2258 } catch (SecurityException e) { 2259 } 2260 MyPrevDevicesForCapturePresetChangedListener listener = 2261 new MyPrevDevicesForCapturePresetChangedListener(); 2262 try { 2263 mAudioManager.addOnPreferredDevicesForCapturePresetChangedListener( 2264 Executors.newSingleThreadExecutor(), listener); 2265 fail("addOnPreferredDevicesForCapturePresetChangedListener must fail" 2266 + "due to no permission"); 2267 } catch (SecurityException e) { 2268 } 2269 // There is not listener added at server side. Nothing to remove. 2270 mAudioManager.removeOnPreferredDevicesForCapturePresetChangedListener(listener); 2271 } 2272 2273 @Test testGetDevices()2274 public void testGetDevices() { 2275 AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL); 2276 for (AudioDeviceInfo device : devices) { 2277 Set<Integer> formats = IntStream.of(device.getEncodings()).boxed() 2278 .collect(Collectors.toSet()); 2279 Set<Integer> channelMasks = IntStream.of(device.getChannelMasks()).boxed() 2280 .collect(Collectors.toSet()); 2281 Set<Integer> channelIndexMasks = IntStream.of(device.getChannelIndexMasks()).boxed() 2282 .collect(Collectors.toSet()); 2283 Set<Integer> sampleRates = IntStream.of(device.getSampleRates()).boxed() 2284 .collect(Collectors.toSet()); 2285 HashSet<Integer> formatsFromProfile = new HashSet<>(); 2286 HashSet<Integer> channelMasksFromProfile = new HashSet<>(); 2287 HashSet<Integer> channelIndexMasksFromProfile = new HashSet<>(); 2288 HashSet<Integer> sampleRatesFromProfile = new HashSet<>(); 2289 for (AudioProfile profile : device.getAudioProfiles()) { 2290 formatsFromProfile.add(profile.getFormat()); 2291 channelMasksFromProfile.addAll(Arrays.stream(profile.getChannelMasks()).boxed() 2292 .collect(Collectors.toList())); 2293 channelIndexMasksFromProfile.addAll(Arrays.stream(profile.getChannelIndexMasks()) 2294 .boxed().collect(Collectors.toList())); 2295 sampleRatesFromProfile.addAll(Arrays.stream(profile.getSampleRates()).boxed() 2296 .collect(Collectors.toList())); 2297 assertTrue(ALL_ENCAPSULATION_TYPES.contains(profile.getEncapsulationType())); 2298 } 2299 for (AudioDescriptor descriptor : device.getAudioDescriptors()) { 2300 assertNotEquals(AudioDescriptor.STANDARD_NONE, descriptor.getStandard()); 2301 assertNotNull(descriptor.getDescriptor()); 2302 assertTrue( 2303 ALL_KNOWN_ENCAPSULATION_TYPES.contains(descriptor.getEncapsulationType())); 2304 } 2305 assertEquals(formats, formatsFromProfile); 2306 assertEquals(channelMasks, channelMasksFromProfile); 2307 assertEquals(channelIndexMasks, channelIndexMasksFromProfile); 2308 assertEquals(sampleRates, sampleRatesFromProfile); 2309 } 2310 } 2311 2312 @Test 2313 @RequiresFlagsEnabled(value = Flags.FLAG_SUPPORTED_DEVICE_TYPES_API) testGetSupportedDeviceTypes()2314 public void testGetSupportedDeviceTypes() { 2315 Set<Integer> deviceTypesOutputs = 2316 mAudioManager.getSupportedDeviceTypes(AudioManager.GET_DEVICES_OUTPUTS); 2317 assertNotEquals(deviceTypesOutputs, null); 2318 2319 if (AudioTestUtil.hasAudioOutput(mContext)) { 2320 assertNotEquals(deviceTypesOutputs.size(), 0); 2321 } else { 2322 assertEquals(deviceTypesOutputs.size(), 0); 2323 } 2324 2325 Set<Integer> deviceTypesInputs = 2326 mAudioManager.getSupportedDeviceTypes(AudioManager.GET_DEVICES_INPUTS); 2327 assertNotEquals(deviceTypesInputs, null); 2328 2329 if (AudioTestUtil.hasAudioInput(mContext)) { 2330 assertNotEquals(deviceTypesInputs.size(), 0); 2331 } else { 2332 // We can't really check this. 2333 // We are not sure of the equivalence of has "microphone" and "never support audio 2334 // inputs". For instance an android device could support input devices like HDMI IN 2335 // but not have a microphone. 2336 // assertEquals(deviceTypesInputs.size(), 0); 2337 } 2338 } 2339 2340 @Test testGetDirectPlaybackSupport()2341 public void testGetDirectPlaybackSupport() { 2342 assertEquals(AudioManager.DIRECT_PLAYBACK_NOT_SUPPORTED, 2343 AudioManager.getDirectPlaybackSupport( 2344 new AudioFormat.Builder().build(), 2345 new AudioAttributes.Builder().build())); 2346 AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS); 2347 AudioAttributes attr = new AudioAttributes.Builder() 2348 .setUsage(AudioAttributes.USAGE_MEDIA) 2349 .setLegacyStreamType(STREAM_MUSIC).build(); 2350 for (AudioDeviceInfo device : devices) { 2351 for (int encoding : device.getEncodings()) { 2352 for (int channelMask : device.getChannelMasks()) { 2353 for (int sampleRate : device.getSampleRates()) { 2354 AudioFormat format = new AudioFormat.Builder() 2355 .setEncoding(encoding) 2356 .setChannelMask(channelMask) 2357 .setSampleRate(sampleRate).build(); 2358 final int directPlaybackSupport = 2359 AudioManager.getDirectPlaybackSupport(format, attr); 2360 assertEquals( 2361 AudioTrack.isDirectPlaybackSupported(format, attr), 2362 directPlaybackSupport 2363 != AudioManager.DIRECT_PLAYBACK_NOT_SUPPORTED); 2364 if (directPlaybackSupport == AudioManager.DIRECT_PLAYBACK_NOT_SUPPORTED) { 2365 assertEquals( 2366 DIRECT_OFFLOAD_MAP.getOrDefault( 2367 AudioManager.getPlaybackOffloadSupport(format, attr), 2368 INVALID_DIRECT_PLAYBACK_MODE).intValue(), 2369 directPlaybackSupport); 2370 } else if ((directPlaybackSupport 2371 & AudioManager.DIRECT_PLAYBACK_OFFLOAD_SUPPORTED) 2372 != AudioManager.DIRECT_PLAYBACK_NOT_SUPPORTED) { 2373 // AudioManager.getPlaybackOffloadSupport can only query offload 2374 // support but not other direct support like passthrough. 2375 assertNotEquals( 2376 AudioManager.DIRECT_PLAYBACK_NOT_SUPPORTED, 2377 DIRECT_OFFLOAD_MAP.getOrDefault( 2378 AudioManager.getPlaybackOffloadSupport(format, attr), 2379 AudioManager.DIRECT_PLAYBACK_NOT_SUPPORTED) 2380 & directPlaybackSupport); 2381 } 2382 } 2383 } 2384 } 2385 } 2386 } 2387 2388 @AppModeFull(reason = "Instant apps cannot hold permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED") 2389 @Test testIndependentStreamTypes()2390 public void testIndependentStreamTypes() throws Exception { 2391 Log.i(TAG, "starting testIndependentStreamTypes"); 2392 getInstrumentation().getUiAutomation() 2393 .adoptShellPermissionIdentity(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED); 2394 try { 2395 final List<Integer> independentStreamTypes = mAudioManager.getIndependentStreamTypes(); 2396 assertNotNull("Null list of independent stream types", independentStreamTypes); 2397 final boolean usesGroups = mAudioManager.isVolumeControlUsingVolumeGroups(); 2398 Log.i(TAG, "testIndependentStreamTypes: usesGroups:" + usesGroups 2399 + " independentTypes" + independentStreamTypes); 2400 if (usesGroups) { 2401 assertTrue("Empty list of independent stream types with volume groups", 2402 independentStreamTypes.size() > 0); 2403 return; 2404 } 2405 assertTrue("Unexpected number of independent stream types " 2406 + independentStreamTypes.size(), independentStreamTypes.size() > 0); 2407 // verify independent streams are not aliased 2408 for (int indepStream : independentStreamTypes) { 2409 final int alias = mAudioManager.getStreamTypeAlias(indepStream); 2410 assertEquals("Independent stream " + indepStream + " has alias " + alias, 2411 indepStream, alias); 2412 } 2413 // verify aliased streams are not independent, and non-aliased streams are 2414 for (int stream : PUBLIC_STREAM_TYPES) { 2415 final int alias = mAudioManager.getStreamTypeAlias(stream); 2416 if (alias != stream) { 2417 assertFalse("Stream" + stream + " aliased to " + alias 2418 + " but marked independent", independentStreamTypes.contains(stream)); 2419 } else { 2420 // independent stream 2421 assertTrue("Stream " + stream 2422 + " has no alias but is not marked as independent", 2423 independentStreamTypes.contains(stream)); 2424 } 2425 } 2426 } finally { 2427 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 2428 } 2429 } 2430 2431 @AppModeFull(reason = "Instant apps cannot hold permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED") 2432 @Test testStreamTypeAliasChange()2433 public void testStreamTypeAliasChange() throws Exception { 2434 if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { 2435 Log.i(TAG, "skipping testStreamTypeAliasChange, not a phone"); 2436 return; 2437 } 2438 Log.i(TAG, "starting testStreamTypeAliasChange"); 2439 getInstrumentation().getUiAutomation() 2440 .adoptShellPermissionIdentity(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED); 2441 2442 // get initial state 2443 final int notifAliasAtStart = mAudioManager.getStreamTypeAlias(STREAM_NOTIFICATION); 2444 if (notifAliasAtStart != STREAM_NOTIFICATION && notifAliasAtStart != STREAM_RING) { 2445 // skipping test because it can't take advantage of the test API to modify 2446 // the notification alias 2447 Log.i(TAG, "skipping testStreamTypeAliasChange: NOTIFICATION aliased to stream " 2448 + notifAliasAtStart); 2449 return; 2450 } 2451 boolean notifAliasedToRingAtStart = (notifAliasAtStart == STREAM_RING); 2452 final MyBlockingRunnableListener streamAliasCb = new MyBlockingRunnableListener(); 2453 Runnable onStreamAliasChanged = () -> streamAliasCb.onSomeEventThatsExpected(); 2454 try { 2455 if (!notifAliasedToRingAtStart) { 2456 // if notif and ring are not aliased, they should each be independent streams 2457 final List<Integer> indies = mAudioManager.getIndependentStreamTypes(); 2458 assertTrue("NOTIFICATION not in independent streams " + indies, 2459 indies.contains(STREAM_NOTIFICATION)); 2460 assertTrue("RING not in independent streams " + indies, 2461 indies.contains(STREAM_RING)); 2462 } 2463 mAudioManager.addOnStreamAliasingChangedListener( 2464 Executors.newSingleThreadExecutor(), 2465 onStreamAliasChanged); 2466 mAudioManager.setNotifAliasRingForTest(!notifAliasedToRingAtStart); 2467 final String aliasing = notifAliasedToRingAtStart ? "unaliasing" : "aliasing"; 2468 assertTrue(aliasing + " RING and NOTIFICATION didn't trigger callback", 2469 streamAliasCb.waitForExpectedEvent(TIME_TO_WAIT_CALLBACK_MS)); 2470 final int expectedNotifAlias = notifAliasedToRingAtStart ? STREAM_NOTIFICATION 2471 : STREAM_RING; 2472 assertEquals("After " + aliasing + " alias incorrect", 2473 expectedNotifAlias, mAudioManager.getStreamTypeAlias(STREAM_NOTIFICATION)); 2474 if (notifAliasedToRingAtStart) { 2475 // if notif and ring were aliased, they should now be independent streams 2476 final List<Integer> indies = mAudioManager.getIndependentStreamTypes(); 2477 assertTrue("After alias change, NOTIFICATION not in independent streams " 2478 + indies, 2479 indies.contains(STREAM_NOTIFICATION)); 2480 assertTrue("After alias change, RING not in independent streams " + indies, 2481 indies.contains(STREAM_RING)); 2482 } 2483 2484 } finally { 2485 mAudioManager.setNotifAliasRingForTest(notifAliasedToRingAtStart); 2486 mAudioManager.removeOnStreamAliasingChangedListener(onStreamAliasChanged); 2487 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 2488 } 2489 } 2490 2491 @Test testAssistantUidRouting()2492 public void testAssistantUidRouting() { 2493 try { 2494 mAudioManager.addAssistantServicesUids(new int[0]); 2495 fail("addAssistantServicesUids must fail due to no permission"); 2496 } catch (SecurityException e) { 2497 } 2498 2499 try { 2500 mAudioManager.removeAssistantServicesUids(new int[0]); 2501 fail("removeAssistantServicesUids must fail due to no permission"); 2502 } catch (SecurityException e) { 2503 } 2504 2505 try { 2506 int[] uids = mAudioManager.getAssistantServicesUids(); 2507 fail("getAssistantServicesUids must fail due to no permission"); 2508 } catch (SecurityException e) { 2509 } 2510 2511 try { 2512 mAudioManager.setActiveAssistantServiceUids(new int[0]); 2513 fail("setActiveAssistantServiceUids must fail due to no permission"); 2514 } catch (SecurityException e) { 2515 } 2516 2517 try { 2518 int[] activeUids = mAudioManager.getActiveAssistantServicesUids(); 2519 fail("getActiveAssistantServicesUids must fail due to no permission"); 2520 } catch (SecurityException e) { 2521 } 2522 } 2523 2524 @AppModeFull(reason = "Instant apps cannot hold android.permission.MODIFY_AUDIO_ROUTING") 2525 @Test testBluetoothVariableLatency()2526 public void testBluetoothVariableLatency() throws Exception { 2527 assertThrows(SecurityException.class, 2528 () -> mAudioManager.supportsBluetoothVariableLatency()); 2529 assertThrows(SecurityException.class, 2530 () -> mAudioManager.setBluetoothVariableLatencyEnabled(false)); 2531 assertThrows(SecurityException.class, 2532 () -> mAudioManager.setBluetoothVariableLatencyEnabled(true)); 2533 assertThrows(SecurityException.class, 2534 () -> mAudioManager.isBluetoothVariableLatencyEnabled()); 2535 2536 getInstrumentation().getUiAutomation() 2537 .adoptShellPermissionIdentity(Manifest.permission.MODIFY_AUDIO_ROUTING); 2538 if (mAudioManager.supportsBluetoothVariableLatency()) { 2539 boolean savedEnabled = mAudioManager.isBluetoothVariableLatencyEnabled(); 2540 mAudioManager.setBluetoothVariableLatencyEnabled(false); 2541 assertFalse(mAudioManager.isBluetoothVariableLatencyEnabled()); 2542 mAudioManager.setBluetoothVariableLatencyEnabled(true); 2543 assertTrue(mAudioManager.isBluetoothVariableLatencyEnabled()); 2544 mAudioManager.setBluetoothVariableLatencyEnabled(savedEnabled); 2545 } 2546 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 2547 } 2548 2549 @Test testGetHalVersion()2550 public void testGetHalVersion() { 2551 AudioHalVersionInfo halVersion = AudioManager.getHalVersion(); 2552 assertNotEquals(null, halVersion); 2553 assertTrue( 2554 AudioHalVersionInfo.AUDIO_HAL_TYPE_AIDL == halVersion.getHalType() 2555 || AudioHalVersionInfo.AUDIO_HAL_TYPE_HIDL == halVersion.getHalType()); 2556 assertTrue(halVersion.getMajorVersion() > 0); 2557 assertTrue(halVersion.getMinorVersion() >= 0); 2558 } 2559 2560 @Test testPreferredMixerAttributes()2561 public void testPreferredMixerAttributes() throws Exception { 2562 final AudioAttributes attr = new AudioAttributes.Builder() 2563 .setUsage(AudioAttributes.USAGE_MEDIA).build(); 2564 final AudioMixerAttributes defaultMixerAttributes = new AudioMixerAttributes.Builder( 2565 new AudioFormat.Builder() 2566 .setEncoding(AudioFormat.ENCODING_PCM_16BIT) 2567 .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO) 2568 .setSampleRate(48000) 2569 .build()) 2570 .setMixerBehavior(AudioMixerAttributes.MIXER_BEHAVIOR_DEFAULT) 2571 .build(); 2572 2573 for (AudioDeviceInfo device : mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL)) { 2574 List<AudioMixerAttributes> supportedMixerAttributes = 2575 mAudioManager.getSupportedMixerAttributes(device); 2576 if (supportedMixerAttributes.isEmpty()) { 2577 // Setting preferred mixer attributes is not supported 2578 assertFalse(mAudioManager.setPreferredMixerAttributes( 2579 attr, device, defaultMixerAttributes)); 2580 } else { 2581 for (AudioMixerAttributes mixerAttr : supportedMixerAttributes) { 2582 ListenableFuture<Void> setMixerFuture = getMixerAttrChangedFuture(attr, 2583 device.getId()); 2584 assertNotNull(mixerAttr.getFormat()); 2585 assertTrue(ALL_MIXER_BEHAVIORS.contains(mixerAttr.getMixerBehavior())); 2586 assertTrue(mAudioManager.setPreferredMixerAttributes(attr, device, mixerAttr)); 2587 waitForMixerAttrChanged(setMixerFuture); 2588 ListenableFuture<Void> clearMixerFuture = getMixerAttrChangedFuture(attr, 2589 device.getId()); 2590 final AudioMixerAttributes mixerAttrFromQuery = 2591 mAudioManager.getPreferredMixerAttributes(attr, device); 2592 assertEquals(mixerAttr, mixerAttrFromQuery); 2593 assertTrue(mAudioManager.clearPreferredMixerAttributes(attr, device)); 2594 waitForMixerAttrChanged(clearMixerFuture); 2595 assertNull(mAudioManager.getPreferredMixerAttributes(attr, device)); 2596 } 2597 } 2598 } 2599 } 2600 2601 @Test testVolumeGroupHashCode()2602 public void testVolumeGroupHashCode() throws Exception { 2603 getInstrumentation().getUiAutomation().adoptShellPermissionIdentity( 2604 Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED); 2605 List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups(); 2606 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 2607 2608 List<AudioVolumeGroup> copyVolumeGroups = List.copyOf(audioVolumeGroups); 2609 for (AudioVolumeGroup avg : audioVolumeGroups) { 2610 final AudioVolumeGroup copiedGroup = copyVolumeGroups.stream().filter( 2611 group -> group.getId() == avg.getId()).findFirst().get(); 2612 assertTrue(avg.equals(copiedGroup)); 2613 assertEquals("hashCode doesn't return the same value twice for id " 2614 + avg.getId(), avg.hashCode(), avg.hashCode()); 2615 assertEquals("hashCode on the copied group doesn't return the same value for id " 2616 + avg.getId(), avg.hashCode(), copiedGroup.hashCode()); 2617 } 2618 } 2619 2620 @Test testAdjustVolumeGroupVolume()2621 public void testAdjustVolumeGroupVolume() { 2622 getInstrumentation().getUiAutomation().adoptShellPermissionIdentity( 2623 Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED, 2624 Manifest.permission.MODIFY_AUDIO_ROUTING, 2625 Manifest.permission.QUERY_AUDIO_STATE, 2626 Manifest.permission.MODIFY_PHONE_STATE); 2627 2628 List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups(); 2629 assertTrue(audioVolumeGroups.size() > 0); 2630 2631 final AudioAttributes callAa = new AudioAttributes.Builder() 2632 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION) 2633 .build(); 2634 int voiceCallVolumeGroup = mAudioManager.getVolumeGroupIdForAttributes(callAa); 2635 2636 assertNotEquals(voiceCallVolumeGroup, AudioVolumeGroup.DEFAULT_VOLUME_GROUP); 2637 2638 AudioVolumeGroupCallbackHelper vgCbReceiver = new AudioVolumeGroupCallbackHelper(); 2639 mAudioManager.registerVolumeGroupCallback(mContext.getMainExecutor(), vgCbReceiver); 2640 2641 try { 2642 // Validate Audio Volume Groups callback reception 2643 for (final AudioVolumeGroup audioVolumeGroup : audioVolumeGroups) { 2644 int volumeGroupId = audioVolumeGroup.getId(); 2645 int[] avgStreamTypes = audioVolumeGroup.getLegacyStreamTypes(); 2646 if (avgStreamTypes.length != 0) { 2647 // filters out bijective as API is dispatched to stream. 2648 // Following compatibility test will ensure API are dispatched 2649 continue; 2650 } 2651 int indexMax = mAudioManager.getVolumeGroupMaxVolumeIndex(volumeGroupId); 2652 int indexMin = mAudioManager.getVolumeGroupMinVolumeIndex(volumeGroupId); 2653 boolean isMutable = (indexMin == 0) || (volumeGroupId == voiceCallVolumeGroup); 2654 2655 // Set the receiver to filter only the current group callback 2656 int index = resetVolumeIndex(indexMin, indexMax); 2657 vgCbReceiver.setExpectedVolumeGroup(volumeGroupId); 2658 mAudioManager.setVolumeGroupVolumeIndex(volumeGroupId, index, 0/*flags*/); 2659 assertTrue(vgCbReceiver.waitForExpectedVolumeGroupChanged( 2660 AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS)); 2661 int readIndex = mAudioManager.getVolumeGroupVolumeIndex(volumeGroupId); 2662 assertEquals("Failed to set volume for group id " 2663 + volumeGroupId, readIndex, index); 2664 2665 while (index < indexMax) { 2666 vgCbReceiver.setExpectedVolumeGroup(volumeGroupId); 2667 mAudioManager.adjustVolumeGroupVolume( 2668 volumeGroupId, AudioManager.ADJUST_RAISE, 0/*flags*/); 2669 assertTrue(vgCbReceiver.waitForExpectedVolumeGroupChanged( 2670 AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS)); 2671 readIndex = mAudioManager.getVolumeGroupVolumeIndex(volumeGroupId); 2672 index += 1; 2673 assertEquals(readIndex, index); 2674 } 2675 // Max reached 2676 vgCbReceiver.setExpectedVolumeGroup(volumeGroupId); 2677 mAudioManager.adjustVolumeGroupVolume( 2678 volumeGroupId, AudioManager.ADJUST_RAISE, 0/*flags*/); 2679 assertTrue("Cb expected for group " 2680 + volumeGroupId, vgCbReceiver.waitForExpectedVolumeGroupChanged( 2681 AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS)); 2682 readIndex = mAudioManager.getVolumeGroupVolumeIndex(volumeGroupId); 2683 assertEquals(readIndex, indexMax); 2684 2685 while (index > indexMin) { 2686 vgCbReceiver.setExpectedVolumeGroup(volumeGroupId); 2687 mAudioManager.adjustVolumeGroupVolume( 2688 volumeGroupId, AudioManager.ADJUST_LOWER, 0/*flags*/); 2689 assertTrue(vgCbReceiver.waitForExpectedVolumeGroupChanged( 2690 AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS)); 2691 index -= 1; 2692 readIndex = mAudioManager.getVolumeGroupVolumeIndex(volumeGroupId); 2693 assertEquals("Failed to decrease volume for group id " 2694 + volumeGroupId, readIndex, index); 2695 } 2696 // Min reached 2697 vgCbReceiver.setExpectedVolumeGroup(volumeGroupId); 2698 mAudioManager.adjustVolumeGroupVolume( 2699 volumeGroupId, AudioManager.ADJUST_LOWER, 0/*flags*/); 2700 assertTrue("Cb expected for group " 2701 + volumeGroupId, vgCbReceiver.waitForExpectedVolumeGroupChanged( 2702 AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS)); 2703 readIndex = mAudioManager.getVolumeGroupVolumeIndex(volumeGroupId); 2704 assertEquals("Failed to decrease volume for group id " 2705 + volumeGroupId, readIndex, indexMin); 2706 2707 // Mute/Unmute 2708 if (isMutable) { 2709 int lastAudibleIndex; 2710 index = resetVolumeIndex(indexMin, indexMax); 2711 vgCbReceiver.setExpectedVolumeGroup(volumeGroupId); 2712 mAudioManager.setVolumeGroupVolumeIndex(volumeGroupId, index, 0/*flags*/); 2713 assertTrue(vgCbReceiver.waitForExpectedVolumeGroupChanged( 2714 AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS)); 2715 2716 readIndex = mAudioManager.getVolumeGroupVolumeIndex(volumeGroupId); 2717 assertEquals("Failed to set volume for group id " 2718 + volumeGroupId, readIndex, index); 2719 2720 lastAudibleIndex = 2721 mAudioManager.getLastAudibleVolumeForVolumeGroup(volumeGroupId); 2722 assertEquals(lastAudibleIndex, index); 2723 assertFalse(mAudioManager.isVolumeGroupMuted(volumeGroupId)); 2724 2725 // Mute 2726 vgCbReceiver.setExpectedVolumeGroup(volumeGroupId); 2727 mAudioManager.adjustVolumeGroupVolume( 2728 volumeGroupId, AudioManager.ADJUST_MUTE, 0/*flags*/); 2729 assertTrue(vgCbReceiver.waitForExpectedVolumeGroupChanged( 2730 AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS)); 2731 readIndex = mAudioManager.getVolumeGroupVolumeIndex(volumeGroupId); 2732 assertEquals("Failed to mute volume for group id " 2733 + volumeGroupId, readIndex, indexMin); 2734 assertEquals(lastAudibleIndex, 2735 mAudioManager.getLastAudibleVolumeForVolumeGroup(volumeGroupId)); 2736 assertTrue(mAudioManager.isVolumeGroupMuted(volumeGroupId)); 2737 2738 // Unmute 2739 vgCbReceiver.setExpectedVolumeGroup(volumeGroupId); 2740 mAudioManager.adjustVolumeGroupVolume( 2741 volumeGroupId, AudioManager.ADJUST_UNMUTE, 0/*flags*/); 2742 assertTrue(vgCbReceiver.waitForExpectedVolumeGroupChanged( 2743 AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS)); 2744 readIndex = mAudioManager.getVolumeGroupVolumeIndex(volumeGroupId); 2745 assertEquals("Failed to unmute volume for group id " 2746 + volumeGroupId, readIndex, lastAudibleIndex); 2747 assertEquals(lastAudibleIndex, 2748 mAudioManager.getLastAudibleVolumeForVolumeGroup(volumeGroupId)); 2749 assertFalse(mAudioManager.isVolumeGroupMuted(volumeGroupId)); 2750 2751 // Toggle Mute (from unmuted) 2752 vgCbReceiver.setExpectedVolumeGroup(volumeGroupId); 2753 mAudioManager.adjustVolumeGroupVolume( 2754 volumeGroupId, AudioManager.ADJUST_TOGGLE_MUTE, 0/*flags*/); 2755 assertTrue(vgCbReceiver.waitForExpectedVolumeGroupChanged( 2756 AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS)); 2757 readIndex = mAudioManager.getVolumeGroupVolumeIndex(volumeGroupId); 2758 assertEquals("Failed to mute volume for group id " 2759 + volumeGroupId, readIndex, indexMin); 2760 assertEquals(lastAudibleIndex, 2761 mAudioManager.getLastAudibleVolumeForVolumeGroup(volumeGroupId)); 2762 assertTrue(mAudioManager.isVolumeGroupMuted(volumeGroupId)); 2763 2764 // Toggle Mute (from muted) 2765 vgCbReceiver.setExpectedVolumeGroup(volumeGroupId); 2766 mAudioManager.adjustVolumeGroupVolume( 2767 volumeGroupId, AudioManager.ADJUST_TOGGLE_MUTE, 0/*flags*/); 2768 assertTrue(vgCbReceiver.waitForExpectedVolumeGroupChanged( 2769 AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS)); 2770 readIndex = mAudioManager.getVolumeGroupVolumeIndex(volumeGroupId); 2771 assertEquals("Failed to unmute volume for group id " 2772 + volumeGroupId, readIndex, lastAudibleIndex); 2773 assertEquals(lastAudibleIndex, 2774 mAudioManager.getLastAudibleVolumeForVolumeGroup(volumeGroupId)); 2775 assertFalse(mAudioManager.isVolumeGroupMuted(volumeGroupId)); 2776 } else { 2777 int lastAudibleIndex; 2778 index = resetVolumeIndex(indexMin, indexMax); 2779 vgCbReceiver.setExpectedVolumeGroup(volumeGroupId); 2780 mAudioManager.setVolumeGroupVolumeIndex(volumeGroupId, index, 0/*flags*/); 2781 assertTrue(vgCbReceiver.waitForExpectedVolumeGroupChanged( 2782 AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS)); 2783 readIndex = mAudioManager.getVolumeGroupVolumeIndex(volumeGroupId); 2784 assertEquals(readIndex, index); 2785 2786 lastAudibleIndex = 2787 mAudioManager.getLastAudibleVolumeForVolumeGroup(volumeGroupId); 2788 assertEquals(lastAudibleIndex, index); 2789 assertFalse(mAudioManager.isVolumeGroupMuted(volumeGroupId)); 2790 2791 // Mute 2792 vgCbReceiver.setExpectedVolumeGroup(volumeGroupId); 2793 mAudioManager.adjustVolumeGroupVolume( 2794 volumeGroupId, AudioManager.ADJUST_MUTE, 0/*flags*/); 2795 assertFalse(vgCbReceiver.waitForExpectedVolumeGroupChanged( 2796 AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS)); 2797 readIndex = mAudioManager.getVolumeGroupVolumeIndex(volumeGroupId); 2798 assertEquals("Unexpected volume mute for group id " + volumeGroupId 2799 + " readIndex=" + readIndex, readIndex, lastAudibleIndex); 2800 assertEquals(lastAudibleIndex, 2801 mAudioManager.getLastAudibleVolumeForVolumeGroup(volumeGroupId)); 2802 assertFalse(mAudioManager.isVolumeGroupMuted(volumeGroupId)); 2803 2804 // Unmute 2805 vgCbReceiver.setExpectedVolumeGroup(volumeGroupId); 2806 mAudioManager.adjustVolumeGroupVolume( 2807 volumeGroupId, AudioManager.ADJUST_UNMUTE, 0/*flags*/); 2808 assertFalse(vgCbReceiver.waitForExpectedVolumeGroupChanged( 2809 AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS)); 2810 readIndex = mAudioManager.getVolumeGroupVolumeIndex(volumeGroupId); 2811 assertEquals(readIndex, lastAudibleIndex); 2812 assertEquals(lastAudibleIndex, 2813 mAudioManager.getLastAudibleVolumeForVolumeGroup(volumeGroupId)); 2814 assertFalse(mAudioManager.isVolumeGroupMuted(volumeGroupId)); 2815 2816 // Toggle Mute (from unmuted) 2817 vgCbReceiver.setExpectedVolumeGroup(volumeGroupId); 2818 mAudioManager.adjustVolumeGroupVolume( 2819 volumeGroupId, AudioManager.ADJUST_TOGGLE_MUTE, 0/*flags*/); 2820 assertFalse(vgCbReceiver.waitForExpectedVolumeGroupChanged( 2821 AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS)); 2822 readIndex = mAudioManager.getVolumeGroupVolumeIndex(volumeGroupId); 2823 assertEquals(readIndex, lastAudibleIndex); 2824 assertEquals(lastAudibleIndex, 2825 mAudioManager.getLastAudibleVolumeForVolumeGroup(volumeGroupId)); 2826 assertFalse(mAudioManager.isVolumeGroupMuted(volumeGroupId)); 2827 2828 // Toggle Mute (from muted) 2829 vgCbReceiver.setExpectedVolumeGroup(volumeGroupId); 2830 mAudioManager.adjustVolumeGroupVolume( 2831 volumeGroupId, AudioManager.ADJUST_TOGGLE_MUTE, 0/*flags*/); 2832 assertFalse(vgCbReceiver.waitForExpectedVolumeGroupChanged( 2833 AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS)); 2834 readIndex = mAudioManager.getVolumeGroupVolumeIndex(volumeGroupId); 2835 assertEquals(readIndex, lastAudibleIndex); 2836 assertEquals(lastAudibleIndex, 2837 mAudioManager.getLastAudibleVolumeForVolumeGroup(volumeGroupId)); 2838 assertFalse(mAudioManager.isVolumeGroupMuted(volumeGroupId)); 2839 } 2840 } 2841 } finally { 2842 mAudioManager.unregisterVolumeGroupCallback(vgCbReceiver); 2843 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 2844 } 2845 } 2846 2847 // A helper class to let the test wait for AudioDeviceCallback functions to be called. The test 2848 // should call expectDevicesAdded/Removed to mark the interested events, then call 2849 // waitForDevicesAdded/Removed to block the thread and wait. Calling waitForDevicesAdded/Removed 2850 // will clear the interested events so that the test can call expectDevicesAdded/Removed again. 2851 private static class AudioDeviceCallbackHelper extends AudioDeviceCallback { 2852 MyBlockingRunnableListener mOnDevicesAdded; 2853 MyBlockingRunnableListener mOnDevicesRemoved; 2854 2855 @Override onAudioDevicesAdded(AudioDeviceInfo[] devices)2856 public void onAudioDevicesAdded(AudioDeviceInfo[] devices) { 2857 if (mOnDevicesAdded != null) { 2858 mOnDevicesAdded.onSomeEventThatsExpected(); 2859 } 2860 } 2861 2862 @Override onAudioDevicesRemoved(AudioDeviceInfo[] devices)2863 public void onAudioDevicesRemoved(AudioDeviceInfo[] devices) { 2864 if (mOnDevicesRemoved != null) { 2865 mOnDevicesRemoved.onSomeEventThatsExpected(); 2866 } 2867 } 2868 expectDevicesAdded()2869 void expectDevicesAdded() { 2870 mOnDevicesAdded = new MyBlockingRunnableListener(); 2871 } 2872 expectDevicesRemoved()2873 void expectDevicesRemoved() { 2874 mOnDevicesRemoved = new MyBlockingRunnableListener(); 2875 } 2876 waitForDevicesAdded()2877 void waitForDevicesAdded() { 2878 mOnDevicesAdded.waitForExpectedEvent(TIME_TO_WAIT_CALLBACK_MS); 2879 mOnDevicesAdded = null; 2880 } 2881 waitForDevicesRemoved()2882 void waitForDevicesRemoved() { 2883 mOnDevicesRemoved.waitForExpectedEvent(TIME_TO_WAIT_CALLBACK_MS); 2884 mOnDevicesRemoved = null; 2885 } 2886 } 2887 2888 @AppModeFull(reason = "Instant apps cannot hold android.permission.MODIFY_AUDIO_ROUTING") 2889 @Test testSetWiredDeviceConnectionState()2890 public void testSetWiredDeviceConnectionState() { 2891 final AudioDeviceAttributes ada = 2892 new AudioDeviceAttributes( 2893 AudioDeviceAttributes.ROLE_OUTPUT, 2894 AudioDeviceInfo.TYPE_IP, 2895 "1.2.3.4", 2896 "TestDeviceName", 2897 new ArrayList<>(), 2898 new ArrayList<>()); 2899 2900 // Calling the API without permission should fail. 2901 try { 2902 mAudioManager.setWiredDeviceConnectionState( 2903 ada, AudioManager.DEVICE_CONNECTION_STATE_DISCONNECTED); 2904 fail("setWiredDeviceConnectionState must fail due to no permission"); 2905 } catch (SecurityException e) { 2906 } 2907 2908 // The following test uses the attachable audio device that is already connected to the DUT, 2909 // because connecting a non exist audio device may cause failures at the HAL layer. 2910 final AudioDeviceAttributes device = findDetachableOutputDevice(); 2911 if (device == null) { 2912 Log.i( 2913 TAG, 2914 "Can't find suitable output device, skip the" 2915 + " testSetWiredDeviceConnectionState"); 2916 return; 2917 } 2918 2919 HandlerThread workerThread = new HandlerThread("worker"); 2920 2921 AudioDeviceCallbackHelper callbackHelper = new AudioDeviceCallbackHelper(); 2922 2923 try { 2924 getInstrumentation() 2925 .getUiAutomation() 2926 .adoptShellPermissionIdentity(Manifest.permission.MODIFY_AUDIO_ROUTING); 2927 2928 workerThread.start(); 2929 2930 // Consume the first onAudioDevicesAdded callback. 2931 callbackHelper.expectDevicesAdded(); 2932 mAudioManager.registerAudioDeviceCallback( 2933 callbackHelper, workerThread.getThreadHandler()); 2934 callbackHelper.waitForDevicesAdded(); 2935 2936 // Test disconnect device. 2937 callbackHelper.expectDevicesRemoved(); 2938 mAudioManager.setWiredDeviceConnectionState( 2939 device, AudioManager.DEVICE_CONNECTION_STATE_DISCONNECTED); 2940 callbackHelper.waitForDevicesRemoved(); 2941 2942 assertFalse( 2943 Arrays.asList(mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)) 2944 .stream() 2945 .anyMatch(d -> d.getType() == device.getType())); 2946 2947 // Test connect device. 2948 callbackHelper.expectDevicesAdded(); 2949 mAudioManager.setWiredDeviceConnectionState( 2950 device, AudioManager.DEVICE_CONNECTION_STATE_CONNECTED); 2951 callbackHelper.waitForDevicesAdded(); 2952 2953 assertTrue( 2954 Arrays.asList(mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)) 2955 .stream() 2956 .anyMatch(d -> d.getType() == device.getType())); 2957 2958 } finally { 2959 mAudioManager.unregisterAudioDeviceCallback(callbackHelper); 2960 workerThread.quit(); 2961 2962 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 2963 } 2964 } 2965 findDetachableOutputDevice()2966 private AudioDeviceAttributes findDetachableOutputDevice() { 2967 Set<Integer> supportedTypes = 2968 mAudioManager.getSupportedDeviceTypes(AudioManager.GET_DEVICES_OUTPUTS); 2969 2970 AudioDeviceInfo[] attachedDevices = 2971 mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS); 2972 HashSet<Integer> attachedTypes = new HashSet<>(); 2973 for (AudioDeviceInfo attachedDevice : attachedDevices) { 2974 attachedTypes.add(attachedDevice.getType()); 2975 } 2976 2977 for (int deviceType : 2978 new int[] { 2979 AudioDeviceInfo.TYPE_HDMI, 2980 AudioDeviceInfo.TYPE_WIRED_HEADSET, 2981 AudioDeviceInfo.TYPE_USB_DEVICE 2982 }) { 2983 if (!supportedTypes.contains(deviceType) || !attachedTypes.contains(deviceType)) { 2984 continue; 2985 } 2986 2987 return new AudioDeviceAttributes( 2988 AudioDeviceAttributes.ROLE_OUTPUT, 2989 deviceType, 2990 "", 2991 "TestDeviceName", 2992 new ArrayList<>(), 2993 new ArrayList<>()); 2994 } 2995 2996 return null; 2997 } 2998 waitForMixerAttrChanged(ListenableFuture<Void> future)2999 private void waitForMixerAttrChanged(ListenableFuture<Void> future) 3000 throws Exception { 3001 future.get(FUTURE_WAIT_SECS, TimeUnit.SECONDS); 3002 } 3003 getMixerAttrChangedFuture(AudioAttributes audioAttributes, int deviceId)3004 private ListenableFuture<Void> getMixerAttrChangedFuture(AudioAttributes audioAttributes, 3005 int deviceId) { 3006 final ListenableFuture<Void> future = 3007 mCancelRule.registerFuture( 3008 getFutureForListener( 3009 listener -> 3010 mAudioManager.addOnPreferredMixerAttributesChangedListener( 3011 MoreExecutors.directExecutor(), listener), 3012 mAudioManager::removeOnPreferredMixerAttributesChangedListener, 3013 (completer) -> 3014 (AudioAttributes aa, 3015 AudioDeviceInfo device, 3016 AudioMixerAttributes ma) -> { 3017 if (device.getId() == deviceId 3018 && Objects.equals(aa, audioAttributes)) { 3019 completer.set(null); 3020 } 3021 }, 3022 "Wait for mixer attr changed future")); 3023 return future; 3024 } 3025 assertCallChangesStreamVolume(Runnable r, int stream, int expectedVolume)3026 private void assertCallChangesStreamVolume(Runnable r, int stream, int expectedVolume) 3027 throws Exception { 3028 assertCallChangesStreamVolume(r, stream, expectedVolume, null); 3029 } 3030 assertCallChangesStreamVolume(Runnable r, int stream, int expectedVolume, String msg)3031 private void assertCallChangesStreamVolume(Runnable r, int stream, int expectedVolume, 3032 String msg) 3033 throws Exception { 3034 var initVol = mAudioManager.getStreamVolume(stream); 3035 assertWithMessage("Stream volume is already at desired") 3036 .that(initVol) 3037 .isNotEqualTo(expectedVolume); 3038 3039 var future = mCancelRule.registerFuture(getFutureForIntent( 3040 mContext, 3041 AudioManager.ACTION_VOLUME_CHANGED, 3042 i -> (i != null) 3043 && i.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1) 3044 == stream)); 3045 r.run(); 3046 var intent = future.get(FUTURE_WAIT_SECS, TimeUnit.SECONDS); 3047 String assertMessage = "Unexpected volume for stream " + stream + ". " 3048 + ((msg != null) ? msg : ""); 3049 // TODO prev volume from intent is not zeroed when moving out of zen 3050 /* 3051 assertWithMessage(assertMessage) 3052 .that(intent.getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, -1)) 3053 .isEqualTo(initVol); 3054 */ 3055 assertWithMessage(assertMessage) 3056 .that(intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1)) 3057 .isEqualTo(expectedVolume); 3058 assertWithMessage(assertMessage) 3059 .that(mAudioManager.getStreamVolume(stream)) 3060 .isEqualTo(expectedVolume); 3061 } 3062 assertCallDoesNotChangeStreamVolume(Runnable r, int stream)3063 private void assertCallDoesNotChangeStreamVolume(Runnable r, int stream) throws Exception { 3064 assertCallDoesNotChangeStreamVolume(r, stream, null); 3065 } 3066 assertCallDoesNotChangeStreamVolume(Runnable r, int stream, String message)3067 private void assertCallDoesNotChangeStreamVolume(Runnable r, int stream, String message) 3068 throws Exception { 3069 // It is hard to test a negative, but we will do our best 3070 final int initVol = mAudioManager.getStreamVolume(stream); 3071 // Set the volume to a known value 3072 3073 var future = mCancelRule.registerFuture(getFutureForIntent( 3074 mContext, 3075 AudioManager.ACTION_VOLUME_CHANGED, 3076 i -> (i != null) 3077 && i.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1) 3078 == stream)); 3079 r.run(); 3080 SystemClock.sleep(PROVE_NEGATIVE_DURATION_MS); 3081 AmUtils.waitForBroadcastBarrier(); 3082 assertThat(future.isDone()) 3083 .isFalse(); 3084 3085 assertWithMessage("Call expected to not change volume. " 3086 + ((message != null) ? message : "")) 3087 .that(mAudioManager.getStreamVolume(stream)) 3088 .isEqualTo(initVol); 3089 } 3090 waitForStreamVolumeSet(int stream, int expectedVolume)3091 private void waitForStreamVolumeSet(int stream, int expectedVolume) throws Exception { 3092 final var initVol = mAudioManager.getStreamVolume(stream); 3093 // Set the volume to a known value 3094 if (initVol != expectedVolume) { 3095 var future = mCancelRule.registerFuture(getFutureForIntent( 3096 mContext, 3097 AudioManager.ACTION_VOLUME_CHANGED, 3098 i -> (i != null) 3099 && i.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1) 3100 == stream)); 3101 mAudioManager.setStreamVolume(stream, 3102 expectedVolume, 0 /* flags */); 3103 assertThat(future.get(FUTURE_WAIT_SECS, TimeUnit.SECONDS) 3104 .getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1)) 3105 .isEqualTo(expectedVolume); 3106 } 3107 assertWithMessage("Failed to set stream volume for " + stream + " to " + expectedVolume) 3108 .that(mAudioManager.getStreamVolume(stream)) 3109 .isEqualTo(expectedVolume); 3110 3111 } 3112 3113 pollWithBackoff(BooleanSupplier isDone, long initialMs, long backoff, long maxBackoff, long timeout)3114 private void pollWithBackoff(BooleanSupplier isDone, long initialMs, 3115 long backoff, long maxBackoff, long timeout) { 3116 final long startTime = SystemClock.uptimeMillis(); 3117 long waitMs = initialMs; 3118 while (true) { 3119 if (isDone.getAsBoolean()) { 3120 return; 3121 } 3122 long timeLeft = timeout - (SystemClock.uptimeMillis() - startTime); 3123 if (timeLeft < 0) { 3124 throw new AssertionError("Polling timeout"); 3125 } 3126 waitMs = Math.min(Math.min(waitMs + backoff, maxBackoff), timeLeft); 3127 SystemClock.sleep(waitMs); 3128 } 3129 } 3130 createMuteFuture(int stream)3131 private ListenableFuture<Intent> createMuteFuture(int stream) { 3132 return mCancelRule.registerFuture(getFutureForIntent(mContext, 3133 "android.media.STREAM_MUTE_CHANGED_ACTION", 3134 i -> (i != null) && 3135 i.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1) == stream)); 3136 } 3137 MuteStateTransition(boolean before, boolean after)3138 private static record MuteStateTransition(boolean before, boolean after) {} 3139 3140 private static interface ThrowingRunnable { run()3141 public void run() throws Exception; 3142 } 3143 assertStreamMuteStateChange(ThrowingRunnable r, Map<Integer, MuteStateTransition> streamMuteMap, String msg)3144 private void assertStreamMuteStateChange(ThrowingRunnable r, 3145 Map<Integer, MuteStateTransition> streamMuteMap, 3146 String msg) 3147 throws Exception { 3148 3149 streamMuteMap.forEach( 3150 (Integer stream, MuteStateTransition mute) 3151 -> assertWithMessage(msg + " Initial stream mute state for " + stream + 3152 "does not correspond to expected mute state") 3153 .that(mAudioManager.isStreamMute(stream)) 3154 .isEqualTo(mute.before())); 3155 3156 ListenableFuture<List<Intent>> futures = null; 3157 List<ListenableFuture<Intent>> unchangedFutures = null; 3158 3159 futures = Futures.allAsList(streamMuteMap.entrySet().stream() 3160 .filter(e -> e.getValue().before() != e.getValue().after()) 3161 .map(e -> { 3162 return Futures.transform(createMuteFuture(e.getKey()), 3163 (Intent i) -> { 3164 assertWithMessage(msg + " Stream " + e.getKey() + " failed to mute") 3165 .that(i.getBooleanExtra( 3166 "android.media.EXTRA_STREAM_VOLUME_MUTED", 3167 false)) 3168 .isEqualTo(e.getValue().after()); 3169 return i; 3170 }, MoreExecutors.directExecutor()); 3171 }) 3172 .collect(Collectors.toList())); 3173 3174 unchangedFutures = streamMuteMap.entrySet().stream() 3175 .filter(e -> e.getValue().before() == e.getValue().after()) 3176 .map(e -> createMuteFuture(e.getKey())) 3177 .collect(Collectors.toList()); 3178 3179 r.run(); 3180 3181 SystemClock.sleep(PROVE_NEGATIVE_DURATION_MS); 3182 AmUtils.waitForBroadcastBarrier(); 3183 futures.get(FUTURE_WAIT_SECS, TimeUnit.SECONDS); 3184 3185 for (var f : unchangedFutures) { 3186 if (f.isDone()) { 3187 throw new AssertionError(msg + " Unexpected unmute: " + f.get()); 3188 } 3189 } 3190 3191 streamMuteMap.forEach( 3192 (Integer stream, MuteStateTransition mute) 3193 -> assertWithMessage(msg + " Final stream mute state for " + stream 3194 + " does not correspond to expected mute state") 3195 .that(mAudioManager.isStreamMute(stream)) 3196 .isEqualTo(mute.after())); 3197 } 3198 assertMusicActive(boolean expectedIsMusicActive)3199 private void assertMusicActive(boolean expectedIsMusicActive) throws Exception { 3200 final long startPoll = SystemClock.uptimeMillis(); 3201 boolean actualIsMusicActive = mAudioManager.isMusicActive(); 3202 while (SystemClock.uptimeMillis() - startPoll < POLL_TIME_PLAY_MUSIC 3203 && expectedIsMusicActive != actualIsMusicActive) { 3204 actualIsMusicActive = mAudioManager.isMusicActive(); 3205 } 3206 assertEquals(actualIsMusicActive, actualIsMusicActive); 3207 } 3208 3209 private static final long REPEATED_CHECK_POLL_PERIOD_MS = 100; // 100ms 3210 private static final long DEFAULT_ASYNC_CALL_TIMEOUT_MS = 5 * REPEATED_CHECK_POLL_PERIOD_MS; 3211 3212 /** 3213 * Makes multiple attempts over a given timeout period to test the predicate on an AudioManager 3214 * instance. Test success is evaluated against a true predicate result. 3215 * @param am the AudioManager instance to use for the test 3216 * @param predicate the test to run either until it returns true, or until the timeout expires 3217 * @param timeoutMs the maximum time allowed for the test to pass 3218 * @param errorString the string to be displayed in case of failure 3219 * @throws Exception 3220 */ assertTrueCheckTimeout(AudioManager am, Predicate<AudioManager> predicate, long timeoutMs, String errorString)3221 private void assertTrueCheckTimeout(AudioManager am, Predicate<AudioManager> predicate, 3222 long timeoutMs, String errorString) throws Exception { 3223 long checkStart = SystemClock.uptimeMillis(); 3224 boolean result = false; 3225 while (SystemClock.uptimeMillis() - checkStart < timeoutMs) { 3226 result = predicate.test(am); 3227 if (result) { 3228 break; 3229 } 3230 Thread.sleep(REPEATED_CHECK_POLL_PERIOD_MS); 3231 } 3232 assertTrue(errorString, result); 3233 } 3234 isAutomotive()3235 private boolean isAutomotive() { 3236 PackageManager pm = mContext.getPackageManager(); 3237 return pm.hasSystemFeature(pm.FEATURE_AUTOMOTIVE); 3238 } 3239 3240 // getParameters() & setParameters() are deprecated, so don't test 3241 3242 // setAdditionalOutputDeviceDelay(), getAudioVolumeGroups(), getVolumeIndexForAttributes() 3243 // getMinVolumeIndexForAttributes(), getMaxVolumeIndexForAttributes() & 3244 // setVolumeIndexForAttributes() require privledged permission MODIFY_AUDIO_ROUTING 3245 // and thus cannot be tested here. 3246 } 3247