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