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