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