AudioServicepublic class AudioService extends IAudioService.Stub The implementation of the volume manager service.
This implementation focuses on delivering a responsive UI. Most methods are
asynchronous to external calls. For example, the task of setting a volume
will update our internal state, but in a separate thread will set the system
volume and later persist to the database. Similarly, setting the ringer mode
will update the state and broadcast a change and in a separate thread later
persist the ringer mode. |
Fields Summary |
---|
private static final String | TAG | private static final int | PERSIST_DELAYHow long to delay before persisting a change in volume/ringer mode. | private android.content.Context | mContext | private android.content.ContentResolver | mContentResolver | private android.view.VolumePanel | mVolumePanelThe UI | private static final int | SHARED_MSGUsed when a message should be shared across all stream types. | private static final int | SENDMSG_REPLACEIf the msg is already queued, replace it with this one. | private static final int | SENDMSG_NOOPIf the msg is already queued, ignore this one and leave the old. | private static final int | SENDMSG_QUEUEIf the msg is already queued, queue this one and leave the old. | private static final int | MSG_SET_SYSTEM_VOLUME | private static final int | MSG_PERSIST_VOLUME | private static final int | MSG_PERSIST_RINGER_MODE | private static final int | MSG_PERSIST_VIBRATE_SETTING | private static final int | MSG_MEDIA_SERVER_DIED | private static final int | MSG_MEDIA_SERVER_STARTED | private static final int | MSG_PLAY_SOUND_EFFECT | private AudioSystemThread | mAudioSystemThread | private AudioHandler | mAudioHandler | private VolumeStreamState[] | mStreamStates | private SettingsObserver | mSettingsObserver | private boolean | mMicMute | private int | mMode | private int[] | mRoutes | private Object | mSettingsLock | private boolean | mMediaServerOk | private SoundPool | mSoundPool | private Object | mSoundEffectsLock | private static final int | NUM_SOUNDPOOL_CHANNELS | private static final int | SOUND_EFFECT_VOLUME | private static final String | SOUND_EFFECTS_PATH | private static final String[] | SOUND_EFFECT_FILES | private int[] | SOUND_EFFECT_FILES_MAP | private AudioSystem.ErrorCallback | mAudioSystemCallback | private int | mRingerModeCurrent ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
{@link AudioManager#RINGER_MODE_SILENT}, or
{@link AudioManager#RINGER_MODE_VIBRATE}. | private int | mMuteAffectedStreams | private int | mVibrateSettingHas multiple bits per vibrate type to indicate the type's vibrate
setting. See {@link #setVibrateSetting(int, int)}.
NOTE: This is not the final decision of whether vibrate is on/off for the
type since it depends on the ringer mode. See {@link #shouldVibrate(int)}. |
Constructors Summary |
---|
public AudioService(android.content.Context context)
///////////////////////////////////////////////////////////////////////////
// Construction
///////////////////////////////////////////////////////////////////////////
mContext = context;
mContentResolver = context.getContentResolver();
mVolumePanel = new VolumePanel(context, this);
mSettingsObserver = new SettingsObserver();
createAudioSystemThread();
createStreamStates();
readPersistedSettings();
readAudioSettings();
mMediaServerOk = true;
AudioSystem.setErrorCallback(mAudioSystemCallback);
loadSoundEffects();
|
Methods Summary |
---|
public void | adjustStreamVolume(int streamType, int direction, int flags)
ensureValidDirection(direction);
ensureValidStreamType(streamType);
boolean notificationsUseRingVolume = Settings.System.getInt(mContentResolver,
Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1) == 1;
if (notificationsUseRingVolume && streamType == AudioManager.STREAM_NOTIFICATION) {
// Redirect the volume change to the ring stream
streamType = AudioManager.STREAM_RING;
}
VolumeStreamState streamState = mStreamStates[streamType];
final int oldIndex = streamState.mIndex;
boolean adjustVolume = true;
// If either the client forces allowing ringer modes for this adjustment,
// or the stream type is one that is affected by ringer modes
if ((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0
|| streamType == AudioManager.STREAM_RING) {
// Check if the ringer mode changes with this volume adjustment. If
// it does, it will handle adjusting the volume, so we won't below
adjustVolume = checkForRingerModeChange(oldIndex, direction);
}
if (adjustVolume && streamState.adjustIndex(direction)) {
boolean alsoUpdateNotificationVolume = notificationsUseRingVolume &&
streamType == AudioManager.STREAM_RING;
if (alsoUpdateNotificationVolume) {
mStreamStates[AudioManager.STREAM_NOTIFICATION].adjustIndex(direction);
}
// Post message to set system volume (it in turn will post a message
// to persist). Do not change volume if stream is muted.
if (streamState.muteCount() == 0) {
sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0,
streamState, 0);
if (alsoUpdateNotificationVolume) {
sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, AudioManager.STREAM_NOTIFICATION,
SENDMSG_NOOP, 0, 0, mStreamStates[AudioManager.STREAM_NOTIFICATION], 0);
}
}
}
// UI
mVolumePanel.postVolumeChanged(streamType, flags);
// Broadcast Intent
sendVolumeUpdate(streamType);
| public void | adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags)
int streamType = getActiveStreamType(suggestedStreamType);
// Don't play sound on other streams
if (streamType != AudioSystem.STREAM_RING && (flags & AudioManager.FLAG_PLAY_SOUND) != 0) {
flags &= ~AudioManager.FLAG_PLAY_SOUND;
}
adjustStreamVolume(streamType, direction, flags);
| public void | adjustVolume(int direction, int flags)
adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags);
| private void | applyAudioSettings()
synchronized (mSettingsLock) {
AudioSystem.muteMicrophone(mMicMute);
AudioSystem.setMode(mMode);
for (int mode = 0; mode < AudioSystem.NUM_MODES; mode++) {
AudioSystem.setRouting(mode, mRoutes[mode], AudioSystem.ROUTE_ALL);
}
}
| private void | broadcastRingerMode()
// Send sticky broadcast
if (ActivityManagerNative.isSystemReady()) {
Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION);
broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, mRingerMode);
long origCallerIdentityToken = Binder.clearCallingIdentity();
mContext.sendStickyBroadcast(broadcast);
Binder.restoreCallingIdentity(origCallerIdentityToken);
}
| private void | broadcastVibrateSetting(int vibrateType)
// Send broadcast
if (ActivityManagerNative.isSystemReady()) {
Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
mContext.sendBroadcast(broadcast);
}
| boolean | checkAudioSettingsPermission(java.lang.String method)
if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS")
== PackageManager.PERMISSION_GRANTED) {
return true;
}
String msg = "Audio Settings Permission Denial: " + method + " from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid();
Log.w(TAG, msg);
return false;
| private boolean | checkForRingerModeChange(int oldIndex, int direction)Checks if the adjustment should change ringer mode instead of just
adjusting volume. If so, this will set the proper ringer mode and volume
indices on the stream states.
boolean adjustVolumeIndex = true;
int newRingerMode = mRingerMode;
if (mRingerMode == AudioManager.RINGER_MODE_NORMAL && oldIndex == 1
&& direction == AudioManager.ADJUST_LOWER) {
newRingerMode = AudioManager.RINGER_MODE_VIBRATE;
} else if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
if (direction == AudioManager.ADJUST_RAISE) {
newRingerMode = AudioManager.RINGER_MODE_NORMAL;
} else if (direction == AudioManager.ADJUST_LOWER) {
newRingerMode = AudioManager.RINGER_MODE_SILENT;
}
} else if (direction == AudioManager.ADJUST_RAISE
&& mRingerMode == AudioManager.RINGER_MODE_SILENT) {
newRingerMode = AudioManager.RINGER_MODE_VIBRATE;
}
if (newRingerMode != mRingerMode) {
setRingerMode(newRingerMode);
/*
* If we are changing ringer modes, do not increment/decrement the
* volume index. Instead, the handler for the message above will
* take care of changing the index.
*/
adjustVolumeIndex = false;
}
return adjustVolumeIndex;
| private void | createAudioSystemThread()
mAudioSystemThread = new AudioSystemThread();
mAudioSystemThread.start();
waitForAudioHandlerCreation();
| private void | createStreamStates()
final int[] volumeLevelsPhone =
createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_VOICE_CALL]);
final int[] volumeLevelsCoarse =
createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_SYSTEM]);
final int[] volumeLevelsFine =
createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC]);
final int[] volumeLevelsBtPhone =
createVolumeLevels(0,
AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_BLUETOOTH_SCO]);
int numStreamTypes = AudioSystem.getNumStreamTypes();
VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
for (int i = 0; i < numStreamTypes; i++) {
final int[] levels;
switch (i) {
case AudioSystem.STREAM_MUSIC:
levels = volumeLevelsFine;
break;
case AudioSystem.STREAM_VOICE_CALL:
levels = volumeLevelsPhone;
break;
case AudioSystem.STREAM_BLUETOOTH_SCO:
levels = volumeLevelsBtPhone;
break;
default:
levels = volumeLevelsCoarse;
break;
}
if (i == AudioSystem.STREAM_BLUETOOTH_SCO) {
streams[i] = new VolumeStreamState(AudioManager.DEFAULT_STREAM_VOLUME[i], i,levels);
} else {
streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[i], i, levels);
}
}
| private static int[] | createVolumeLevels(int offset, int numlevels)
double curve = 1.0f; // 1.4f
int [] volumes = new int[numlevels + offset];
for (int i = 0; i < offset; i++) {
volumes[i] = 0;
}
double val = 0;
double max = Math.pow(numlevels - 1, curve);
for (int i = 0; i < numlevels; i++) {
val = Math.pow(i, curve) / max;
volumes[offset + i] = (int) (val * 100.0f);
}
return volumes;
| private void | ensureValidDirection(int direction)
if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
throw new IllegalArgumentException("Bad direction " + direction);
}
| private void | ensureValidStreamType(int streamType)
if (streamType < 0 || streamType >= mStreamStates.length) {
throw new IllegalArgumentException("Bad stream type " + streamType);
}
| private int | getActiveStreamType(int suggestedStreamType)
boolean isOffhook = false;
try {
ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
if (phone != null) isOffhook = phone.isOffhook();
} catch (RemoteException e) {
Log.w(TAG, "Couldn't connect to phone service", e);
}
if ((getRouting(AudioSystem.MODE_IN_CALL) & AudioSystem.ROUTE_BLUETOOTH_SCO) != 0) {
// Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
return AudioSystem.STREAM_BLUETOOTH_SCO;
} else if (isOffhook) {
// Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
return AudioSystem.STREAM_VOICE_CALL;
} else if (AudioSystem.isMusicActive()) {
// Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC...");
return AudioSystem.STREAM_MUSIC;
} else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
// Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING...");
return AudioSystem.STREAM_RING;
} else {
// Log.v(TAG, "getActiveStreamType: Returning suggested type " + suggestedStreamType);
return suggestedStreamType;
}
| public int | getMode()
return mMode;
| private static int | getMsg(int baseMsg, int streamType)
return (baseMsg & 0xffff) | streamType << 16;
| private static int | getMsgBase(int msg)
return msg & 0xffff;
| public int | getRingerMode()
return mRingerMode;
| public int | getRouting(int mode)
return mRoutes[mode];
| public int | getStreamMaxVolume(int streamType)
ensureValidStreamType(streamType);
return mStreamStates[streamType].getMaxIndex();
| public int | getStreamVolume(int streamType)
ensureValidStreamType(streamType);
return mStreamStates[streamType].mIndex;
| public static int | getValueForVibrateSetting(int existingValue, int vibrateType, int vibrateSetting)
// First clear the existing setting. Each vibrate type has two bits in
// the value. Note '3' is '11' in binary.
existingValue &= ~(3 << (vibrateType * 2));
// Set into the old value
existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
return existingValue;
| public int | getVibrateSetting(int vibrateType)
return (mVibrateSetting >> (vibrateType * 2)) & 3;
| public boolean | isMicrophoneMute()
return mMicMute;
| public boolean | isMusicActive()
return AudioSystem.isMusicActive();
| public boolean | isStreamAffectedByMute(int streamType)
return (mMuteAffectedStreams & (1 << streamType)) != 0;
| public boolean | isStreamAffectedByRingerMode(int streamType)
int ringerModeAffectedStreams = Settings.System.getInt(mContentResolver,
Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0);
return (ringerModeAffectedStreams & (1 << streamType)) != 0;
| public boolean | loadSoundEffects()Loads samples into the soundpool.
This method must be called at when sound effects are enabled
synchronized (mSoundEffectsLock) {
mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0);
if (mSoundPool == null) {
return false;
}
/*
* poolId table: The value -1 in this table indicates that corresponding
* file (same index in SOUND_EFFECT_FILES[] has not been loaded.
* Once loaded, the value in poolId is the sample ID and the same
* sample can be reused for another effect using the same file.
*/
int[] poolId = new int[SOUND_EFFECT_FILES.length];
for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) {
poolId[fileIdx] = -1;
}
/*
* Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
* If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
* this indicates we have a valid sample loaded for this effect.
*/
for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
// Do not load sample if this effect uses the MediaPlayer
if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
continue;
}
if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effect][0]];
int sampleId = mSoundPool.load(filePath, 0);
SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
if (sampleId <= 0) {
Log.w(TAG, "Soundpool could not load file: "+filePath);
}
} else {
SOUND_EFFECT_FILES_MAP[effect][1] = poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
}
}
}
return true;
| public void | playSoundEffect(int effectType)
sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP,
effectType, SOUND_EFFECT_VOLUME, null, 0);
| public void | playSoundEffectVolume(int effectType, float volume)
sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP,
effectType, (int) (volume * 1000), null, 0);
| private void | readAudioSettings()
synchronized (mSettingsLock) {
mMicMute = AudioSystem.isMicrophoneMuted();
mMode = AudioSystem.getMode();
for (int mode = 0; mode < AudioSystem.NUM_MODES; mode++) {
mRoutes[mode] = AudioSystem.getRouting(mode);
}
}
| private void | readPersistedSettings()
final ContentResolver cr = mContentResolver;
mRingerMode = System.getInt(cr, System.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
mVibrateSetting = System.getInt(cr, System.VIBRATE_ON, 0);
mMuteAffectedStreams = System.getInt(cr,
System.MUTE_STREAMS_AFFECTED,
((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM)));
// Each stream will read its own persisted settings
// Broadcast the sticky intent
broadcastRingerMode();
// Broadcast vibrate settings
broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
| private static void | sendMsg(android.os.Handler handler, int baseMsg, int streamType, int existingMsgPolicy, int arg1, int arg2, java.lang.Object obj, int delay)
int msg = (streamType == SHARED_MSG) ? baseMsg : getMsg(baseMsg, streamType);
if (existingMsgPolicy == SENDMSG_REPLACE) {
handler.removeMessages(msg);
} else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
return;
}
handler
.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
| private void | sendVolumeUpdate(int streamType)
Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, getStreamVolume(streamType));
// Currently, sending the intent only when the stream is BLUETOOTH_SCO
if (streamType == AudioManager.STREAM_BLUETOOTH_SCO) {
mContext.sendBroadcast(intent);
}
| public void | setMicrophoneMute(boolean on)
if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
return;
}
synchronized (mSettingsLock) {
if (on != mMicMute) {
AudioSystem.muteMicrophone(on);
mMicMute = on;
}
}
| public void | setMode(int mode)
if (!checkAudioSettingsPermission("setMode()")) {
return;
}
synchronized (mSettingsLock) {
if (mode != mMode) {
AudioSystem.setMode(mode);
mMode = mode;
}
int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
int index = mStreamStates[streamType].mIndex;
syncRingerAndNotificationStreamVolume(streamType, index, true);
setStreamVolumeInt(streamType, index, true);
}
| public void | setParameter(java.lang.String key, java.lang.String value)
AudioSystem.setParameter(key, value);
| public void | setRingerMode(int ringerMode)
if (ringerMode != mRingerMode) {
setRingerModeInt(ringerMode);
// Send sticky broadcast
broadcastRingerMode();
}
| private void | setRingerModeInt(int ringerMode)
mRingerMode = ringerMode;
// Adjust volumes via posting message
int numStreamTypes = AudioSystem.getNumStreamTypes();
if (mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
if (!isStreamAffectedByRingerMode(streamType)) continue;
// Bring back last audible volume
setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex,
false);
}
} else {
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
if (!isStreamAffectedByRingerMode(streamType)) continue;
// Either silent or vibrate, either way volume is 0
setStreamVolumeInt(streamType, 0, false);
}
}
// Post a persist ringer mode msg
sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, SHARED_MSG,
SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
| public void | setRouting(int mode, int routes, int mask)
if (!checkAudioSettingsPermission("setRouting()")) {
return;
}
synchronized (mSettingsLock) {
if ((mRoutes[mode] & mask) != (routes & mask)) {
AudioSystem.setRouting(mode, routes, mask);
mRoutes[mode] = (mRoutes[mode] & ~mask) | (routes & mask);
}
int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
int index = mStreamStates[streamType].mIndex;
syncRingerAndNotificationStreamVolume(streamType, index, true);
setStreamVolumeInt(streamType, index, true);
}
| public void | setStreamMute(int streamType, boolean state, android.os.IBinder cb)
if (isStreamAffectedByMute(streamType)) {
mStreamStates[streamType].mute(cb, state);
}
| public void | setStreamSolo(int streamType, boolean state, android.os.IBinder cb)
for (int stream = 0; stream < mStreamStates.length; stream++) {
if (!isStreamAffectedByMute(stream) || stream == streamType) continue;
// Bring back last audible volume
mStreamStates[stream].mute(cb, state);
}
| public void | setStreamVolume(int streamType, int index, int flags)
ensureValidStreamType(streamType);
syncRingerAndNotificationStreamVolume(streamType, index, false);
setStreamVolumeInt(streamType, index, false);
// UI, etc.
mVolumePanel.postVolumeChanged(streamType, flags);
// Broadcast Intent
sendVolumeUpdate(streamType);
| private void | setStreamVolumeInt(int streamType, int index, boolean force)Sets the stream state's index, and posts a message to set system volume.
This will not call out to the UI. Assumes a valid stream type.
VolumeStreamState streamState = mStreamStates[streamType];
if (streamState.setIndex(index) || force) {
// Post message to set system volume (it in turn will post a message
// to persist). Do not change volume if stream is muted.
if (streamState.muteCount() == 0) {
sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0,
streamState, 0);
}
}
| public void | setVibrateSetting(int vibrateType, int vibrateSetting)
mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
// Broadcast change
broadcastVibrateSetting(vibrateType);
// Post message to set ringer mode (it in turn will post a message
// to persist)
sendMsg(mAudioHandler, MSG_PERSIST_VIBRATE_SETTING, SHARED_MSG, SENDMSG_NOOP, 0, 0,
null, 0);
| public boolean | shouldVibrate(int vibrateType)
switch (getVibrateSetting(vibrateType)) {
case AudioManager.VIBRATE_SETTING_ON:
return mRingerMode != AudioManager.RINGER_MODE_SILENT;
case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
return mRingerMode == AudioManager.RINGER_MODE_VIBRATE;
case AudioManager.VIBRATE_SETTING_OFF:
// Phone ringer should always vibrate in vibrate mode
if (vibrateType == AudioManager.VIBRATE_TYPE_RINGER) {
return mRingerMode == AudioManager.RINGER_MODE_VIBRATE;
}
default:
return false;
}
| private void | syncRingerAndNotificationStreamVolume(int streamType, int index, boolean force)Sync the STREAM_RING and STREAM_NOTIFICATION volumes if mandated by the
value in Settings.
boolean notificationsUseRingVolume = Settings.System.getInt(mContentResolver,
Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1) == 1;
if (notificationsUseRingVolume) {
if (streamType == AudioManager.STREAM_NOTIFICATION) {
// Redirect the volume change to the ring stream
streamType = AudioManager.STREAM_RING;
}
if (streamType == AudioManager.STREAM_RING) {
// One-off to sync notification volume to ringer volume
setStreamVolumeInt(AudioManager.STREAM_NOTIFICATION, index, force);
}
}
| public void | unloadSoundEffects()Unloads samples from the sound pool.
This method can be called to free some memory when
sound effects are disabled.
synchronized (mSoundEffectsLock) {
if (mSoundPool == null) {
return;
}
int[] poolId = new int[SOUND_EFFECT_FILES.length];
for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) {
poolId[fileIdx] = 0;
}
for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
continue;
}
if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
SOUND_EFFECT_FILES_MAP[effect][1] = -1;
poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
}
}
mSoundPool = null;
}
| private void | waitForAudioHandlerCreation()Waits for the volume handler to be created by the other thread.
synchronized(this) {
while (mAudioHandler == null) {
try {
// Wait for mAudioHandler to be set by the other thread
wait();
} catch (InterruptedException e) {
Log.e(TAG, "Interrupted while waiting on volume handler.");
}
}
}
|
|