diff options
author | Eric Laurent <elaurent@google.com> | 2012-04-23 18:42:39 -0700 |
---|---|---|
committer | Eric Laurent <elaurent@google.com> | 2012-04-26 18:36:56 -0700 |
commit | 6d5176638c2189595cede38fb92c3e7e8700e221 (patch) | |
tree | 27b673ef8d8ca32894e8b62d64e40f52403d63c6 | |
parent | f18222da3cdfd3b052361369b70a4d22396039c1 (diff) | |
download | frameworks_base-6d5176638c2189595cede38fb92c3e7e8700e221.zip frameworks_base-6d5176638c2189595cede38fb92c3e7e8700e221.tar.gz frameworks_base-6d5176638c2189595cede38fb92c3e7e8700e221.tar.bz2 |
system and UI sounds volume policy
Implement a more consistent policy for system and UI sounds (key clicks, lock/unlock,
camera shutter, DTMF, low battery...):
- All system sounds are played over STREAM_SYSTEM stream type.
- The STREAM_SYSTEM volume that was previously fixed now tracks the volume of a "master"
stream type. This "master" stream type is STREAM_RING for phones and STREAM_MUSIC for
tablets which corresponds to the stream whose volume is modified by default by the volume
keys.
- The STREAM_SYSTEM volume ranges from -24dB to -6dB (-24dB to -12dB over headphones) when the
"master" stream volume ranges from its min to its max.
- DTMF tones are played over STREAM_DTMF that tracks the "master" stream volume in the same
manner with the following exception: when in call, DTMF stream tracks STREAM_VOICE_CALL volume.
- Camera shutter sound is played over STREAM_SYSTEM_ENFORCED stream that tracks the "master"
stream volume except in countries where regulation enforces this sound. In this case
its volume is fixed and cannot be muted.
- Low battery sound is played over STREAM_SYSTEM and therefore has a tunable volume and is
heard while in call.
Issue 6344620.
Issue 6069229.
Issue 6213100.
Change-Id: I53a237878ead596e706c5dbbb1420e62cde32bd7
5 files changed, 149 insertions, 61 deletions
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 012e095..2a006c6 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -701,6 +701,21 @@ public class AudioManager { } /** + * Get the stream type whose volume is driving the UI sounds volume. + * UI sounds are screen lock/unlock, camera shutter, key clicks... + * @hide + */ + public int getMasterStreamType() { + IAudioService service = getService(); + try { + return service.getMasterStreamType(); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in getMasterStreamType", e); + return STREAM_RING; + } + } + + /** * Sets the ringer mode. * <p> * Silent mode will mute the volume and will not vibrate. Vibrate mode will diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index dcf72cc..dddb443 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -202,22 +202,39 @@ public class AudioService extends IAudioService.Stub { 15, // STREAM_DTMF 15 // STREAM_TTS }; - /* STREAM_VOLUME_ALIAS[] indicates for each stream if it uses the volume settings + /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings * of another stream: This avoids multiplying the volume settings for hidden * stream types that follow other stream behavior for volume settings - * NOTE: do not create loops in aliases! */ + * NOTE: do not create loops in aliases! + * Some streams alias to different streams according to device category (phone or tablet) or + * use case (in call s off call...).See updateStreamVolumeAlias() for more details + * mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and + * STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/ private final int[] STREAM_VOLUME_ALIAS = new int[] { - AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL - AudioSystem.STREAM_SYSTEM, // STREAM_SYSTEM - AudioSystem.STREAM_RING, // STREAM_RING - AudioSystem.STREAM_MUSIC, // STREAM_MUSIC - AudioSystem.STREAM_ALARM, // STREAM_ALARM - AudioSystem.STREAM_RING, // STREAM_NOTIFICATION - AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO - AudioSystem.STREAM_SYSTEM, // STREAM_SYSTEM_ENFORCED - AudioSystem.STREAM_VOICE_CALL, // STREAM_DTMF - AudioSystem.STREAM_MUSIC // STREAM_TTS + AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL + AudioSystem.STREAM_RING, // STREAM_SYSTEM + AudioSystem.STREAM_RING, // STREAM_RING + AudioSystem.STREAM_MUSIC, // STREAM_MUSIC + AudioSystem.STREAM_ALARM, // STREAM_ALARM + AudioSystem.STREAM_RING, // STREAM_NOTIFICATION + AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO + AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED + AudioSystem.STREAM_RING, // STREAM_DTMF + AudioSystem.STREAM_MUSIC // STREAM_TTS }; + private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] { + AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL + AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM + AudioSystem.STREAM_RING, // STREAM_RING + AudioSystem.STREAM_MUSIC, // STREAM_MUSIC + AudioSystem.STREAM_ALARM, // STREAM_ALARM + AudioSystem.STREAM_RING, // STREAM_NOTIFICATION + AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO + AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED + AudioSystem.STREAM_MUSIC, // STREAM_DTMF + AudioSystem.STREAM_MUSIC // STREAM_TTS + }; + private int[] mStreamVolumeAlias; private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() { public void onError(int error) { @@ -333,7 +350,7 @@ public class AudioService extends IAudioService.Stub { // message looper for SoundPool listener private Looper mSoundPoolLooper = null; // default volume applied to sound played with playSoundEffect() - private static final int SOUND_EFFECT_DEFAULT_VOLUME_DB = -20; + private static final int SOUND_EFFECT_DEFAULT_VOLUME_DB = 0; // volume applied to sound played with playSoundEffect() read from ro.config.sound_fx_volume private int SOUND_EFFECT_VOLUME_DB; // getActiveStreamType() will return STREAM_NOTIFICATION during this period after a notification @@ -374,13 +391,14 @@ public class AudioService extends IAudioService.Stub { SOUND_EFFECT_DEFAULT_VOLUME_DB); mVolumePanel = new VolumePanel(context, this); + mMode = AudioSystem.MODE_NORMAL; mForcedUseForComm = AudioSystem.FORCE_NONE; createAudioSystemThread(); readPersistedSettings(); mSettingsObserver = new SettingsObserver(); + updateStreamVolumeAlias(false /*updateVolumes*/); createStreamStates(); - mMode = AudioSystem.MODE_NORMAL; mMediaServerOk = true; // Call setRingerModeInt() to apply correct mute @@ -459,26 +477,54 @@ public class AudioService extends IAudioService.Stub { VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; for (int i = 0; i < numStreamTypes; i++) { - streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[STREAM_VOLUME_ALIAS[i]], i); + streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i); } // Correct stream index values for streams with aliases for (int i = 0; i < numStreamTypes; i++) { int device = getDeviceForStream(i); - if (STREAM_VOLUME_ALIAS[i] != i) { + if (mStreamVolumeAlias[i] != i) { int index = rescaleIndex(streams[i].getIndex(device, false /* lastAudible */), - STREAM_VOLUME_ALIAS[i], + mStreamVolumeAlias[i], i); streams[i].mIndex.put(device, streams[i].getValidIndex(index)); streams[i].applyDeviceVolume(device); index = rescaleIndex(streams[i].getIndex(device, true /* lastAudible */), - STREAM_VOLUME_ALIAS[i], + mStreamVolumeAlias[i], i); streams[i].mLastAudibleIndex.put(device, streams[i].getValidIndex(index)); } } } + + private void updateStreamVolumeAlias(boolean updateVolumes) { + int dtmfStreamAlias; + if (mVoiceCapable) { + mStreamVolumeAlias = STREAM_VOLUME_ALIAS; + dtmfStreamAlias = AudioSystem.STREAM_RING; + } else { + mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE; + dtmfStreamAlias = AudioSystem.STREAM_MUSIC; + } + if (isInCommunication()) { + dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL; + } + mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias; + if (updateVolumes) { + mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias], + false /*lastAudible*/); + mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias], + true /*lastAudible*/); + sendMsg(mAudioHandler, + MSG_SET_ALL_VOLUMES, + SENDMSG_QUEUE, + 0, + 0, + mStreamStates[AudioSystem.STREAM_DTMF], 0); + } + } + private void readPersistedSettings() { final ContentResolver cr = mContentResolver; @@ -555,7 +601,7 @@ public class AudioService extends IAudioService.Stub { // Play sounds on STREAM_RING only and if lock screen is not on. if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && - ((STREAM_VOLUME_ALIAS[streamType] != AudioSystem.STREAM_RING) + ((mStreamVolumeAlias[streamType] != AudioSystem.STREAM_RING) || (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) { flags &= ~AudioManager.FLAG_PLAY_SOUND; } @@ -571,7 +617,7 @@ public class AudioService extends IAudioService.Stub { // use stream type alias here so that streams with same alias have the same behavior, // including with regard to silent mode control (e.g the use of STREAM_RING below and in // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION) - int streamTypeAlias = STREAM_VOLUME_ALIAS[streamType]; + int streamTypeAlias = mStreamVolumeAlias[streamType]; VolumeStreamState streamState = mStreamStates[streamTypeAlias]; final int device = getDeviceForStream(streamTypeAlias); @@ -603,7 +649,7 @@ public class AudioService extends IAudioService.Stub { // on last audible index for an alias would not give the correct value int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int i = numStreamTypes - 1; i >= 0; i--) { - if (STREAM_VOLUME_ALIAS[i] == streamTypeAlias) { + if (mStreamVolumeAlias[i] == streamTypeAlias) { VolumeStreamState s = mStreamStates[i]; s.adjustLastAudibleIndex(direction, device); @@ -656,7 +702,7 @@ public class AudioService extends IAudioService.Stub { /** @see AudioManager#setStreamVolume(int, int, int) */ public void setStreamVolume(int streamType, int index, int flags) { ensureValidStreamType(streamType); - VolumeStreamState streamState = mStreamStates[STREAM_VOLUME_ALIAS[streamType]]; + VolumeStreamState streamState = mStreamStates[mStreamVolumeAlias[streamType]]; final int device = getDeviceForStream(streamType); // get last audible index if stream is muted, current index otherwise @@ -665,13 +711,13 @@ public class AudioService extends IAudioService.Stub { // setting ring or notifications volume to 0 on voice capable devices enters silent mode if (mVoiceCapable && (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || - (STREAM_VOLUME_ALIAS[streamType] == AudioSystem.STREAM_RING))) { + (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING))) { int newRingerMode; if (index == 0) { newRingerMode = System.getInt(mContentResolver, System.VIBRATE_IN_SILENT, 1) == 1 ? AudioManager.RINGER_MODE_VIBRATE : AudioManager.RINGER_MODE_SILENT; - setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], + setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false, @@ -682,8 +728,8 @@ public class AudioService extends IAudioService.Stub { setRingerMode(newRingerMode); } - index = rescaleIndex(index * 10, streamType, STREAM_VOLUME_ALIAS[streamType]); - setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, device, false, true); + index = rescaleIndex(index * 10, streamType, mStreamVolumeAlias[streamType]); + setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false, true); // get last audible index if stream is muted, current index otherwise index = streamState.getIndex(device, (streamState.muteCount() != 0) /* lastAudible */); @@ -964,6 +1010,15 @@ public class AudioService extends IAudioService.Stub { return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME); } + /** @see AudioManager#getMasterStreamType(int) */ + public int getMasterStreamType() { + if (mVoiceCapable) { + return AudioSystem.STREAM_RING; + } else { + return AudioSystem.STREAM_MUSIC; + } + } + /** @see AudioManager#getRingerMode() */ public int getRingerMode() { synchronized(mSettingsLock) { @@ -1004,7 +1059,7 @@ public class AudioService extends IAudioService.Stub { // ring and notifications volume should never be 0 when not silenced // on voice capable devices if (mVoiceCapable && - STREAM_VOLUME_ALIAS[streamType] == AudioSystem.STREAM_RING) { + mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) { Set set = mStreamStates[streamType].mLastAudibleIndex.entrySet(); Iterator i = set.iterator(); @@ -1244,8 +1299,10 @@ public class AudioService extends IAudioService.Stub { } int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); int device = getDeviceForStream(streamType); - int index = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].getIndex(device, false); - setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, device, true, false); + int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device, false); + setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, false); + + updateStreamVolumeAlias(true /*updateVolumes*/); } return newModeOwnerPid; } @@ -1978,18 +2035,23 @@ public class AudioService extends IAudioService.Stub { } } - private int getActiveStreamType(int suggestedStreamType) { + private boolean isInCommunication() { + boolean isOffhook = false; if (mVoiceCapable) { - 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); } + } + return (isOffhook || getMode() == AudioManager.MODE_IN_COMMUNICATION); + } - if (isOffhook || getMode() == AudioManager.MODE_IN_COMMUNICATION) { + private int getActiveStreamType(int suggestedStreamType) { + if (mVoiceCapable) { + if (isInCommunication()) { if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) == AudioSystem.FORCE_BT_SCO) { // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); @@ -2010,7 +2072,7 @@ public class AudioService extends IAudioService.Stub { return suggestedStreamType; } } else { - if (getMode() == AudioManager.MODE_IN_COMMUNICATION) { + if (isInCommunication()) { if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) == AudioSystem.FORCE_BT_SCO) { // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); @@ -2181,7 +2243,7 @@ public class AudioService extends IAudioService.Stub { // 0 without the device being in silent mode if ((lastAudibleIndex == 0) && (mVoiceCapable || - (STREAM_VOLUME_ALIAS[mStreamType] != AudioSystem.STREAM_MUSIC))) { + (mStreamVolumeAlias[mStreamType] != AudioSystem.STREAM_MUSIC))) { lastAudibleIndex = AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]; // Correct the data base sendMsg(mAudioHandler, @@ -2198,7 +2260,7 @@ public class AudioService extends IAudioService.Stub { // this is permitted on tablets for music stream type. if (checkSilentVolume && (index == 0) && (mVoiceCapable || - (STREAM_VOLUME_ALIAS[mStreamType] != AudioSystem.STREAM_MUSIC))) { + (mStreamVolumeAlias[mStreamType] != AudioSystem.STREAM_MUSIC))) { index = lastAudibleIndex; // Correct the data base sendMsg(mAudioHandler, @@ -2258,11 +2320,11 @@ public class AudioService extends IAudioService.Stub { // Apply change to all streams using this one as alias int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { - if (streamType != mStreamType && STREAM_VOLUME_ALIAS[streamType] == mStreamType) { + if (streamType != mStreamType && mStreamVolumeAlias[streamType] == mStreamType) { mStreamStates[streamType].setIndex(rescaleIndex(index, mStreamType, streamType), - device, + getDeviceForStream(streamType), lastAudible); } } @@ -2301,6 +2363,27 @@ public class AudioService extends IAudioService.Stub { return mIndexMax; } + public HashMap <Integer, Integer> getAllIndexes(boolean lastAudible) { + if (lastAudible) { + return mLastAudibleIndex; + } else { + return mIndex; + } + } + + public void setAllIndexes(VolumeStreamState srcStream, boolean lastAudible) { + HashMap <Integer, Integer> indexes = srcStream.getAllIndexes(lastAudible); + Set set = indexes.entrySet(); + Iterator i = set.iterator(); + while (i.hasNext()) { + Map.Entry entry = (Map.Entry)i.next(); + int device = ((Integer)entry.getKey()).intValue(); + int index = ((Integer)entry.getValue()).intValue(); + index = rescaleIndex(index, srcStream.getStreamType(), mStreamType); + setIndex(index, device, lastAudible); + } + } + public void mute(IBinder cb, boolean state) { VolumeDeathHandler handler = getDeathHandler(cb, state); if (handler == null) { @@ -2310,6 +2393,10 @@ public class AudioService extends IAudioService.Stub { handler.mute(state); } + public int getStreamType() { + return mStreamType; + } + private int getValidIndex(int index) { if (index < 0) { return 0; @@ -2484,8 +2571,8 @@ public class AudioService extends IAudioService.Stub { int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { if (streamType != streamState.mStreamType && - STREAM_VOLUME_ALIAS[streamType] == streamState.mStreamType) { - mStreamStates[streamType].applyDeviceVolume(device); + mStreamVolumeAlias[streamType] == streamState.mStreamType) { + mStreamStates[streamType].applyDeviceVolume(getDeviceForStream(streamType)); } } @@ -2509,7 +2596,7 @@ public class AudioService extends IAudioService.Stub { int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { if (streamType != streamState.mStreamType && - STREAM_VOLUME_ALIAS[streamType] == streamState.mStreamType) { + mStreamVolumeAlias[streamType] == streamState.mStreamType) { mStreamStates[streamType].applyAllVolumes(); } } diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 0311c59..df21040 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -117,4 +117,6 @@ interface IAudioService { void stopBluetoothSco(IBinder cb); void forceVolumeControlStream(int streamType, IBinder cb); + + int getMasterStreamType(); } diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java index fe7d5aa..3c30f5d 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java @@ -241,7 +241,7 @@ public class PowerUI extends SystemUI { if (soundUri != null) { final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri); if (sfx != null) { - sfx.setStreamType(AudioManager.STREAM_NOTIFICATION); + sfx.setStreamType(AudioManager.STREAM_SYSTEM); sfx.play(); } } diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java index 5b9160d..fec9530 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -149,11 +149,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private static final boolean ENABLE_INSECURE_STATUS_BAR_EXPAND = true; /** The stream type that the lock sounds are tied to. */ - private static final int MASTER_STREAM_TYPE = AudioManager.STREAM_RING; - /** Minimum volume for lock sounds, as a ratio of max MASTER_STREAM_TYPE */ - final float MIN_LOCK_VOLUME = 0.05f; - /** Maximum volume for lock sounds, as a ratio of max MASTER_STREAM_TYPE */ - final float MAX_LOCK_VOLUME = 0.4f; + private int mMasterStreamType; private Context mContext; private AlarmManager mAlarmManager; @@ -1142,24 +1138,12 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (mAudioManager == null) { mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); if (mAudioManager == null) return; - mMasterStreamMaxVolume = mAudioManager.getStreamMaxVolume(MASTER_STREAM_TYPE); + mMasterStreamType = mAudioManager.getMasterStreamType(); } // If the stream is muted, don't play the sound - if (mAudioManager.isStreamMute(MASTER_STREAM_TYPE)) return; + if (mAudioManager.isStreamMute(mMasterStreamType)) return; - // Adjust the lock sound volume from a minimum of MIN_LOCK_VOLUME to a maximum - // of MAX_LOCK_VOLUME, relative to the maximum level of the MASTER_STREAM_TYPE volume. - float lockSoundVolume; - int masterStreamVolume = mAudioManager.getStreamVolume(MASTER_STREAM_TYPE); - if (masterStreamVolume == 0) { - return; - } else { - lockSoundVolume = MIN_LOCK_VOLUME + (MAX_LOCK_VOLUME - MIN_LOCK_VOLUME) - * ((float) masterStreamVolume / mMasterStreamMaxVolume); - } - - mLockSoundStreamId = mLockSounds.play(whichSound, lockSoundVolume, lockSoundVolume, 1, - 0, 1.0f); + mLockSoundStreamId = mLockSounds.play(whichSound, 1.0f, 1.0f, 1, 0, 1.0f); } } |