Skip to content

Commit dd45d01

Browse files
author
Eric Laurent
committed
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
1 parent 0e2aade commit dd45d01

File tree

6 files changed

+211
-38
lines changed

6 files changed

+211
-38
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
/*
4+
** Copyright 2012, The Android Open Source Project
5+
**
6+
** Licensed under the Apache License, Version 2.0 (the "License");
7+
** you may not use this file except in compliance with the License.
8+
** You may obtain a copy of the License at
9+
**
10+
** http://www.apache.org/licenses/LICENSE-2.0
11+
**
12+
** Unless required by applicable law or agreed to in writing, software
13+
** distributed under the License is distributed on an "AS IS" BASIS,
14+
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
** See the License for the specific language governing permissions and
16+
** limitations under the License.
17+
*/
18+
-->
19+
20+
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
21+
22+
<!-- Whether camera shutter sound is forced or not (country specific). -->
23+
<bool name="config_camera_sound_forced">true</bool>
24+
25+
</resources>

core/res/res/values/config.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,4 +981,7 @@
981981
-->
982982
<bool name="config_wifiDisplaySupportsProtectedBuffers">false</bool>
983983

984+
<!-- Whether camera shutter sound is forced or not (country specific). -->
985+
<bool name="config_camera_sound_forced">false</bool>
986+
984987
</resources>

core/res/res/values/symbols.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@
275275
<java-symbol type="bool" name="config_enableWifiDisplay" />
276276
<java-symbol type="bool" name="config_useDevInputEventForAudioJack" />
277277
<java-symbol type="bool" name="config_safe_media_volume_enabled" />
278+
<java-symbol type="bool" name="config_camera_sound_forced" />
278279

279280
<java-symbol type="integer" name="config_cursorWindowSize" />
280281
<java-symbol type="integer" name="config_longPressOnPowerBehavior" />

media/java/android/media/AudioService.java

Lines changed: 176 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,21 @@ public AudioService(Context context) {
462462
mVolumePanel = new VolumePanel(context, this);
463463
mMode = AudioSystem.MODE_NORMAL;
464464
mForcedUseForComm = AudioSystem.FORCE_NONE;
465+
465466
createAudioSystemThread();
467+
468+
boolean cameraSoundForced = mContext.getResources().getBoolean(
469+
com.android.internal.R.bool.config_camera_sound_forced);
470+
mCameraSoundForced = new Boolean(cameraSoundForced);
471+
sendMsg(mAudioHandler,
472+
MSG_SET_FORCE_USE,
473+
SENDMSG_QUEUE,
474+
AudioSystem.FOR_SYSTEM,
475+
cameraSoundForced ?
476+
AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
477+
null,
478+
0);
479+
466480
readPersistedSettings();
467481
mSettingsObserver = new SettingsObserver();
468482
updateStreamVolumeAlias(false /*updateVolumes*/);
@@ -585,6 +599,8 @@ private void dumpStreamStates(PrintWriter pw) {
585599
mStreamStates[i].dump(pw);
586600
pw.println("");
587601
}
602+
pw.print("\n- mute affected streams = 0x");
603+
pw.println(Integer.toHexString(mMuteAffectedStreams));
588604
}
589605

590606

@@ -634,35 +650,44 @@ private void readPersistedSettings() {
634650
}
635651
synchronized(mSettingsLock) {
636652
mRingerMode = ringerMode;
637-
}
638653

639-
// System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
640-
// are still needed while setVibrateSetting() and getVibrateSetting() are being deprecated.
641-
mVibrateSetting = getValueForVibrateSetting(0,
642-
AudioManager.VIBRATE_TYPE_NOTIFICATION,
643-
mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
644-
: AudioManager.VIBRATE_SETTING_OFF);
645-
mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
646-
AudioManager.VIBRATE_TYPE_RINGER,
647-
mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
648-
: AudioManager.VIBRATE_SETTING_OFF);
649-
650-
// make sure settings for ringer mode are consistent with device type: non voice capable
651-
// devices (tablets) include media stream in silent mode whereas phones don't.
652-
mRingerModeAffectedStreams = Settings.System.getIntForUser(cr,
653-
Settings.System.MODE_RINGER_STREAMS_AFFECTED,
654-
((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
655-
(1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
656-
UserHandle.USER_CURRENT);
657-
if (mVoiceCapable) {
658-
mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
659-
} else {
660-
mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
654+
// System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
655+
// are still needed while setVibrateSetting() and getVibrateSetting() are being
656+
// deprecated.
657+
mVibrateSetting = getValueForVibrateSetting(0,
658+
AudioManager.VIBRATE_TYPE_NOTIFICATION,
659+
mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
660+
: AudioManager.VIBRATE_SETTING_OFF);
661+
mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
662+
AudioManager.VIBRATE_TYPE_RINGER,
663+
mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
664+
: AudioManager.VIBRATE_SETTING_OFF);
665+
666+
// make sure settings for ringer mode are consistent with device type: non voice capable
667+
// devices (tablets) include media stream in silent mode whereas phones don't.
668+
mRingerModeAffectedStreams = Settings.System.getIntForUser(cr,
669+
Settings.System.MODE_RINGER_STREAMS_AFFECTED,
670+
((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
671+
(1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
672+
UserHandle.USER_CURRENT);
673+
if (mVoiceCapable) {
674+
mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
675+
} else {
676+
mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
677+
}
678+
synchronized (mCameraSoundForced) {
679+
if (mCameraSoundForced) {
680+
mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
681+
} else {
682+
mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
683+
}
684+
}
685+
686+
Settings.System.putIntForUser(cr,
687+
Settings.System.MODE_RINGER_STREAMS_AFFECTED,
688+
mRingerModeAffectedStreams,
689+
UserHandle.USER_CURRENT);
661690
}
662-
Settings.System.putIntForUser(cr,
663-
Settings.System.MODE_RINGER_STREAMS_AFFECTED,
664-
mRingerModeAffectedStreams,
665-
UserHandle.USER_CURRENT);
666691

667692
mMuteAffectedStreams = System.getIntForUser(cr,
668693
System.MUTE_STREAMS_AFFECTED,
@@ -2601,12 +2626,18 @@ public synchronized void readSettings() {
26012626
// only be stale values
26022627
// on first call to readSettings() at init time, muteCount() is always 0 so we will
26032628
// always create entries for default device
2604-
if ((muteCount() == 0) && (mStreamType == AudioSystem.STREAM_SYSTEM) ||
2629+
if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
26052630
(mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
2606-
mLastAudibleIndex.put(AudioSystem.DEVICE_OUT_DEFAULT,
2607-
10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]);
2608-
mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT,
2609-
10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]);
2631+
int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
2632+
synchronized (mCameraSoundForced) {
2633+
if (mCameraSoundForced) {
2634+
index = mIndexMax;
2635+
}
2636+
}
2637+
if (muteCount() == 0) {
2638+
mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
2639+
}
2640+
mLastAudibleIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
26102641
return;
26112642
}
26122643

@@ -2618,10 +2649,11 @@ public synchronized void readSettings() {
26182649
remainingDevices &= ~device;
26192650

26202651
// ignore settings for fixed volume devices: volume should always be at max
2621-
if ((muteCount() == 0) &&
2622-
(mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) &&
2652+
if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) &&
26232653
((device & mFixedVolumeDevices) != 0)) {
2624-
mIndex.put(device, mIndexMax);
2654+
if (muteCount() == 0) {
2655+
mIndex.put(device, mIndexMax);
2656+
}
26252657
mLastAudibleIndex.put(device, mIndexMax);
26262658
continue;
26272659
}
@@ -2676,7 +2708,9 @@ public synchronized void readSettings() {
26762708
this,
26772709
PERSIST_DELAY);
26782710
}
2679-
mIndex.put(device, getValidIndex(10 * index));
2711+
if (muteCount() == 0) {
2712+
mIndex.put(device, getValidIndex(10 * index));
2713+
}
26802714
}
26812715
}
26822716

@@ -2716,6 +2750,11 @@ public boolean adjustIndex(int deltaIndex, int device) {
27162750
public synchronized boolean setIndex(int index, int device, boolean lastAudible) {
27172751
int oldIndex = getIndex(device, false /* lastAudible */);
27182752
index = getValidIndex(index);
2753+
synchronized (mCameraSoundForced) {
2754+
if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
2755+
index = mIndexMax;
2756+
}
2757+
}
27192758
mIndex.put(device, getValidIndex(index));
27202759

27212760
if (oldIndex != index) {
@@ -2819,6 +2858,21 @@ public synchronized void setAllIndexes(VolumeStreamState srcStream, boolean last
28192858
}
28202859
}
28212860

2861+
public synchronized void setAllIndexesToMax() {
2862+
Set set = mIndex.entrySet();
2863+
Iterator i = set.iterator();
2864+
while (i.hasNext()) {
2865+
Map.Entry entry = (Map.Entry)i.next();
2866+
entry.setValue(mIndexMax);
2867+
}
2868+
set = mLastAudibleIndex.entrySet();
2869+
i = set.iterator();
2870+
while (i.hasNext()) {
2871+
Map.Entry entry = (Map.Entry)i.next();
2872+
entry.setValue(mIndexMax);
2873+
}
2874+
}
2875+
28222876
public synchronized void mute(IBinder cb, boolean state) {
28232877
VolumeDeathHandler handler = getDeathHandler(cb, state);
28242878
if (handler == null) {
@@ -2967,6 +3021,8 @@ private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
29673021
}
29683022

29693023
private void dump(PrintWriter pw) {
3024+
pw.print(" Mute count: ");
3025+
pw.println(muteCount());
29703026
pw.print(" Current: ");
29713027
Set set = mIndex.entrySet();
29723028
Iterator i = set.iterator();
@@ -3215,6 +3271,8 @@ public void handleMessage(Message msg) {
32153271
// Restore forced usage for communcations and record
32163272
AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
32173273
AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
3274+
AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
3275+
AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
32183276

32193277
// Restore stream volumes
32203278
int numStreamTypes = AudioSystem.getNumStreamTypes();
@@ -3372,6 +3430,13 @@ public void onChange(boolean selfChange) {
33723430
} else {
33733431
ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
33743432
}
3433+
synchronized (mCameraSoundForced) {
3434+
if (mCameraSoundForced) {
3435+
ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3436+
} else {
3437+
ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3438+
}
3439+
}
33753440
if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
33763441
/*
33773442
* Ensure all stream types that should be affected by ringer mode
@@ -5587,6 +5652,48 @@ private void handleConfigurationChanged(Context context) {
55875652
0,
55885653
null,
55895654
0);
5655+
5656+
boolean cameraSoundForced = mContext.getResources().getBoolean(
5657+
com.android.internal.R.bool.config_camera_sound_forced);
5658+
synchronized (mSettingsLock) {
5659+
synchronized (mCameraSoundForced) {
5660+
if (cameraSoundForced != mCameraSoundForced) {
5661+
mCameraSoundForced = cameraSoundForced;
5662+
5663+
VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
5664+
if (cameraSoundForced) {
5665+
s.setAllIndexesToMax();
5666+
mRingerModeAffectedStreams &=
5667+
~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5668+
} else {
5669+
s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM],
5670+
false /*lastAudible*/);
5671+
s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM],
5672+
true /*lastAudible*/);
5673+
mRingerModeAffectedStreams |=
5674+
(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5675+
}
5676+
// take new state into account for streams muted by ringer mode
5677+
setRingerModeInt(getRingerMode(), false);
5678+
5679+
sendMsg(mAudioHandler,
5680+
MSG_SET_FORCE_USE,
5681+
SENDMSG_QUEUE,
5682+
AudioSystem.FOR_SYSTEM,
5683+
cameraSoundForced ?
5684+
AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
5685+
null,
5686+
0);
5687+
5688+
sendMsg(mAudioHandler,
5689+
MSG_SET_ALL_VOLUMES,
5690+
SENDMSG_QUEUE,
5691+
0,
5692+
0,
5693+
mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
5694+
}
5695+
}
5696+
}
55905697
} catch (Exception e) {
55915698
Log.e(TAG, "Error retrieving device orientation: " + e);
55925699
}
@@ -5762,6 +5869,38 @@ public void disableSafeMediaVolume() {
57625869
}
57635870

57645871

5872+
//==========================================================================================
5873+
// Camera shutter sound policy.
5874+
// config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5875+
// sound is forced (sound even if the device is in silent mode) or not. This option is false by
5876+
// default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5877+
//==========================================================================================
5878+
5879+
// cached value of com.android.internal.R.bool.config_camera_sound_forced
5880+
private Boolean mCameraSoundForced;
5881+
5882+
// called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
5883+
public boolean isCameraSoundForced() {
5884+
synchronized (mCameraSoundForced) {
5885+
return mCameraSoundForced;
5886+
}
5887+
}
5888+
5889+
private static final String[] RINGER_MODE_NAMES = new String[] {
5890+
"SILENT",
5891+
"VIBRATE",
5892+
"NORMAL"
5893+
};
5894+
5895+
private void dumpRingerMode(PrintWriter pw) {
5896+
pw.println("\nRinger mode: ");
5897+
pw.println("- mode: "+RINGER_MODE_NAMES[mRingerMode]);
5898+
pw.print("- ringer mode affected streams = 0x");
5899+
pw.println(Integer.toHexString(mRingerModeAffectedStreams));
5900+
pw.print("- ringer mode muted streams = 0x");
5901+
pw.println(Integer.toHexString(mRingerModeMutedStreams));
5902+
}
5903+
57655904
@Override
57665905
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
57675906
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
@@ -5770,6 +5909,7 @@ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
57705909
dumpRCStack(pw);
57715910
dumpRCCStack(pw);
57725911
dumpStreamStates(pw);
5912+
dumpRingerMode(pw);
57735913
pw.println("\nAudio routes:");
57745914
pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
57755915
pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);

media/java/android/media/AudioSystem.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,15 +354,17 @@ public static String getDeviceName(int device)
354354
public static final int FORCE_DIGITAL_DOCK = 9;
355355
public static final int FORCE_NO_BT_A2DP = 10;
356356
public static final int FORCE_REMOTE_SUBMIX = 11;
357-
private static final int NUM_FORCE_CONFIG = 12;
357+
public static final int FORCE_SYSTEM_ENFORCED = 12;
358+
private static final int NUM_FORCE_CONFIG = 13;
358359
public static final int FORCE_DEFAULT = FORCE_NONE;
359360

360361
// usage for setForceUse, must match AudioSystem::force_use
361362
public static final int FOR_COMMUNICATION = 0;
362363
public static final int FOR_MEDIA = 1;
363364
public static final int FOR_RECORD = 2;
364365
public static final int FOR_DOCK = 3;
365-
private static final int NUM_FORCE_USE = 4;
366+
public static final int FOR_SYSTEM = 4;
367+
private static final int NUM_FORCE_USE = 5;
366368

367369
// usage for AudioRecord.startRecordingSync(), must match AudioSystem::sync_event_t
368370
public static final int SYNC_EVENT_NONE = 0;

media/java/android/media/IAudioService.aidl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,4 +153,6 @@ interface IAudioService {
153153
int setBluetoothA2dpDeviceConnectionState(in BluetoothDevice device, int state);
154154

155155
AudioRoutesInfo startWatchingRoutes(in IAudioRoutesObserver observer);
156+
157+
boolean isCameraSoundForced();
156158
}

0 commit comments

Comments
 (0)