diff options
author | Eric Laurent <elaurent@google.com> | 2012-10-08 09:04:34 -0700 |
---|---|---|
committer | Eric Laurent <elaurent@google.com> | 2012-10-08 17:00:02 -0700 |
commit | dd45d01128423a82652a3c9d77fa393631d95229 (patch) | |
tree | 4687f5a52053ab197d9ecfb7bf1a1e5684346224 | |
parent | 0e2aade9f1cfbbbdb60889ca9e1399093eb542ac (diff) | |
download | frameworks_base-dd45d01128423a82652a3c9d77fa393631d95229.zip frameworks_base-dd45d01128423a82652a3c9d77fa393631d95229.tar.gz frameworks_base-dd45d01128423a82652a3c9d77fa393631d95229.tar.bz2 |
enforce camera sound according to country code
Use mcc config overlay mechanism to enforce camera shutter sounds
in countries where it is mandatory.
Property ro.camera.sound.forced is not needed anymore.
When camera sound is forced, STREAM_SYSTEM_ENFORCED is removed from
streams affected by ringer mode and its volume is
maxed out. AudioSystem.FORCE_SYSTEM_ENFORCED is sent to audio
policy manager to alter the routing policy for STREAM_SYSTEM_ENFORCED.
Also fix streams being unmuted when settings are reloaded
upon user switch while in silent mode.
Add ringer mode to audio service dump.
Bug 7032634.
Change-Id: Iceea5bba3b8d3aabf8e42b222deb33a893dc8f38
-rw-r--r-- | core/res/res/values-mcc440/config.xml | 25 | ||||
-rwxr-xr-x | core/res/res/values/config.xml | 3 | ||||
-rw-r--r-- | core/res/res/values/symbols.xml | 1 | ||||
-rw-r--r-- | media/java/android/media/AudioService.java | 212 | ||||
-rw-r--r-- | media/java/android/media/AudioSystem.java | 6 | ||||
-rw-r--r-- | media/java/android/media/IAudioService.aidl | 2 |
6 files changed, 211 insertions, 38 deletions
diff --git a/core/res/res/values-mcc440/config.xml b/core/res/res/values-mcc440/config.xml new file mode 100644 index 0000000..4ca1677 --- /dev/null +++ b/core/res/res/values-mcc440/config.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2012, 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. +*/ +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Whether camera shutter sound is forced or not (country specific). --> + <bool name="config_camera_sound_forced">true</bool> + +</resources> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 16960c8..a00f071 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -981,4 +981,7 @@ --> <bool name="config_wifiDisplaySupportsProtectedBuffers">false</bool> + <!-- Whether camera shutter sound is forced or not (country specific). --> + <bool name="config_camera_sound_forced">false</bool> + </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 281d92a..e615fd4 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -275,6 +275,7 @@ <java-symbol type="bool" name="config_enableWifiDisplay" /> <java-symbol type="bool" name="config_useDevInputEventForAudioJack" /> <java-symbol type="bool" name="config_safe_media_volume_enabled" /> + <java-symbol type="bool" name="config_camera_sound_forced" /> <java-symbol type="integer" name="config_cursorWindowSize" /> <java-symbol type="integer" name="config_longPressOnPowerBehavior" /> diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 7d17391..f26d322 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -462,7 +462,21 @@ public class AudioService extends IAudioService.Stub implements OnFinished { mVolumePanel = new VolumePanel(context, this); mMode = AudioSystem.MODE_NORMAL; mForcedUseForComm = AudioSystem.FORCE_NONE; + createAudioSystemThread(); + + boolean cameraSoundForced = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_camera_sound_forced); + mCameraSoundForced = new Boolean(cameraSoundForced); + sendMsg(mAudioHandler, + MSG_SET_FORCE_USE, + SENDMSG_QUEUE, + AudioSystem.FOR_SYSTEM, + cameraSoundForced ? + AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE, + null, + 0); + readPersistedSettings(); mSettingsObserver = new SettingsObserver(); updateStreamVolumeAlias(false /*updateVolumes*/); @@ -585,6 +599,8 @@ public class AudioService extends IAudioService.Stub implements OnFinished { mStreamStates[i].dump(pw); pw.println(""); } + pw.print("\n- mute affected streams = 0x"); + pw.println(Integer.toHexString(mMuteAffectedStreams)); } @@ -634,35 +650,44 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } synchronized(mSettingsLock) { mRingerMode = ringerMode; - } - // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting - // are still needed while setVibrateSetting() and getVibrateSetting() are being deprecated. - mVibrateSetting = getValueForVibrateSetting(0, - AudioManager.VIBRATE_TYPE_NOTIFICATION, - mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT - : AudioManager.VIBRATE_SETTING_OFF); - mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, - AudioManager.VIBRATE_TYPE_RINGER, - mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT - : AudioManager.VIBRATE_SETTING_OFF); - - // make sure settings for ringer mode are consistent with device type: non voice capable - // devices (tablets) include media stream in silent mode whereas phones don't. - mRingerModeAffectedStreams = Settings.System.getIntForUser(cr, - Settings.System.MODE_RINGER_STREAMS_AFFECTED, - ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)| - (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)), - UserHandle.USER_CURRENT); - if (mVoiceCapable) { - mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC); - } else { - mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC); + // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting + // are still needed while setVibrateSetting() and getVibrateSetting() are being + // deprecated. + mVibrateSetting = getValueForVibrateSetting(0, + AudioManager.VIBRATE_TYPE_NOTIFICATION, + mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT + : AudioManager.VIBRATE_SETTING_OFF); + mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, + AudioManager.VIBRATE_TYPE_RINGER, + mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT + : AudioManager.VIBRATE_SETTING_OFF); + + // make sure settings for ringer mode are consistent with device type: non voice capable + // devices (tablets) include media stream in silent mode whereas phones don't. + mRingerModeAffectedStreams = Settings.System.getIntForUser(cr, + Settings.System.MODE_RINGER_STREAMS_AFFECTED, + ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)| + (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)), + UserHandle.USER_CURRENT); + if (mVoiceCapable) { + mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC); + } else { + mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC); + } + synchronized (mCameraSoundForced) { + if (mCameraSoundForced) { + mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED); + } else { + mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED); + } + } + + Settings.System.putIntForUser(cr, + Settings.System.MODE_RINGER_STREAMS_AFFECTED, + mRingerModeAffectedStreams, + UserHandle.USER_CURRENT); } - Settings.System.putIntForUser(cr, - Settings.System.MODE_RINGER_STREAMS_AFFECTED, - mRingerModeAffectedStreams, - UserHandle.USER_CURRENT); mMuteAffectedStreams = System.getIntForUser(cr, System.MUTE_STREAMS_AFFECTED, @@ -2601,12 +2626,18 @@ public class AudioService extends IAudioService.Stub implements OnFinished { // only be stale values // on first call to readSettings() at init time, muteCount() is always 0 so we will // always create entries for default device - if ((muteCount() == 0) && (mStreamType == AudioSystem.STREAM_SYSTEM) || + if ((mStreamType == AudioSystem.STREAM_SYSTEM) || (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) { - mLastAudibleIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, - 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]); - mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, - 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]); + int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]; + synchronized (mCameraSoundForced) { + if (mCameraSoundForced) { + index = mIndexMax; + } + } + if (muteCount() == 0) { + mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index); + } + mLastAudibleIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index); return; } @@ -2618,10 +2649,11 @@ public class AudioService extends IAudioService.Stub implements OnFinished { remainingDevices &= ~device; // ignore settings for fixed volume devices: volume should always be at max - if ((muteCount() == 0) && - (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) && + if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) && ((device & mFixedVolumeDevices) != 0)) { - mIndex.put(device, mIndexMax); + if (muteCount() == 0) { + mIndex.put(device, mIndexMax); + } mLastAudibleIndex.put(device, mIndexMax); continue; } @@ -2676,7 +2708,9 @@ public class AudioService extends IAudioService.Stub implements OnFinished { this, PERSIST_DELAY); } - mIndex.put(device, getValidIndex(10 * index)); + if (muteCount() == 0) { + mIndex.put(device, getValidIndex(10 * index)); + } } } @@ -2716,6 +2750,11 @@ public class AudioService extends IAudioService.Stub implements OnFinished { public synchronized boolean setIndex(int index, int device, boolean lastAudible) { int oldIndex = getIndex(device, false /* lastAudible */); index = getValidIndex(index); + synchronized (mCameraSoundForced) { + if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) { + index = mIndexMax; + } + } mIndex.put(device, getValidIndex(index)); if (oldIndex != index) { @@ -2819,6 +2858,21 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } } + public synchronized void setAllIndexesToMax() { + Set set = mIndex.entrySet(); + Iterator i = set.iterator(); + while (i.hasNext()) { + Map.Entry entry = (Map.Entry)i.next(); + entry.setValue(mIndexMax); + } + set = mLastAudibleIndex.entrySet(); + i = set.iterator(); + while (i.hasNext()) { + Map.Entry entry = (Map.Entry)i.next(); + entry.setValue(mIndexMax); + } + } + public synchronized void mute(IBinder cb, boolean state) { VolumeDeathHandler handler = getDeathHandler(cb, state); if (handler == null) { @@ -2967,6 +3021,8 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } private void dump(PrintWriter pw) { + pw.print(" Mute count: "); + pw.println(muteCount()); pw.print(" Current: "); Set set = mIndex.entrySet(); Iterator i = set.iterator(); @@ -3215,6 +3271,8 @@ public class AudioService extends IAudioService.Stub implements OnFinished { // Restore forced usage for communcations and record AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm); AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm); + AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ? + AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE); // Restore stream volumes int numStreamTypes = AudioSystem.getNumStreamTypes(); @@ -3372,6 +3430,13 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } else { ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC); } + synchronized (mCameraSoundForced) { + if (mCameraSoundForced) { + ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED); + } else { + ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED); + } + } if (ringerModeAffectedStreams != mRingerModeAffectedStreams) { /* * Ensure all stream types that should be affected by ringer mode @@ -5587,6 +5652,48 @@ public class AudioService extends IAudioService.Stub implements OnFinished { 0, null, 0); + + boolean cameraSoundForced = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_camera_sound_forced); + synchronized (mSettingsLock) { + synchronized (mCameraSoundForced) { + if (cameraSoundForced != mCameraSoundForced) { + mCameraSoundForced = cameraSoundForced; + + VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED]; + if (cameraSoundForced) { + s.setAllIndexesToMax(); + mRingerModeAffectedStreams &= + ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED); + } else { + s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], + false /*lastAudible*/); + s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], + true /*lastAudible*/); + mRingerModeAffectedStreams |= + (1 << AudioSystem.STREAM_SYSTEM_ENFORCED); + } + // take new state into account for streams muted by ringer mode + setRingerModeInt(getRingerMode(), false); + + sendMsg(mAudioHandler, + MSG_SET_FORCE_USE, + SENDMSG_QUEUE, + AudioSystem.FOR_SYSTEM, + cameraSoundForced ? + AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE, + null, + 0); + + sendMsg(mAudioHandler, + MSG_SET_ALL_VOLUMES, + SENDMSG_QUEUE, + 0, + 0, + mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0); + } + } + } } catch (Exception e) { Log.e(TAG, "Error retrieving device orientation: " + e); } @@ -5762,6 +5869,38 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } + //========================================================================================== + // Camera shutter sound policy. + // config_camera_sound_forced configuration option in config.xml defines if the camera shutter + // sound is forced (sound even if the device is in silent mode) or not. This option is false by + // default and can be overridden by country specific overlay in values-mccXXX/config.xml. + //========================================================================================== + + // cached value of com.android.internal.R.bool.config_camera_sound_forced + private Boolean mCameraSoundForced; + + // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound + public boolean isCameraSoundForced() { + synchronized (mCameraSoundForced) { + return mCameraSoundForced; + } + } + + private static final String[] RINGER_MODE_NAMES = new String[] { + "SILENT", + "VIBRATE", + "NORMAL" + }; + + private void dumpRingerMode(PrintWriter pw) { + pw.println("\nRinger mode: "); + pw.println("- mode: "+RINGER_MODE_NAMES[mRingerMode]); + pw.print("- ringer mode affected streams = 0x"); + pw.println(Integer.toHexString(mRingerModeAffectedStreams)); + pw.print("- ringer mode muted streams = 0x"); + pw.println(Integer.toHexString(mRingerModeMutedStreams)); + } + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); @@ -5770,6 +5909,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { dumpRCStack(pw); dumpRCCStack(pw); dumpStreamStates(pw); + dumpRingerMode(pw); pw.println("\nAudio routes:"); pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType)); pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName); diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 2cff4ff..103e817 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -354,7 +354,8 @@ public class AudioSystem public static final int FORCE_DIGITAL_DOCK = 9; public static final int FORCE_NO_BT_A2DP = 10; public static final int FORCE_REMOTE_SUBMIX = 11; - private static final int NUM_FORCE_CONFIG = 12; + public static final int FORCE_SYSTEM_ENFORCED = 12; + private static final int NUM_FORCE_CONFIG = 13; public static final int FORCE_DEFAULT = FORCE_NONE; // usage for setForceUse, must match AudioSystem::force_use @@ -362,7 +363,8 @@ public class AudioSystem public static final int FOR_MEDIA = 1; public static final int FOR_RECORD = 2; public static final int FOR_DOCK = 3; - private static final int NUM_FORCE_USE = 4; + public static final int FOR_SYSTEM = 4; + private static final int NUM_FORCE_USE = 5; // usage for AudioRecord.startRecordingSync(), must match AudioSystem::sync_event_t public static final int SYNC_EVENT_NONE = 0; diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 7ae61cd..ea99069 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -153,4 +153,6 @@ interface IAudioService { int setBluetoothA2dpDeviceConnectionState(in BluetoothDevice device, int state); AudioRoutesInfo startWatchingRoutes(in IAudioRoutesObserver observer); + + boolean isCameraSoundForced(); } |