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