blob: 5ba8f7e64fa8f0abff110be155f0a7607968742c [file] [log] [blame]
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.media.audio.cts;
import static android.media.AudioManager.ADJUST_LOWER;
import static android.media.AudioManager.ADJUST_RAISE;
import static android.media.AudioManager.ADJUST_SAME;
import static android.media.AudioManager.MODE_IN_CALL;
import static android.media.AudioManager.MODE_IN_COMMUNICATION;
import static android.media.AudioManager.MODE_NORMAL;
import static android.media.AudioManager.MODE_RINGTONE;
import static android.media.AudioManager.RINGER_MODE_NORMAL;
import static android.media.AudioManager.RINGER_MODE_SILENT;
import static android.media.AudioManager.RINGER_MODE_VIBRATE;
import static android.media.AudioManager.STREAM_ACCESSIBILITY;
import static android.media.AudioManager.STREAM_ALARM;
import static android.media.AudioManager.STREAM_DTMF;
import static android.media.AudioManager.STREAM_MUSIC;
import static android.media.AudioManager.STREAM_NOTIFICATION;
import static android.media.AudioManager.STREAM_RING;
import static android.media.AudioManager.STREAM_SYSTEM;
import static android.media.AudioManager.STREAM_VOICE_CALL;
import static android.media.AudioManager.USE_DEFAULT_STREAM_TYPE;
import static android.media.AudioManager.VIBRATE_SETTING_OFF;
import static android.media.AudioManager.VIBRATE_SETTING_ON;
import static android.media.AudioManager.VIBRATE_SETTING_ONLY_SILENT;
import static android.media.AudioManager.VIBRATE_TYPE_NOTIFICATION;
import static android.media.AudioManager.VIBRATE_TYPE_RINGER;
import static android.provider.Settings.Global.APPLY_RAMPING_RINGER;
import static android.provider.Settings.System.SOUND_EFFECTS_ENABLED;
import static org.junit.Assert.assertNotEquals;
import android.Manifest;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.media.AudioAttributes;
import android.media.AudioDescriptor;
import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceInfo;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioProfile;
import android.media.AudioTrack;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.media.MicrophoneInfo;
import android.media.audio.cts.R;
import android.media.audiopolicy.AudioProductStrategy;
import android.media.cts.NonMediaMainlineTest;
import android.media.cts.Utils;
import android.os.Build;
import android.os.SystemClock;
import android.os.Vibrator;
import android.platform.test.annotations.AppModeFull;
import android.provider.Settings;
import android.provider.Settings.System;
import android.test.InstrumentationTestCase;
import android.text.TextUtils;
import android.util.Log;
import android.view.SoundEffectConstants;
import androidx.test.InstrumentationRegistry;
import com.android.compatibility.common.util.ApiLevelUtil;
import com.android.compatibility.common.util.CddTest;
import com.android.compatibility.common.util.MediaUtils;
import com.android.compatibility.common.util.SettingsStateKeeperRule;
import com.android.internal.annotations.GuardedBy;
import org.junit.ClassRule;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@NonMediaMainlineTest
public class AudioManagerTest extends InstrumentationTestCase {
private final static String TAG = "AudioManagerTest";
private final static long ASYNC_TIMING_TOLERANCE_MS = 50;
private final static long POLL_TIME_VOLUME_ADJUST = 200;
private final static long POLL_TIME_UPDATE_INTERRUPTION_FILTER = 5000;
private final static int MP3_TO_PLAY = R.raw.testmp3; // ~ 5 second mp3
private final static long POLL_TIME_PLAY_MUSIC = 2000;
private final static long TIME_TO_PLAY = 2000;
private final static String APPOPS_OP_STR = "android:write_settings";
private final static Set<Integer> ALL_KNOWN_ENCAPSULATION_TYPES = new HashSet<>() {{
add(AudioProfile.AUDIO_ENCAPSULATION_TYPE_IEC61937);
}};
private final static Set<Integer> ALL_ENCAPSULATION_TYPES = new HashSet<>() {{
add(AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE);
add(AudioProfile.AUDIO_ENCAPSULATION_TYPE_IEC61937);
}};
private final static HashSet<Integer> ALL_AUDIO_STANDARDS = new HashSet<>() {{
add(AudioDescriptor.STANDARD_NONE);
add(AudioDescriptor.STANDARD_EDID);
}};
private static final HashMap<Integer, Integer> DIRECT_OFFLOAD_MAP = new HashMap<>() {{
put(AudioManager.PLAYBACK_OFFLOAD_NOT_SUPPORTED,
AudioManager.DIRECT_PLAYBACK_NOT_SUPPORTED);
put(AudioManager.PLAYBACK_OFFLOAD_SUPPORTED,
AudioManager.DIRECT_PLAYBACK_OFFLOAD_SUPPORTED);
put(AudioManager.PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED,
AudioManager.DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED);
}};
private static final int INVALID_DIRECT_PLAYBACK_MODE = -1;
private AudioManager mAudioManager;
private NotificationManager mNm;
private boolean mHasVibrator;
private boolean mUseFixedVolume;
private boolean mIsTelevision;
private boolean mIsSingleVolume;
private boolean mSkipRingerTests;
// From N onwards, ringer mode adjustments that toggle DND are not allowed unless
// package has DND access. Many tests in this package toggle DND access in order
// to get device out of the DND state for the test to proceed correctly.
// But DND access is disabled completely on low ram devices,
// so completely skip those tests here.
// These tests are migrated to CTS verifier tests to ensure test coverage.
private Context mContext;
private int mOriginalRingerMode;
private Map<Integer, Integer> mOriginalStreamVolumes = new HashMap<>();
private NotificationManager.Policy mOriginalNotificationPolicy;
private int mOriginalZen;
private boolean mDoNotCheckUnmute;
private boolean mAppsBypassingDnd;
@ClassRule
public static final SettingsStateKeeperRule mSurroundSoundFormatsSettingsKeeper =
new SettingsStateKeeperRule(InstrumentationRegistry.getTargetContext(),
Settings.Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS);
@ClassRule
public static final SettingsStateKeeperRule mSurroundSoundModeSettingsKeeper =
new SettingsStateKeeperRule(InstrumentationRegistry.getTargetContext(),
Settings.Global.ENCODED_SURROUND_OUTPUT);
@Override
protected void setUp() throws Exception {
super.setUp();
mContext = getInstrumentation().getContext();
Utils.enableAppOps(mContext.getPackageName(), APPOPS_OP_STR, getInstrumentation());
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
mAppsBypassingDnd = NotificationManager.getService().areChannelsBypassingDnd();
mHasVibrator = (vibrator != null) && vibrator.hasVibrator();
mUseFixedVolume = mContext.getResources().getBoolean(
Resources.getSystem().getIdentifier("config_useFixedVolume", "bool", "android"));
PackageManager packageManager = mContext.getPackageManager();
mIsTelevision = packageManager != null
&& (packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
|| packageManager.hasSystemFeature(PackageManager.FEATURE_TELEVISION));
mIsSingleVolume = mContext.getResources().getBoolean(
Resources.getSystem().getIdentifier("config_single_volume", "bool", "android"));
mSkipRingerTests = mUseFixedVolume || mIsTelevision || mIsSingleVolume;
// Store the original volumes that that they can be recovered in tearDown().
final int[] streamTypes = {
STREAM_VOICE_CALL,
STREAM_SYSTEM,
STREAM_RING,
STREAM_MUSIC,
STREAM_ALARM,
STREAM_NOTIFICATION,
STREAM_DTMF,
STREAM_ACCESSIBILITY,
};
mOriginalRingerMode = mAudioManager.getRingerMode();
for (int streamType : streamTypes) {
mOriginalStreamVolumes.put(streamType, mAudioManager.getStreamVolume(streamType));
}
try {
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
mOriginalNotificationPolicy = mNm.getNotificationPolicy();
mOriginalZen = mNm.getCurrentInterruptionFilter();
} finally {
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), false);
}
// Check original microphone mute/unmute status
mDoNotCheckUnmute = false;
if (mAudioManager.isMicrophoneMute()) {
mAudioManager.setMicrophoneMute(false);
if (mAudioManager.isMicrophoneMute()) {
Log.w(TAG, "Mic seems muted by hardware! Please unmute and rerrun the test.");
mDoNotCheckUnmute = true;
}
}
}
@Override
protected void tearDown() throws Exception {
try {
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
mNm.setNotificationPolicy(mOriginalNotificationPolicy);
setInterruptionFilter(mOriginalZen);
// Recover the volume and the ringer mode that the test may have overwritten.
for (Map.Entry<Integer, Integer> e : mOriginalStreamVolumes.entrySet()) {
mAudioManager.setStreamVolume(e.getKey(), e.getValue(),
AudioManager.FLAG_ALLOW_RINGER_MODES);
}
mAudioManager.setRingerMode(mOriginalRingerMode);
} finally {
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), false);
}
}
@AppModeFull(reason = "Instant apps cannot hold android.permission.MODIFY_AUDIO_SETTINGS")
public void testMicrophoneMute() throws Exception {
mAudioManager.setMicrophoneMute(true);
assertTrue(mAudioManager.isMicrophoneMute());
mAudioManager.setMicrophoneMute(false);
assertFalse(mAudioManager.isMicrophoneMute() && !mDoNotCheckUnmute);
}
@AppModeFull(reason = "Instant apps cannot hold android.permission.MODIFY_AUDIO_SETTINGS")
public void testMicrophoneMuteIntent() throws Exception {
if (!mDoNotCheckUnmute) {
final MyBlockingIntentReceiver receiver = new MyBlockingIntentReceiver(
AudioManager.ACTION_MICROPHONE_MUTE_CHANGED);
final boolean initialMicMute = mAudioManager.isMicrophoneMute();
try {
mContext.registerReceiver(receiver,
new IntentFilter(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED));
// change the mic mute state
mAudioManager.setMicrophoneMute(!initialMicMute);
// verify a change was reported
final boolean intentFired = receiver.waitForExpectedAction(500/*ms*/);
assertTrue("ACTION_MICROPHONE_MUTE_CHANGED wasn't fired", intentFired);
// verify the mic mute state is expected
final boolean newMicMute = mAudioManager.isMicrophoneMute();
assertTrue("new mic mute state not as expected (" + !initialMicMute + ")",
(newMicMute == !initialMicMute));
} finally {
mContext.unregisterReceiver(receiver);
mAudioManager.setMicrophoneMute(initialMicMute);
}
}
}
@AppModeFull(reason = "Instant apps cannot hold android.permission.MODIFY_AUDIO_SETTINGS")
public void testSpeakerphoneIntent() throws Exception {
// Speaker Phone Not supported in Automotive
if (isAutomotive()) {
return;
}
final MyBlockingIntentReceiver receiver = new MyBlockingIntentReceiver(
AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED);
final boolean initialSpeakerphoneState = mAudioManager.isSpeakerphoneOn();
try {
mContext.registerReceiver(receiver,
new IntentFilter(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED));
// change the speakerphone state
mAudioManager.setSpeakerphoneOn(!initialSpeakerphoneState);
// verify a change was reported
final boolean intentFired = receiver.waitForExpectedAction(500/*ms*/);
assertTrue("ACTION_SPEAKERPHONE_STATE_CHANGED wasn't fired", intentFired);
// verify the speakerphon state is expected
final boolean newSpeakerphoneState = mAudioManager.isSpeakerphoneOn();
assertTrue("new mic mute state not as expected ("
+ !initialSpeakerphoneState + ")",
newSpeakerphoneState == !initialSpeakerphoneState);
} finally {
mContext.unregisterReceiver(receiver);
mAudioManager.setSpeakerphoneOn(initialSpeakerphoneState);
}
}
private static final class MyBlockingIntentReceiver extends BroadcastReceiver {
private final SafeWaitObject mLock = new SafeWaitObject();
// the action for the intent to check
private final String mAction;
@GuardedBy("mLock")
private boolean mIntentReceived = false;
MyBlockingIntentReceiver(String action) {
mAction = action;
}
@Override
public void onReceive(Context context, Intent intent) {
if (!TextUtils.equals(intent.getAction(), mAction)) {
// move along, this is not the action we're looking for
return;
}
synchronized (mLock) {
mIntentReceived = true;
mLock.safeNotify();
}
}
public boolean waitForExpectedAction(long timeOutMs) {
synchronized (mLock) {
try {
mLock.safeWait(timeOutMs);
} catch (InterruptedException e) { }
return mIntentReceived;
}
}
}
public void testSoundEffects() throws Exception {
Settings.System.putInt(mContext.getContentResolver(), SOUND_EFFECTS_ENABLED, 1);
// should hear sound after loadSoundEffects() called.
mAudioManager.loadSoundEffects();
Thread.sleep(TIME_TO_PLAY);
float volume = 0.5f; // volume should be between 0.f to 1.f (or -1).
mAudioManager.playSoundEffect(SoundEffectConstants.CLICK);
mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP, volume);
mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN, volume);
mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT, volume);
mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT, volume);
// won't hear sound after unloadSoundEffects() called();
mAudioManager.unloadSoundEffects();
mAudioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP, volume);
mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN, volume);
mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT, volume);
mAudioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT, volume);
}
public void testCheckingZenModeBlockDoesNotRequireNotificationPolicyAccess() throws Exception {
try {
// set zen mode to priority only, so playSoundEffect will check notification policy
Utils.toggleNotificationPolicyAccess(mContext.getPackageName(), getInstrumentation(),
true);
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY);
Settings.System.putInt(mContext.getContentResolver(), SOUND_EFFECTS_ENABLED, 1);
// take away write-notification policy access from the package
Utils.toggleNotificationPolicyAccess(mContext.getPackageName(), getInstrumentation(),
false);
// playSoundEffect should NOT throw a security exception; all apps have read-access
mAudioManager.playSoundEffect(SoundEffectConstants.CLICK);
} finally {
Utils.toggleNotificationPolicyAccess(mContext.getPackageName(), getInstrumentation(),
true);
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
Utils.toggleNotificationPolicyAccess(mContext.getPackageName(), getInstrumentation(),
false);
}
}
public void testMusicActive() throws Exception {
if (mAudioManager.isMusicActive()) {
return;
}
MediaPlayer mp = MediaPlayer.create(mContext, MP3_TO_PLAY);
assertNotNull(mp);
mp.setAudioStreamType(STREAM_MUSIC);
mp.start();
assertMusicActive(true);
mp.stop();
mp.release();
assertMusicActive(false);
}
@AppModeFull(reason = "Instant apps cannot hold android.permission.MODIFY_AUDIO_SETTINGS")
public void testAccessMode() throws Exception {
mAudioManager.setMode(MODE_RINGTONE);
assertEquals(MODE_RINGTONE, mAudioManager.getMode());
mAudioManager.setMode(MODE_IN_COMMUNICATION);
assertEquals(MODE_IN_COMMUNICATION, mAudioManager.getMode());
mAudioManager.setMode(MODE_NORMAL);
assertEquals(MODE_NORMAL, mAudioManager.getMode());
}
public void testSetSurroundFormatEnabled() throws Exception {
getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
Manifest.permission.WRITE_SETTINGS);
int audioFormat = AudioFormat.ENCODING_DTS;
mAudioManager.setSurroundFormatEnabled(audioFormat, true /*enabled*/);
assertTrue(mAudioManager.isSurroundFormatEnabled(audioFormat));
mAudioManager.setSurroundFormatEnabled(audioFormat, false /*enabled*/);
assertFalse(mAudioManager.isSurroundFormatEnabled(audioFormat));
getInstrumentation().getUiAutomation().dropShellPermissionIdentity();
}
public void testSetEncodedSurroundMode() throws Exception {
getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
Manifest.permission.WRITE_SETTINGS);
int expectedSurroundFormatsMode = Settings.Global.ENCODED_SURROUND_OUTPUT_MANUAL;
mAudioManager.setEncodedSurroundMode(expectedSurroundFormatsMode);
assertEquals(expectedSurroundFormatsMode, mAudioManager.getEncodedSurroundMode());
expectedSurroundFormatsMode = Settings.Global.ENCODED_SURROUND_OUTPUT_NEVER;
mAudioManager.setEncodedSurroundMode(expectedSurroundFormatsMode);
assertEquals(expectedSurroundFormatsMode, mAudioManager.getEncodedSurroundMode());
getInstrumentation().getUiAutomation().dropShellPermissionIdentity();
}
@SuppressWarnings("deprecation")
@AppModeFull(reason = "Instant apps cannot hold android.permission.MODIFY_AUDIO_SETTINGS")
public void testRouting() throws Exception {
// setBluetoothA2dpOn is a no-op, and getRouting should always return -1
boolean oldA2DP = mAudioManager.isBluetoothA2dpOn();
mAudioManager.setBluetoothA2dpOn(true);
assertEquals(oldA2DP , mAudioManager.isBluetoothA2dpOn());
mAudioManager.setBluetoothA2dpOn(false);
assertEquals(oldA2DP , mAudioManager.isBluetoothA2dpOn());
assertEquals(-1, mAudioManager.getRouting(MODE_RINGTONE));
assertEquals(-1, mAudioManager.getRouting(MODE_NORMAL));
assertEquals(-1, mAudioManager.getRouting(MODE_IN_CALL));
assertEquals(-1, mAudioManager.getRouting(MODE_IN_COMMUNICATION));
mAudioManager.setBluetoothScoOn(true);
assertTrueCheckTimeout(mAudioManager, p -> p.isBluetoothScoOn(),
DEFAULT_ASYNC_CALL_TIMEOUT_MS, "isBluetoothScoOn returned false");
mAudioManager.setBluetoothScoOn(false);
assertTrueCheckTimeout(mAudioManager, p -> !p.isBluetoothScoOn(),
DEFAULT_ASYNC_CALL_TIMEOUT_MS, "isBluetoothScoOn returned true");
// Speaker Phone Not supported in Automotive
if (isAutomotive()) {
return;
}
mAudioManager.setSpeakerphoneOn(true);
assertTrueCheckTimeout(mAudioManager, p -> p.isSpeakerphoneOn(),
DEFAULT_ASYNC_CALL_TIMEOUT_MS, "isSpeakerPhoneOn() returned false");
mAudioManager.setSpeakerphoneOn(false);
assertTrueCheckTimeout(mAudioManager, p -> !p.isSpeakerphoneOn(),
DEFAULT_ASYNC_CALL_TIMEOUT_MS, "isSpeakerPhoneOn() returned true");
}
public void testVibrateNotification() throws Exception {
if (mUseFixedVolume || !mHasVibrator) {
return;
}
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
// VIBRATE_SETTING_ON
mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_ON);
assertEquals(mHasVibrator ? VIBRATE_SETTING_ON : VIBRATE_SETTING_OFF,
mAudioManager.getVibrateSetting(VIBRATE_TYPE_NOTIFICATION));
mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
mAudioManager.setRingerMode(RINGER_MODE_SILENT);
assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
mAudioManager.getRingerMode());
assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
// VIBRATE_SETTING_OFF
mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_OFF);
assertEquals(VIBRATE_SETTING_OFF,
mAudioManager.getVibrateSetting(VIBRATE_TYPE_NOTIFICATION));
mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
mAudioManager.setRingerMode(RINGER_MODE_SILENT);
assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
mAudioManager.getRingerMode());
assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
// VIBRATE_SETTING_ONLY_SILENT
mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_ONLY_SILENT);
assertEquals(mHasVibrator ? VIBRATE_SETTING_ONLY_SILENT : VIBRATE_SETTING_OFF,
mAudioManager.getVibrateSetting(VIBRATE_TYPE_NOTIFICATION));
mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
mAudioManager.setRingerMode(RINGER_MODE_SILENT);
assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
mAudioManager.getRingerMode());
assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_NOTIFICATION));
// VIBRATE_TYPE_NOTIFICATION
mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_ON);
assertEquals(mHasVibrator ? VIBRATE_SETTING_ON : VIBRATE_SETTING_OFF,
mAudioManager.getVibrateSetting(VIBRATE_TYPE_NOTIFICATION));
mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_OFF);
assertEquals(VIBRATE_SETTING_OFF, mAudioManager
.getVibrateSetting(VIBRATE_TYPE_NOTIFICATION));
mAudioManager.setVibrateSetting(VIBRATE_TYPE_NOTIFICATION, VIBRATE_SETTING_ONLY_SILENT);
assertEquals(mHasVibrator ? VIBRATE_SETTING_ONLY_SILENT : VIBRATE_SETTING_OFF,
mAudioManager.getVibrateSetting(VIBRATE_TYPE_NOTIFICATION));
}
public void testVibrateRinger() throws Exception {
if (mUseFixedVolume || !mHasVibrator) {
return;
}
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
// VIBRATE_TYPE_RINGER
mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_ON);
assertEquals(mHasVibrator ? VIBRATE_SETTING_ON : VIBRATE_SETTING_OFF,
mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER));
mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
mAudioManager.setRingerMode(RINGER_MODE_SILENT);
assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
mAudioManager.getRingerMode());
assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
// VIBRATE_SETTING_OFF
mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_OFF);
assertEquals(VIBRATE_SETTING_OFF, mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER));
mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
mAudioManager.setRingerMode(RINGER_MODE_SILENT);
assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
mAudioManager.getRingerMode());
// Note: as of Froyo, if VIBRATE_TYPE_RINGER is set to OFF, it will
// not vibrate, even in RINGER_MODE_VIBRATE. This allows users to
// disable the vibration for incoming calls only.
assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
// VIBRATE_SETTING_ONLY_SILENT
mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_ONLY_SILENT);
assertEquals(mHasVibrator ? VIBRATE_SETTING_ONLY_SILENT : VIBRATE_SETTING_OFF,
mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER));
mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
mAudioManager.setRingerMode(RINGER_MODE_SILENT);
assertFalse(mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
mAudioManager.getRingerMode());
assertEquals(mHasVibrator, mAudioManager.shouldVibrate(VIBRATE_TYPE_RINGER));
// VIBRATE_TYPE_NOTIFICATION
mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_ON);
assertEquals(mHasVibrator ? VIBRATE_SETTING_ON : VIBRATE_SETTING_OFF,
mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER));
mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_OFF);
assertEquals(VIBRATE_SETTING_OFF, mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER));
mAudioManager.setVibrateSetting(VIBRATE_TYPE_RINGER, VIBRATE_SETTING_ONLY_SILENT);
assertEquals(mHasVibrator ? VIBRATE_SETTING_ONLY_SILENT : VIBRATE_SETTING_OFF,
mAudioManager.getVibrateSetting(VIBRATE_TYPE_RINGER));
}
public void testAccessRingMode() throws Exception {
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
mAudioManager.setRingerMode(RINGER_MODE_SILENT);
// AudioService#setRingerMode() has:
// if (isTelevision) return;
if (mSkipRingerTests) {
assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
} else {
assertEquals(RINGER_MODE_SILENT, mAudioManager.getRingerMode());
}
mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
if (mSkipRingerTests) {
assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
} else {
assertEquals(mHasVibrator ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT,
mAudioManager.getRingerMode());
}
}
public void testSetRingerModePolicyAccess() throws Exception {
if (mSkipRingerTests) {
return;
}
// Apps without policy access cannot change silent -> normal or silent -> vibrate.
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
mAudioManager.setRingerMode(RINGER_MODE_SILENT);
assertEquals(RINGER_MODE_SILENT, mAudioManager.getRingerMode());
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), false);
try {
mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
fail("Apps without notification policy access cannot change ringer mode");
} catch (SecurityException e) {
}
try {
mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
fail("Apps without notification policy access cannot change ringer mode");
} catch (SecurityException e) {
}
// Apps without policy access cannot change normal -> silent.
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), false);
try {
mAudioManager.setRingerMode(RINGER_MODE_SILENT);
fail("Apps without notification policy access cannot change ringer mode");
} catch (SecurityException e) {
}
assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
if (mHasVibrator) {
// Apps without policy access cannot change vibrate -> silent.
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), false);
try {
mAudioManager.setRingerMode(RINGER_MODE_SILENT);
fail("Apps without notification policy access cannot change ringer mode");
} catch (SecurityException e) {
}
// Apps without policy access can change vibrate -> normal and vice versa.
assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
}
}
public void testAccessRampingRinger() {
boolean originalEnabledState = mAudioManager.isRampingRingerEnabled();
try {
mAudioManager.setRampingRingerEnabled(false);
assertFalse(mAudioManager.isRampingRingerEnabled());
mAudioManager.setRampingRingerEnabled(true);
assertTrue(mAudioManager.isRampingRingerEnabled());
} finally {
mAudioManager.setRampingRingerEnabled(originalEnabledState);
}
}
public void testRampingRingerSetting() {
boolean originalEnabledState = mAudioManager.isRampingRingerEnabled();
try {
// Deprecated public setting should still be supported and affect the setting getter.
Settings.Global.putInt(mContext.getContentResolver(), APPLY_RAMPING_RINGER, 0);
assertFalse(mAudioManager.isRampingRingerEnabled());
Settings.Global.putInt(mContext.getContentResolver(), APPLY_RAMPING_RINGER, 1);
assertTrue(mAudioManager.isRampingRingerEnabled());
} finally {
mAudioManager.setRampingRingerEnabled(originalEnabledState);
}
}
public void testVolume() throws Exception {
if (MediaUtils.check(mIsTelevision, "No volume test due to fixed/full vol devices"))
return;
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
int volume, volumeDelta;
int[] streams = {STREAM_ALARM,
STREAM_MUSIC,
STREAM_VOICE_CALL,
STREAM_RING};
mAudioManager.adjustVolume(ADJUST_RAISE, 0);
// adjusting volume is asynchronous, wait before other volume checks
Thread.sleep(ASYNC_TIMING_TOLERANCE_MS);
mAudioManager.adjustSuggestedStreamVolume(
ADJUST_LOWER, USE_DEFAULT_STREAM_TYPE, 0);
Thread.sleep(ASYNC_TIMING_TOLERANCE_MS);
int maxMusicVolume = mAudioManager.getStreamMaxVolume(STREAM_MUSIC);
for (int stream : streams) {
if (mIsSingleVolume && stream != STREAM_MUSIC) {
continue;
}
// set ringer mode to back normal to not interfere with volume tests
mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
int maxVolume = mAudioManager.getStreamMaxVolume(stream);
int minVolume = mAudioManager.getStreamMinVolume(stream);
// validate min
assertTrue(String.format("minVolume(%d) must be >= 0", minVolume), minVolume >= 0);
assertTrue(String.format("minVolume(%d) must be < maxVolume(%d)", minVolume,
maxVolume),
minVolume < maxVolume);
final int minNonZeroVolume = Math.max(minVolume, 1);
mAudioManager.setStreamVolume(stream, minNonZeroVolume, 0);
if (mUseFixedVolume) {
assertEquals(maxVolume, mAudioManager.getStreamVolume(stream));
continue;
}
assertEquals(String.format("stream=%d", stream),
minNonZeroVolume, mAudioManager.getStreamVolume(stream));
if (stream == STREAM_MUSIC && mAudioManager.isWiredHeadsetOn()) {
// due to new regulations, music sent over a wired headset may be volume limited
// until the user explicitly increases the limit, so we can't rely on being able
// to set the volume to getStreamMaxVolume(). Instead, determine the current limit
// by increasing the volume until it won't go any higher, then use that volume as
// the maximum for the purposes of this test
int curvol = 0;
int prevvol = 0;
do {
prevvol = curvol;
mAudioManager.adjustStreamVolume(stream, ADJUST_RAISE, 0);
curvol = mAudioManager.getStreamVolume(stream);
} while (curvol != prevvol);
maxVolume = maxMusicVolume = curvol;
}
mAudioManager.setStreamVolume(stream, maxVolume, 0);
mAudioManager.adjustStreamVolume(stream, ADJUST_RAISE, 0);
assertEquals(maxVolume, mAudioManager.getStreamVolume(stream));
volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(stream));
mAudioManager.adjustSuggestedStreamVolume(ADJUST_LOWER, stream, 0);
assertStreamVolumeEquals(stream, maxVolume - volumeDelta,
"Vol ADJUST_LOWER suggested stream:" + stream + " maxVol:" + maxVolume);
// volume lower
mAudioManager.setStreamVolume(stream, maxVolume, 0);
volume = mAudioManager.getStreamVolume(stream);
while (volume > minVolume) {
volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(stream));
mAudioManager.adjustStreamVolume(stream, ADJUST_LOWER, 0);
assertStreamVolumeEquals(stream, Math.max(0, volume - volumeDelta),
"Vol ADJUST_LOWER on stream:" + stream + " vol:" + volume
+ " minVol:" + minVolume + " volDelta:" + volumeDelta);
volume = mAudioManager.getStreamVolume(stream);
}
mAudioManager.adjustStreamVolume(stream, ADJUST_SAME, 0);
// volume raise
mAudioManager.setStreamVolume(stream, minNonZeroVolume, 0);
volume = mAudioManager.getStreamVolume(stream);
while (volume < maxVolume) {
volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(stream));
mAudioManager.adjustStreamVolume(stream, ADJUST_RAISE, 0);
assertStreamVolumeEquals(stream, Math.min(volume + volumeDelta, maxVolume),
"Vol ADJUST_RAISE on stream:" + stream + " vol:" + volume
+ " maxVol:" + maxVolume + " volDelta:" + volumeDelta);
volume = mAudioManager.getStreamVolume(stream);
}
// volume same
mAudioManager.setStreamVolume(stream, maxVolume, 0);
mAudioManager.adjustStreamVolume(stream, ADJUST_SAME, 0);
Thread.sleep(ASYNC_TIMING_TOLERANCE_MS);
assertEquals("Vol ADJUST_RAISE onADJUST_SAME stream:" + stream,
maxVolume, mAudioManager.getStreamVolume(stream));
mAudioManager.setStreamVolume(stream, maxVolume, 0);
}
if (mUseFixedVolume) {
return;
}
// adjust volume
mAudioManager.adjustVolume(ADJUST_RAISE, 0);
Thread.sleep(ASYNC_TIMING_TOLERANCE_MS);
boolean isMusicPlayingBeforeTest = false;
if (mAudioManager.isMusicActive()) {
isMusicPlayingBeforeTest = true;
}
MediaPlayer mp = MediaPlayer.create(mContext, MP3_TO_PLAY);
assertNotNull(mp);
mp.setAudioStreamType(STREAM_MUSIC);
mp.setLooping(true);
mp.start();
assertMusicActive(true);
// adjust volume as ADJUST_SAME
mAudioManager.adjustVolume(ADJUST_SAME, 0);
Thread.sleep(ASYNC_TIMING_TOLERANCE_MS);
assertStreamVolumeEquals(STREAM_MUSIC, maxMusicVolume);
// adjust volume as ADJUST_RAISE
mAudioManager.setStreamVolume(STREAM_MUSIC, 0, 0);
volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(STREAM_MUSIC));
mAudioManager.adjustVolume(ADJUST_RAISE, 0);
Thread.sleep(ASYNC_TIMING_TOLERANCE_MS);
assertStreamVolumeEquals(STREAM_MUSIC, Math.min(volumeDelta, maxMusicVolume));
// adjust volume as ADJUST_LOWER
mAudioManager.setStreamVolume(STREAM_MUSIC, maxMusicVolume, 0);
maxMusicVolume = mAudioManager.getStreamVolume(STREAM_MUSIC);
volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(STREAM_MUSIC));
mAudioManager.adjustVolume(ADJUST_LOWER, 0);
assertStreamVolumeEquals(STREAM_MUSIC, Math.max(0, maxMusicVolume - volumeDelta));
mp.stop();
mp.release();
if (!isMusicPlayingBeforeTest) {
assertMusicActive(false);
}
}
public void testAccessibilityVolume() throws Exception {
if (mUseFixedVolume) {
Log.i("AudioManagerTest", "testAccessibilityVolume() skipped: fixed volume");
return;
}
final int maxA11yVol = mAudioManager.getStreamMaxVolume(STREAM_ACCESSIBILITY);
assertTrue("Max a11yVol not strictly positive", maxA11yVol > 0);
int originalVol = mAudioManager.getStreamVolume(STREAM_ACCESSIBILITY);
// changing STREAM_ACCESSIBILITY is subject to permission, shouldn't be able to change it
// test setStreamVolume
final int testSetVol;
if (originalVol != maxA11yVol) {
testSetVol = maxA11yVol;
} else {
testSetVol = maxA11yVol - 1;
}
mAudioManager.setStreamVolume(STREAM_ACCESSIBILITY, testSetVol, 0);
assertStreamVolumeEquals(STREAM_ACCESSIBILITY, originalVol,
"Should not be able to change A11y vol");
// test adjustStreamVolume
// LOWER
if (originalVol > 0) {
mAudioManager.adjustStreamVolume(STREAM_ACCESSIBILITY, ADJUST_LOWER, 0);
assertStreamVolumeEquals(STREAM_ACCESSIBILITY, originalVol,
"Should not be able to change A11y vol");
}
// RAISE
if (originalVol < maxA11yVol) {
mAudioManager.adjustStreamVolume(STREAM_ACCESSIBILITY, ADJUST_RAISE, 0);
assertStreamVolumeEquals(STREAM_ACCESSIBILITY, originalVol,
"Should not be able to change A11y vol");
}
}
public void testSetVoiceCallVolumeToZeroPermission() {
// Verify that only apps with MODIFY_PHONE_STATE can set VOICE_CALL_STREAM to 0
mAudioManager.setStreamVolume(STREAM_VOICE_CALL, 0, 0);
assertTrue("MODIFY_PHONE_STATE is required in order to set voice call volume to 0",
mAudioManager.getStreamVolume(STREAM_VOICE_CALL) != 0);
}
public void testMuteFixedVolume() throws Exception {
int[] streams = {
STREAM_VOICE_CALL,
STREAM_MUSIC,
STREAM_RING,
STREAM_ALARM,
STREAM_NOTIFICATION,
STREAM_SYSTEM};
if (mUseFixedVolume) {
for (int stream : streams) {
mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_MUTE, 0);
assertFalse("Muting should not affect a fixed volume device.",
mAudioManager.isStreamMute(stream));
mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_TOGGLE_MUTE, 0);
assertFalse("Toggling mute should not affect a fixed volume device.",
mAudioManager.isStreamMute(stream));
mAudioManager.setStreamMute(stream, true);
assertFalse("Muting should not affect a fixed volume device.",
mAudioManager.isStreamMute(stream));
}
}
}
public void testMuteDndAffectedStreams() throws Exception {
if (mSkipRingerTests) {
return;
}
int[] streams = { STREAM_RING };
// Mute streams
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
mAudioManager.setRingerMode(RINGER_MODE_SILENT);
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), false);
// Verify streams cannot be unmuted without policy access.
for (int stream : streams) {
try {
mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_UNMUTE, 0);
assertEquals("Apps without Notification policy access can't change ringer mode",
RINGER_MODE_SILENT, mAudioManager.getRingerMode());
} catch (SecurityException e) {
}
try {
mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_TOGGLE_MUTE,
0);
assertEquals("Apps without Notification policy access can't change ringer mode",
RINGER_MODE_SILENT, mAudioManager.getRingerMode());
} catch (SecurityException e) {
}
try {
mAudioManager.setStreamMute(stream, false);
assertEquals("Apps without Notification policy access can't change ringer mode",
RINGER_MODE_SILENT, mAudioManager.getRingerMode());
} catch (SecurityException e) {
}
}
// This ensures we're out of vibrate or silent modes.
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
for (int stream : streams) {
// ensure each stream is on and turned up.
mAudioManager.setStreamVolume(stream,
mAudioManager.getStreamMaxVolume(stream),
0);
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), false);
try {
mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_MUTE, 0);
assertEquals("Apps without Notification policy access can't change ringer mode",
RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
} catch (SecurityException e) {
}
try {
mAudioManager.adjustStreamVolume(
stream, AudioManager.ADJUST_TOGGLE_MUTE, 0);
assertEquals("Apps without Notification policy access can't change ringer mode",
RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
} catch (SecurityException e) {
}
try {
mAudioManager.setStreamMute(stream, true);
assertEquals("Apps without Notification policy access can't change ringer mode",
RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
} catch (SecurityException e) {
}
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
testStreamMuting(stream);
}
}
public void testMuteDndUnaffectedStreams() throws Exception {
if (mSkipRingerTests) {
return;
}
int[] streams = {
STREAM_VOICE_CALL,
STREAM_MUSIC,
STREAM_ALARM
};
int muteAffectedStreams = System.getInt(mContext.getContentResolver(),
System.MUTE_STREAMS_AFFECTED,
// same defaults as in AudioService. Should be kept in sync.
(1 << STREAM_MUSIC) |
(1 << STREAM_RING) |
(1 << STREAM_NOTIFICATION) |
(1 << STREAM_SYSTEM) |
(1 << STREAM_VOICE_CALL));
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
// This ensures we're out of vibrate or silent modes.
mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), false);
for (int stream : streams) {
// ensure each stream is on and turned up.
mAudioManager.setStreamVolume(stream,
mAudioManager.getStreamMaxVolume(stream),
0);
if (((1 << stream) & muteAffectedStreams) == 0) {
mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_MUTE, 0);
assertFalse("Stream " + stream + " should not be affected by mute.",
mAudioManager.isStreamMute(stream));
mAudioManager.setStreamMute(stream, true);
assertFalse("Stream " + stream + " should not be affected by mute.",
mAudioManager.isStreamMute(stream));
mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_TOGGLE_MUTE,
0);
assertFalse("Stream " + stream + " should not be affected by mute.",
mAudioManager.isStreamMute(stream));
continue;
}
testStreamMuting(stream);
}
}
private void testStreamMuting(int stream) {
getInstrumentation().getUiAutomation()
.adoptShellPermissionIdentity(Manifest.permission.QUERY_AUDIO_STATE);
final int streamVolume = mAudioManager.getLastAudibleStreamVolume(stream);
// Voice call requires MODIFY_PHONE_STATE, so we should not be able to mute
if (stream == STREAM_VOICE_CALL) {
mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_MUTE, 0);
assertFalse("Muting voice call stream (" + stream + ") should require "
+ "MODIFY_PHONE_STATE.", mAudioManager.isStreamMute(stream));
} else {
mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_MUTE, 0);
assertTrue("Muting stream " + stream + " failed.",
mAudioManager.isStreamMute(stream));
assertEquals(streamVolume, mAudioManager.getLastAudibleStreamVolume(stream));
mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_UNMUTE, 0);
assertFalse("Unmuting stream " + stream + " failed.",
mAudioManager.isStreamMute(stream));
assertEquals(streamVolume, mAudioManager.getLastAudibleStreamVolume(stream));
mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_TOGGLE_MUTE, 0);
assertTrue("Toggling mute on stream " + stream + " failed.",
mAudioManager.isStreamMute(stream));
assertEquals(streamVolume, mAudioManager.getLastAudibleStreamVolume(stream));
mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_TOGGLE_MUTE, 0);
assertFalse("Toggling mute on stream " + stream + " failed.",
mAudioManager.isStreamMute(stream));
assertEquals(streamVolume, mAudioManager.getLastAudibleStreamVolume(stream));
mAudioManager.setStreamMute(stream, true);
assertTrue("Muting stream " + stream + " using setStreamMute failed",
mAudioManager.isStreamMute(stream));
assertEquals(streamVolume, mAudioManager.getLastAudibleStreamVolume(stream));
// mute it three more times to verify the ref counting is gone.
mAudioManager.setStreamMute(stream, true);
mAudioManager.setStreamMute(stream, true);
mAudioManager.setStreamMute(stream, true);
mAudioManager.setStreamMute(stream, false);
assertFalse("Unmuting stream " + stream + " using setStreamMute failed.",
mAudioManager.isStreamMute(stream));
}
assertEquals(streamVolume, mAudioManager.getLastAudibleStreamVolume(stream));
getInstrumentation().getUiAutomation().dropShellPermissionIdentity();
}
public void testSetInvalidRingerMode() {
int ringerMode = mAudioManager.getRingerMode();
mAudioManager.setRingerMode(-1337);
assertEquals(ringerMode, mAudioManager.getRingerMode());
mAudioManager.setRingerMode(-3007);
assertEquals(ringerMode, mAudioManager.getRingerMode());
}
public void testAdjustVolumeInTotalSilenceMode() throws Exception {
if (mSkipRingerTests) {
return;
}
try {
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
mAudioManager.setStreamVolume(STREAM_MUSIC, 1, 0);
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_NONE);
Thread.sleep(ASYNC_TIMING_TOLERANCE_MS);
int musicVolume = mAudioManager.getStreamVolume(STREAM_MUSIC);
mAudioManager.adjustStreamVolume(
STREAM_MUSIC, ADJUST_RAISE, 0);
assertStreamVolumeEquals(STREAM_MUSIC, musicVolume);
} finally {
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
}
}
public void testAdjustVolumeInAlarmsOnlyMode() throws Exception {
if (mSkipRingerTests) {
return;
}
try {
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
mAudioManager.setStreamVolume(STREAM_MUSIC, 1, 0);
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALARMS);
Thread.sleep(ASYNC_TIMING_TOLERANCE_MS);
int musicVolume = mAudioManager.getStreamVolume(STREAM_MUSIC);
mAudioManager.adjustStreamVolume(
STREAM_MUSIC, ADJUST_RAISE, 0);
int volumeDelta =
getVolumeDelta(mAudioManager.getStreamVolume(STREAM_MUSIC));
assertStreamVolumeEquals(STREAM_MUSIC, musicVolume + volumeDelta);
} finally {
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
}
}
public void testSetStreamVolumeInTotalSilenceMode() throws Exception {
if (mSkipRingerTests) {
return;
}
try {
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
mAudioManager.setStreamVolume(STREAM_RING, 1, 0);
mAudioManager.setStreamVolume(STREAM_MUSIC, 1, 0);
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_NONE);
// delay for streams interruption filter to get into correct state
Thread.sleep(ASYNC_TIMING_TOLERANCE_MS);
// cannot adjust music, can adjust ringer since it could exit DND
int musicVolume = mAudioManager.getStreamVolume(STREAM_MUSIC);
mAudioManager.setStreamVolume(STREAM_MUSIC, 7, 0);
assertStreamVolumeEquals(STREAM_MUSIC, musicVolume);
mAudioManager.setStreamVolume(STREAM_RING, 7, 0);
assertStreamVolumeEquals(STREAM_RING, 7);
} finally {
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
}
}
public void testSetStreamVolumeInAlarmsOnlyMode() throws Exception {
if (mSkipRingerTests) {
return;
}
try {
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
mAudioManager.setStreamVolume(STREAM_RING, 1, 0);
mAudioManager.setStreamVolume(STREAM_MUSIC, 1, 0);
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALARMS);
// delay for streams to get into correct volume states
Thread.sleep(ASYNC_TIMING_TOLERANCE_MS);
// can still adjust music and ring volume
mAudioManager.setStreamVolume(STREAM_MUSIC, 3, 0);
assertStreamVolumeEquals(STREAM_MUSIC, 3);
mAudioManager.setStreamVolume(STREAM_RING, 7, 0);
assertStreamVolumeEquals(STREAM_RING, 7);
} finally {
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
}
}
public void testSetStreamVolumeInPriorityOnlyMode() throws Exception {
if (mSkipRingerTests) {
return;
}
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
try {
// turn off zen, set stream volumes to check for later
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
final int testRingerVol = getTestRingerVol();
mAudioManager.setStreamVolume(STREAM_MUSIC, 1, 0);
mAudioManager.setStreamVolume(STREAM_ALARM, 1, 0);
int musicVolume = mAudioManager.getStreamVolume(STREAM_MUSIC);
int alarmVolume = mAudioManager.getStreamVolume(STREAM_ALARM);
// disallow all sounds in priority only, turn on priority only DND, try to change volume
mNm.setNotificationPolicy(new NotificationManager.Policy(0, 0 , 0));
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY);
// delay for streams to get into correct volume states
Thread.sleep(ASYNC_TIMING_TOLERANCE_MS);
mAudioManager.setStreamVolume(STREAM_MUSIC, 3, 0);
mAudioManager.setStreamVolume(STREAM_ALARM, 5, 0);
mAudioManager.setStreamVolume(STREAM_RING, testRingerVol, 0);
// Turn off zen and make sure stream levels are still the same prior to zen
// aside from ringer since ringer can exit dnd
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
Thread.sleep(ASYNC_TIMING_TOLERANCE_MS); // delay for streams to get into correct states
assertEquals(musicVolume, mAudioManager.getStreamVolume(STREAM_MUSIC));
assertEquals(alarmVolume, mAudioManager.getStreamVolume(STREAM_ALARM));
assertEquals(testRingerVol, mAudioManager.getStreamVolume(STREAM_RING));
} finally {
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
}
}
public void testAdjustVolumeInPriorityOnly() throws Exception {
if (mSkipRingerTests) {
return;
}
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
try {
// turn off zen, set stream volumes to check for later
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
mAudioManager.setStreamVolume(STREAM_RING, 1, 0);
mAudioManager.setStreamVolume(STREAM_MUSIC, 1, 0);
mAudioManager.setStreamVolume(STREAM_ALARM, 1, 0);
int ringVolume = mAudioManager.getStreamVolume(STREAM_RING);
int musicVolume = mAudioManager.getStreamVolume(STREAM_MUSIC);
int alarmVolume = mAudioManager.getStreamVolume(STREAM_ALARM);
// disallow all sounds in priority only, turn on priority only DND, try to change volume
mNm.setNotificationPolicy(new NotificationManager.Policy(0, 0, 0));
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY);
// delay for streams to get into correct mute states
Thread.sleep(ASYNC_TIMING_TOLERANCE_MS);
mAudioManager.adjustStreamVolume(
STREAM_RING, ADJUST_RAISE, 0);
mAudioManager.adjustStreamVolume(
STREAM_MUSIC, ADJUST_RAISE, 0);
mAudioManager.adjustStreamVolume(
STREAM_ALARM, ADJUST_RAISE, 0);
// Turn off zen and make sure stream levels are still the same prior to zen
// aside from ringer since ringer can exit dnd
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
Thread.sleep(ASYNC_TIMING_TOLERANCE_MS); // delay for streams to get into correct states
assertEquals(musicVolume, mAudioManager.getStreamVolume(STREAM_MUSIC));
assertEquals(alarmVolume, mAudioManager.getStreamVolume(STREAM_ALARM));
int volumeDelta =
getVolumeDelta(mAudioManager.getStreamVolume(STREAM_RING));
assertEquals(ringVolume + volumeDelta,
mAudioManager.getStreamVolume(STREAM_RING));
} finally {
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
}
}
public void testPriorityOnlyMuteAll() throws Exception {
if (mSkipRingerTests) {
return;
}
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
try {
// ensure volume is not muted/0 to start test
mAudioManager.setStreamVolume(STREAM_MUSIC, 1, 0);
mAudioManager.setStreamVolume(STREAM_ALARM, 1, 0);
mAudioManager.setStreamVolume(STREAM_SYSTEM, 1, 0);
mAudioManager.setStreamVolume(STREAM_RING, 1, 0);
// disallow all sounds in priority only, turn on priority only DND
mNm.setNotificationPolicy(new NotificationManager.Policy(0, 0, 0));
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY);
assertStreamMuted(STREAM_MUSIC, true,
"Music (media) stream should be muted");
assertStreamMuted(STREAM_SYSTEM, true,
"System stream should be muted");
assertStreamMuted(STREAM_ALARM, true,
"Alarm stream should be muted");
// if channels cannot bypass DND, the Ringer stream should be muted, else it
// shouldn't be muted
assertStreamMuted(STREAM_RING, !mAppsBypassingDnd,
"Ringer stream should be muted if channels cannot bypassDnd");
} finally {
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
}
}
public void testPriorityOnlyMediaAllowed() throws Exception {
if (mSkipRingerTests) {
return;
}
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
try {
// ensure volume is not muted/0 to start test
mAudioManager.setStreamVolume(STREAM_MUSIC, 1, 0);
mAudioManager.setStreamVolume(STREAM_ALARM, 1, 0);
mAudioManager.setStreamVolume(STREAM_SYSTEM, 1, 0);
mAudioManager.setStreamVolume(STREAM_RING, 1, 0);
// allow only media in priority only
mNm.setNotificationPolicy(new NotificationManager.Policy(
NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA, 0, 0));
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY);
assertStreamMuted(STREAM_MUSIC, false,
"Music (media) stream should not be muted");
assertStreamMuted(STREAM_SYSTEM, true,
"System stream should be muted");
assertStreamMuted(STREAM_ALARM, true,
"Alarm stream should be muted");
// if channels cannot bypass DND, the Ringer stream should be muted, else it
// shouldn't be muted
assertStreamMuted(STREAM_RING, !mAppsBypassingDnd,
"Ringer stream should be muted if channels cannot bypassDnd");
} finally {
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
}
}
public void testPriorityOnlySystemAllowed() throws Exception {
if (mSkipRingerTests) {
return;
}
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
try {
// ensure volume is not muted/0 to start test
mAudioManager.setStreamVolume(STREAM_MUSIC, 1, 0);
mAudioManager.setStreamVolume(STREAM_ALARM, 1, 0);
mAudioManager.setStreamVolume(STREAM_SYSTEM, 1, 0);
mAudioManager.setStreamVolume(STREAM_RING, 1, 0);
// allow only system in priority only
mNm.setNotificationPolicy(new NotificationManager.Policy(
NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM, 0, 0));
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY);
assertStreamMuted(STREAM_MUSIC, true,
"Music (media) stream should be muted");
assertStreamMuted(STREAM_SYSTEM, false,
"System stream should not be muted");
assertStreamMuted(STREAM_ALARM, true,
"Alarm stream should be muted");
assertStreamMuted(STREAM_RING, false,
"Ringer stream should not be muted");
} finally {
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
}
}
public void testPriorityOnlySystemDisallowedWithRingerMuted() throws Exception {
if (mSkipRingerTests) {
return;
}
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
try {
// ensure volume is not muted/0 to start test, but then mute ringer
mAudioManager.setStreamVolume(STREAM_MUSIC, 1, 0);
mAudioManager.setStreamVolume(STREAM_ALARM, 1, 0);
mAudioManager.setStreamVolume(STREAM_SYSTEM, 1, 0);
mAudioManager.setStreamVolume(STREAM_RING, 0, 0);
mAudioManager.setRingerMode(RINGER_MODE_SILENT);
// allow only system in priority only
mNm.setNotificationPolicy(new NotificationManager.Policy(
NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM, 0, 0));
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY);
assertStreamMuted(STREAM_MUSIC, true,
"Music (media) stream should be muted");
assertStreamMuted(STREAM_SYSTEM, true,
"System stream should be muted");
assertStreamMuted(STREAM_ALARM, true,
"Alarm stream should be muted");
assertStreamMuted(STREAM_RING, true,
"Ringer stream should be muted");
} finally {
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
}
}
public void testPriorityOnlyAlarmsAllowed() throws Exception {
if (mSkipRingerTests) {
return;
}
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
try {
// ensure volume is not muted/0 to start test
mAudioManager.setStreamVolume(STREAM_MUSIC, 1, 0);
mAudioManager.setStreamVolume(STREAM_ALARM, 1, 0);
mAudioManager.setStreamVolume(STREAM_SYSTEM, 1, 0);
mAudioManager.setStreamVolume(STREAM_RING, 1, 0);
// allow only alarms in priority only
mNm.setNotificationPolicy(new NotificationManager.Policy(
NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS, 0, 0));
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY);
assertStreamMuted(STREAM_MUSIC, true,
"Music (media) stream should be muted");
assertStreamMuted(STREAM_SYSTEM, true,
"System stream should be muted");
assertStreamMuted(STREAM_ALARM, false,
"Alarm stream should not be muted");
// if channels cannot bypass DND, the Ringer stream should be muted, else it
// shouldn't be muted
assertStreamMuted(STREAM_RING, !mAppsBypassingDnd,
"Ringer stream should be muted if channels cannot bypassDnd");
} finally {
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
}
}
public void testPriorityOnlyRingerAllowed() throws Exception {
if (mSkipRingerTests) {
return;
}
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
try {
// ensure volume is not muted/0 to start test
mAudioManager.setStreamVolume(STREAM_MUSIC, 1, 0);
mAudioManager.setStreamVolume(STREAM_ALARM, 1, 0);
mAudioManager.setStreamVolume(STREAM_SYSTEM, 1, 0);
mAudioManager.setStreamVolume(STREAM_RING, 1, 0);
// allow only reminders in priority only
mNm.setNotificationPolicy(new NotificationManager.Policy(
NotificationManager.Policy.PRIORITY_CATEGORY_REMINDERS, 0, 0));
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY);
assertStreamMuted(STREAM_MUSIC, true,
"Music (media) stream should be muted");
assertStreamMuted(STREAM_SYSTEM, true,
"System stream should be muted");
assertStreamMuted(STREAM_ALARM, true,
"Alarm stream should be muted");
assertStreamMuted(STREAM_RING, false,
"Ringer stream should not be muted");
} finally {
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
}
}
public void testPriorityOnlyChannelsCanBypassDnd() throws Exception {
if (mSkipRingerTests) {
return;
}
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
final String NOTIFICATION_CHANNEL_ID = "test_id_" + SystemClock.uptimeMillis();
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "TEST",
NotificationManager.IMPORTANCE_DEFAULT);
try {
// ensure volume is not muted/0 to start test
mAudioManager.setStreamVolume(STREAM_MUSIC, 1, 0);
mAudioManager.setStreamVolume(STREAM_ALARM, 1, 0);
mAudioManager.setStreamVolume(STREAM_SYSTEM, 1, 0);
mAudioManager.setStreamVolume(STREAM_RING, 1, 0);
// create a channel that can bypass dnd
channel.setBypassDnd(true);
mNm.createNotificationChannel(channel);
// allow nothing
mNm.setNotificationPolicy(new NotificationManager.Policy(0,0, 0));
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY);
assertStreamMuted(STREAM_MUSIC, true,
"Music (media) stream should be muted");
assertStreamMuted(STREAM_SYSTEM, true,
"System stream should be muted");
assertStreamMuted(STREAM_ALARM, true,
"Alarm stream should be muted");
assertStreamMuted(STREAM_RING, false,
"Ringer stream should not be muted."
+ " areChannelsBypassing="
+ NotificationManager.getService().areChannelsBypassingDnd());
// delete the channel that can bypass dnd
mNm.deleteNotificationChannel(NOTIFICATION_CHANNEL_ID);
assertStreamMuted(STREAM_MUSIC, true,
"Music (media) stream should be muted");
assertStreamMuted(STREAM_SYSTEM, true,
"System stream should be muted");
assertStreamMuted(STREAM_ALARM, true,
"Alarm stream should be muted");
// if channels cannot bypass DND, the Ringer stream should be muted, else it
// shouldn't be muted
assertStreamMuted(STREAM_RING, !mAppsBypassingDnd,
"Ringer stream should be muted if apps are bypassing dnd"
+ " areChannelsBypassing="
+ NotificationManager.getService().areChannelsBypassingDnd());
} finally {
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
mNm.deleteNotificationChannel(NOTIFICATION_CHANNEL_ID);
Utils.toggleNotificationPolicyAccess(mContext.getPackageName(), getInstrumentation(),
false);
}
}
public void testAdjustVolumeWithIllegalDirection() throws Exception {
// Call the method with illegal direction. System should not reboot.
mAudioManager.adjustVolume(37, 0);
}
private final int[] PUBLIC_STREAM_TYPES = { STREAM_VOICE_CALL,
STREAM_SYSTEM, STREAM_RING, STREAM_MUSIC,
STREAM_ALARM, STREAM_NOTIFICATION,
STREAM_DTMF, STREAM_ACCESSIBILITY };
public void testGetStreamVolumeDbWithIllegalArguments() throws Exception {
Exception ex = null;
// invalid stream type
try {
float gain = mAudioManager.getStreamVolumeDb(-100 /*streamType*/, 0,
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER);
} catch (Exception e) {
ex = e; // expected
}
assertNotNull("No exception was thrown for an invalid stream type", ex);
assertEquals("Wrong exception thrown for invalid stream type",
ex.getClass(), IllegalArgumentException.class);
// invalid volume index
ex = null;
try {
float gain = mAudioManager.getStreamVolumeDb(STREAM_MUSIC, -101 /*volume*/,
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER);
} catch (Exception e) {
ex = e; // expected
}
assertNotNull("No exception was thrown for an invalid volume index", ex);
assertEquals("Wrong exception thrown for invalid volume index",
ex.getClass(), IllegalArgumentException.class);
// invalid out of range volume index
ex = null;
try {
final int maxVol = mAudioManager.getStreamMaxVolume(STREAM_MUSIC);
float gain = mAudioManager.getStreamVolumeDb(STREAM_MUSIC, maxVol + 1,
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER);
} catch (Exception e) {
ex = e; // expected
}
assertNotNull("No exception was thrown for an invalid out of range volume index", ex);
assertEquals("Wrong exception thrown for invalid out of range volume index",
ex.getClass(), IllegalArgumentException.class);
// invalid device type
ex = null;
try {
float gain = mAudioManager.getStreamVolumeDb(STREAM_MUSIC, 0,
-102 /*deviceType*/);
} catch (Exception e) {
ex = e; // expected
}
assertNotNull("No exception was thrown for an invalid device type", ex);
assertEquals("Wrong exception thrown for invalid device type",
ex.getClass(), IllegalArgumentException.class);
// invalid input device type
ex = null;
try {
float gain = mAudioManager.getStreamVolumeDb(STREAM_MUSIC, 0,
AudioDeviceInfo.TYPE_BUILTIN_MIC);
} catch (Exception e) {
ex = e; // expected
}
assertNotNull("No exception was thrown for an invalid input device type", ex);
assertEquals("Wrong exception thrown for invalid input device type",
ex.getClass(), IllegalArgumentException.class);
}
public void testGetStreamVolumeDb() throws Exception {
for (int streamType : PUBLIC_STREAM_TYPES) {
// verify mininum index is strictly inferior to maximum index
final int minIndex = mAudioManager.getStreamMinVolume(streamType);
final int maxIndex = mAudioManager.getStreamMaxVolume(streamType);
assertTrue("Min vol index (" + minIndex + ") for stream " + streamType + " not inferior"
+ " to max vol index (" + maxIndex + ")", minIndex <= maxIndex);
float prevGain = Float.NEGATIVE_INFINITY;
// verify gain increases with the volume indices
for (int idx = minIndex ; idx <= maxIndex ; idx++) {
float gain = mAudioManager.getStreamVolumeDb(streamType, idx,
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER);
assertTrue("Non-monotonically increasing gain at index " + idx + " for stream"
+ streamType, prevGain <= gain);
prevGain = gain;
}
}
}
public void testAdjustSuggestedStreamVolumeWithIllegalArguments() throws Exception {
// Call the method with illegal direction. System should not reboot.
mAudioManager.adjustSuggestedStreamVolume(37, STREAM_MUSIC, 0);
// Call the method with illegal stream. System should not reboot.
mAudioManager.adjustSuggestedStreamVolume(ADJUST_RAISE, 66747, 0);
}
@CddTest(requirement="5.4.1/C-1-4")
public void testGetMicrophones() throws Exception {
if (!mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_MICROPHONE)) {
return;
}
List<MicrophoneInfo> microphones = mAudioManager.getMicrophones();
assertTrue(microphones.size() > 0);
for (int i = 0; i < microphones.size(); i++) {
MicrophoneInfo microphone = microphones.get(i);
Log.i(TAG, "deviceId:" + microphone.getDescription());
Log.i(TAG, "portId:" + microphone.getId());
Log.i(TAG, "type:" + microphone.getType());
Log.i(TAG, "address:" + microphone.getAddress());
Log.i(TAG, "deviceLocation:" + microphone.getLocation());
Log.i(TAG, "deviceGroup:" + microphone.getGroup()
+ " index:" + microphone.getIndexInTheGroup());
MicrophoneInfo.Coordinate3F position = microphone.getPosition();
Log.i(TAG, "position:" + position.x + " " + position.y + " " + position.z);
MicrophoneInfo.Coordinate3F orientation = microphone.getOrientation();
Log.i(TAG, "orientation:" + orientation.x + " "
+ orientation.y + " " + orientation.z);
Log.i(TAG, "frequencyResponse:" + microphone.getFrequencyResponse());
Log.i(TAG, "channelMapping:" + microphone.getChannelMapping());
Log.i(TAG, "sensitivity:" + microphone.getSensitivity());
Log.i(TAG, "max spl:" + microphone.getMaxSpl());
Log.i(TAG, "min spl:" + microphone.getMinSpl());
Log.i(TAG, "directionality:" + microphone.getDirectionality());
Log.i(TAG, "--------------");
}
}
public void testIsHapticPlaybackSupported() {
// Calling the API to make sure it doesn't crash.
Log.i(TAG, "isHapticPlaybackSupported: " + AudioManager.isHapticPlaybackSupported());
}
public void testIsUltrasoundSupported() {
// Calling the API to make sure it must crash due to no permission.
try {
mAudioManager.isUltrasoundSupported();
fail("isUltrasoundSupported must fail due to no permission");
} catch (SecurityException e) {
}
}
public void testGetAudioHwSyncForSession() {
// AudioManager.getAudioHwSyncForSession is not supported before S
if (ApiLevelUtil.isAtMost(Build.VERSION_CODES.R)) {
Log.i(TAG, "testGetAudioHwSyncForSession skipped, release: " + Build.VERSION.SDK_INT);
return;
}
try {
int sessionId = mAudioManager.generateAudioSessionId();
assertNotEquals("testGetAudioHwSyncForSession cannot get audio session ID",
AudioManager.ERROR, sessionId);
int hwSyncId = mAudioManager.getAudioHwSyncForSession(sessionId);
Log.i(TAG, "getAudioHwSyncForSession: " + hwSyncId);
} catch (UnsupportedOperationException e) {
Log.i(TAG, "getAudioHwSyncForSession not supported");
} catch (Exception e) {
fail("Unexpected exception thrown by getAudioHwSyncForSession: " + e);
}
}
private void setInterruptionFilter(int filter) {
mNm.setInterruptionFilter(filter);
final long startPoll = SystemClock.uptimeMillis();
int currentFilter = -1;
while (SystemClock.uptimeMillis() - startPoll < POLL_TIME_UPDATE_INTERRUPTION_FILTER) {
currentFilter = mNm.getCurrentInterruptionFilter();
if (currentFilter == filter) {
return;
}
}
Log.e(TAG, "interruption filter unsuccessfully set. wanted=" + filter
+ " actual=" + currentFilter);
}
private int getVolumeDelta(int volume) {
return 1;
}
private int getTestRingerVol() {
final int currentRingVol = mAudioManager.getStreamVolume(STREAM_RING);
final int maxRingVol = mAudioManager.getStreamMaxVolume(STREAM_RING);
if (currentRingVol != maxRingVol) {
return maxRingVol;
} else {
return maxRingVol - 1;
}
}
public void testAllowedCapturePolicy() throws Exception {
final int policy = mAudioManager.getAllowedCapturePolicy();
assertEquals("Wrong default capture policy", AudioAttributes.ALLOW_CAPTURE_BY_ALL, policy);
for (int setPolicy : new int[] { AudioAttributes.ALLOW_CAPTURE_BY_NONE,
AudioAttributes.ALLOW_CAPTURE_BY_SYSTEM,
AudioAttributes.ALLOW_CAPTURE_BY_ALL}) {
mAudioManager.setAllowedCapturePolicy(setPolicy);
final int getPolicy = mAudioManager.getAllowedCapturePolicy();
assertEquals("Allowed capture policy doesn't match", setPolicy, getPolicy);
}
}
public void testIsHdmiSystemAudidoSupported() {
// just make sure the call works
boolean isSupported = mAudioManager.isHdmiSystemAudioSupported();
Log.d(TAG, "isHdmiSystemAudioSupported() = " + isSupported);
}
public void testIsBluetoothScoAvailableOffCall() {
// just make sure the call works
boolean isSupported = mAudioManager.isBluetoothScoAvailableOffCall();
Log.d(TAG, "isBluetoothScoAvailableOffCall() = " + isSupported);
}
public void testStartStopBluetoothSco() {
mAudioManager.startBluetoothSco();
mAudioManager.stopBluetoothSco();
}
public void testStartStopBluetoothScoVirtualCall() {
mAudioManager.startBluetoothScoVirtualCall();
mAudioManager.stopBluetoothSco();
}
public void testGetAdditionalOutputDeviceDelay() {
AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL);
for (AudioDeviceInfo device : devices) {
long delay = mAudioManager.getAdditionalOutputDeviceDelay(device);
assertTrue("getAdditionalOutputDeviceDelay() = " + delay +" (should be >= 0)",
delay >= 0);
delay = mAudioManager.getMaxAdditionalOutputDeviceDelay(device);
assertTrue("getMaxAdditionalOutputDeviceDelay() = " + delay +" (should be >= 0)",
delay >= 0);
}
}
static class MyPrevDevForStrategyListener implements
AudioManager.OnPreferredDevicesForStrategyChangedListener {
@Override
public void onPreferredDevicesForStrategyChanged(AudioProductStrategy strategy,
List<AudioDeviceAttributes> devices) {
fail("onPreferredDevicesForStrategyChanged must not be called");
}
}
public void testPreferredDevicesForStrategy() {
// setPreferredDeviceForStrategy
AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
if (devices.length <= 0) {
Log.i(TAG, "Skip testPreferredDevicesForStrategy as there is no output device");
return;
}
final AudioDeviceAttributes ada = new AudioDeviceAttributes(devices[0]);
final AudioAttributes mediaAttr = new AudioAttributes.Builder().setUsage(
AudioAttributes.USAGE_MEDIA).build();
final List<AudioProductStrategy> strategies =
AudioProductStrategy.getAudioProductStrategies();
AudioProductStrategy strategyForMedia = null;
for (AudioProductStrategy strategy : strategies) {
if (strategy.supportsAudioAttributes(mediaAttr)) {
strategyForMedia = strategy;
break;
}
}
if (strategyForMedia == null) {
Log.i(TAG, "Skip testPreferredDevicesForStrategy as there is no strategy for media");
return;
}
try {
mAudioManager.setPreferredDeviceForStrategy(strategyForMedia, ada);
fail("setPreferredDeviceForStrategy must fail due to no permission");
} catch (SecurityException e) {
}
try {
mAudioManager.getPreferredDeviceForStrategy(strategyForMedia);
fail("getPreferredDeviceForStrategy must fail due to no permission");
} catch (SecurityException e) {
}
final List<AudioDeviceAttributes> adas = new ArrayList<>();
adas.add(ada);
try {
mAudioManager.setPreferredDevicesForStrategy(strategyForMedia, adas);
fail("setPreferredDevicesForStrategy must fail due to no permission");
} catch (SecurityException e) {
}
try {
mAudioManager.getPreferredDevicesForStrategy(strategyForMedia);
fail("getPreferredDevicesForStrategy must fail due to no permission");
} catch (SecurityException e) {
}
MyPrevDevForStrategyListener listener = new MyPrevDevForStrategyListener();
try {
mAudioManager.addOnPreferredDevicesForStrategyChangedListener(
Executors.newSingleThreadExecutor(), listener);
fail("addOnPreferredDevicesForStrategyChangedListener must fail due to no permission");
} catch (SecurityException e) {
}
// There is not listener added at server side. Nothing to remove.
mAudioManager.removeOnPreferredDevicesForStrategyChangedListener(listener);
}
static class MyPrevDevicesForCapturePresetChangedListener implements
AudioManager.OnPreferredDevicesForCapturePresetChangedListener {
@Override
public void onPreferredDevicesForCapturePresetChanged(
int capturePreset, List<AudioDeviceAttributes> devices) {
fail("onPreferredDevicesForCapturePresetChanged must not be called");
}
}
public void testPreferredDeviceForCapturePreset() {
AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS);
if (devices.length <= 0) {
Log.i(TAG, "Skip testPreferredDevicesForStrategy as there is no input device");
return;
}
final AudioDeviceAttributes ada = new AudioDeviceAttributes(devices[0]);
try {
mAudioManager.setPreferredDeviceForCapturePreset(MediaRecorder.AudioSource.MIC, ada);
fail("setPreferredDeviceForCapturePreset must fail due to no permission");
} catch (SecurityException e) {
}
try {
mAudioManager.getPreferredDevicesForCapturePreset(MediaRecorder.AudioSource.MIC);
fail("getPreferredDevicesForCapturePreset must fail due to no permission");
} catch (SecurityException e) {
}
try {
mAudioManager.clearPreferredDevicesForCapturePreset(MediaRecorder.AudioSource.MIC);
fail("clearPreferredDevicesForCapturePreset must fail due to no permission");
} catch (SecurityException e) {
}
MyPrevDevicesForCapturePresetChangedListener listener =
new MyPrevDevicesForCapturePresetChangedListener();
try {
mAudioManager.addOnPreferredDevicesForCapturePresetChangedListener(
Executors.newSingleThreadExecutor(), listener);
fail("addOnPreferredDevicesForCapturePresetChangedListener must fail"
+ "due to no permission");
} catch (SecurityException e) {
}
// There is not listener added at server side. Nothing to remove.
mAudioManager.removeOnPreferredDevicesForCapturePresetChangedListener(listener);
}
public void testGetDevices() {
AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL);
for (AudioDeviceInfo device : devices) {
HashSet<Integer> formats = IntStream.of(device.getEncodings()).boxed()
.collect(Collectors.toCollection(HashSet::new));
HashSet<Integer> channelMasks = IntStream.of(device.getChannelMasks()).boxed()
.collect(Collectors.toCollection(HashSet::new));
HashSet<Integer> channelIndexMasks = IntStream.of(device.getChannelIndexMasks()).boxed()
.collect(Collectors.toCollection(HashSet::new));
HashSet<Integer> sampleRates = IntStream.of(device.getSampleRates()).boxed()
.collect(Collectors.toCollection(HashSet::new));
HashSet<Integer> formatsFromProfile = new HashSet<>();
HashSet<Integer> channelMasksFromProfile = new HashSet<>();
HashSet<Integer> channelIndexMasksFromProfile = new HashSet<>();
HashSet<Integer> sampleRatesFromProfile = new HashSet<>();
for (AudioProfile profile : device.getAudioProfiles()) {
formatsFromProfile.add(profile.getFormat());
channelMasksFromProfile.addAll(Arrays.stream(profile.getChannelMasks()).boxed()
.collect(Collectors.toList()));
channelIndexMasksFromProfile.addAll(Arrays.stream(profile.getChannelIndexMasks())
.boxed().collect(Collectors.toList()));
sampleRatesFromProfile.addAll(Arrays.stream(profile.getSampleRates()).boxed()
.collect(Collectors.toList()));
assertTrue(ALL_ENCAPSULATION_TYPES.contains(profile.getEncapsulationType()));
}
for (AudioDescriptor descriptor : device.getAudioDescriptors()) {
assertNotEquals(AudioDescriptor.STANDARD_NONE, descriptor.getStandard());
assertNotNull(descriptor.getDescriptor());
assertTrue(
ALL_KNOWN_ENCAPSULATION_TYPES.contains(descriptor.getEncapsulationType()));
}
assertEquals(formats, formatsFromProfile);
assertEquals(channelMasks, channelMasksFromProfile);
assertEquals(channelIndexMasks, channelIndexMasksFromProfile);
assertEquals(sampleRates, sampleRatesFromProfile);
}
}
public void testGetDirectPlaybackSupport() {
assertEquals(AudioManager.DIRECT_PLAYBACK_NOT_SUPPORTED,
AudioManager.getDirectPlaybackSupport(
new AudioFormat.Builder().build(),
new AudioAttributes.Builder().build()));
AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
AudioAttributes attr = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setLegacyStreamType(STREAM_MUSIC).build();
for (AudioDeviceInfo device : devices) {
for (int encoding : device.getEncodings()) {
for (int channelMask : device.getChannelMasks()) {
for (int sampleRate : device.getSampleRates()) {
AudioFormat format = new AudioFormat.Builder()
.setEncoding(encoding)
.setChannelMask(channelMask)
.setSampleRate(sampleRate).build();
final int directPlaybackSupport =
AudioManager.getDirectPlaybackSupport(format, attr);
assertEquals(
AudioTrack.isDirectPlaybackSupported(format, attr),
directPlaybackSupport
!= AudioManager.DIRECT_PLAYBACK_NOT_SUPPORTED);
if (directPlaybackSupport == AudioManager.DIRECT_PLAYBACK_NOT_SUPPORTED) {
assertEquals(
DIRECT_OFFLOAD_MAP.getOrDefault(
AudioManager.getPlaybackOffloadSupport(format, attr),
INVALID_DIRECT_PLAYBACK_MODE).intValue(),
directPlaybackSupport);
} else if ((directPlaybackSupport
& AudioManager.DIRECT_PLAYBACK_OFFLOAD_SUPPORTED)
!= AudioManager.DIRECT_PLAYBACK_NOT_SUPPORTED) {
// AudioManager.getPlaybackOffloadSupport can only query offload
// support but not other direct support like passthrough.
assertNotEquals(
AudioManager.DIRECT_PLAYBACK_NOT_SUPPORTED,
DIRECT_OFFLOAD_MAP.getOrDefault(
AudioManager.getPlaybackOffloadSupport(format, attr),
AudioManager.DIRECT_PLAYBACK_NOT_SUPPORTED)
& directPlaybackSupport);
}
}
}
}
}
}
public void testAssistantUidRouting() {
try {
mAudioManager.addAssistantServicesUids(new int[0]);
fail("addAssistantServicesUids must fail due to no permission");
} catch (SecurityException e) {
}
try {
mAudioManager.removeAssistantServicesUids(new int[0]);
fail("removeAssistantServicesUids must fail due to no permission");
} catch (SecurityException e) {
}
try {
int[] uids = mAudioManager.getAssistantServicesUids();
fail("getAssistantServicesUids must fail due to no permission");
} catch (SecurityException e) {
}
try {
mAudioManager.setActiveAssistantServiceUids(new int[0]);
fail("setActiveAssistantServiceUids must fail due to no permission");
} catch (SecurityException e) {
}
try {
int[] activeUids = mAudioManager.getActiveAssistantServicesUids();
fail("getActiveAssistantServicesUids must fail due to no permission");
} catch (SecurityException e) {
}
}
public void testGetHalVersion() {
assertNotEquals(null, AudioManager.getHalVersion());
}
private void assertStreamVolumeEquals(int stream, int expectedVolume) throws Exception {
assertStreamVolumeEquals(stream, expectedVolume,
"Unexpected stream volume for stream=" + stream);
}
// volume adjustments are asynchronous, we poll the volume in case the volume state hasn't
// been adjusted yet
private void assertStreamVolumeEquals(int stream, int expectedVolume, String msg)
throws Exception {
final long startPoll = SystemClock.uptimeMillis();
int actualVolume = mAudioManager.getStreamVolume(stream);
while (SystemClock.uptimeMillis() - startPoll < POLL_TIME_VOLUME_ADJUST
&& expectedVolume != actualVolume) {
actualVolume = mAudioManager.getStreamVolume(stream);
}
assertEquals(msg, expectedVolume, actualVolume);
}
// volume adjustments are asynchronous, we poll the volume in case the mute state hasn't
// changed yet
private void assertStreamMuted(int stream, boolean expectedMuteState, String msg)
throws Exception{
final long startPoll = SystemClock.uptimeMillis();
boolean actualMuteState = mAudioManager.isStreamMute(stream);
while (SystemClock.uptimeMillis() - startPoll < POLL_TIME_VOLUME_ADJUST
&& expectedMuteState != actualMuteState) {
actualMuteState = mAudioManager.isStreamMute(stream);
}
assertEquals(msg, expectedMuteState, actualMuteState);
}
private void assertMusicActive(boolean expectedIsMusicActive) throws Exception {
final long startPoll = SystemClock.uptimeMillis();
boolean actualIsMusicActive = mAudioManager.isMusicActive();
while (SystemClock.uptimeMillis() - startPoll < POLL_TIME_PLAY_MUSIC
&& expectedIsMusicActive != actualIsMusicActive) {
actualIsMusicActive = mAudioManager.isMusicActive();
}
assertEquals(actualIsMusicActive, actualIsMusicActive);
}
private static final long REPEATED_CHECK_POLL_PERIOD_MS = 100; // 100ms
private static final long DEFAULT_ASYNC_CALL_TIMEOUT_MS = 5 * REPEATED_CHECK_POLL_PERIOD_MS;
/**
* Makes multiple attempts over a given timeout period to test the predicate on an AudioManager
* instance. Test success is evaluated against a true predicate result.
* @param am the AudioManager instance to use for the test
* @param predicate the test to run either until it returns true, or until the timeout expires
* @param timeoutMs the maximum time allowed for the test to pass
* @param errorString the string to be displayed in case of failure
* @throws Exception
*/
private void assertTrueCheckTimeout(AudioManager am, Predicate<AudioManager> predicate,
long timeoutMs, String errorString) throws Exception {
long checkStart = SystemClock.uptimeMillis();
boolean result = false;
while (SystemClock.uptimeMillis() - checkStart < timeoutMs) {
result = predicate.test(am);
if (result) {
break;
}
Thread.sleep(REPEATED_CHECK_POLL_PERIOD_MS);
}
assertTrue(errorString, result);
}
private boolean isAutomotive() {
PackageManager pm = mContext.getPackageManager();
return pm.hasSystemFeature(pm.FEATURE_AUTOMOTIVE);
}
// getParameters() & setParameters() are deprecated, so don't test
// setAdditionalOutputDeviceDelay(), getAudioVolumeGroups(), getVolumeIndexForAttributes()
// getMinVolumeIndexForAttributes(), getMaxVolumeIndexForAttributes() &
// setVolumeIndexForAttributes() require privledged permission MODIFY_AUDIO_ROUTING
// and thus cannot be tested here.
}