有客户反馈:A14触摸声音没有
于是乎,追踪setting打开触摸声音的代码:
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
if (preference == mVibrateWhenRinging) {
Settings.System.putInt(getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING,
mVibrateWhenRinging.isChecked() ? 1 : 0);
} else if (preference == mDtmfTone) {
Settings.System.putInt(getContentResolver(), Settings.System.DTMF_TONE_WHEN_DIALING,
mDtmfTone.isChecked() ? 1 : 0);
} else if (preference == mSoundEffects) {
if (mSoundEffects.isChecked()) {
mAudioManager.loadSoundEffects();
} else {
mAudioManager.unloadSoundEffects();
}
Settings.System.putInt(getContentResolver(), Settings.System.SOUND_EFFECTS_ENABLED,
mSoundEffects.isChecked() ? 1 : 0);
}
可以看出来是用:Settings.System.SOUND_EFFECTS_ENABLED这个setting值来控制的。
利用adb看这个值:
确实是开启了的,于是怀疑跑的过程中哪里中断了(可能谷歌加了些判断逻辑),于是继续追:
在View.java里面的触摸声音代码:
/**
* Set whether this view should have sound effects enabled for events such as
* clicking and touching.
*
* <p>You may wish to disable sound effects for a view if you already play sounds,
* for instance, a dial key that plays dtmf tones.
*
* @param soundEffectsEnabled whether sound effects are enabled for this view.
* @see #isSoundEffectsEnabled()
* @see #playSoundEffect(int)
* @attr ref android.R.styleable#View_soundEffectsEnabled
*/
public void setSoundEffectsEnabled(boolean soundEffectsEnabled) {
setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED);
}
/**
* @return whether this view should have sound effects enabled for events such as
* clicking and touching.
*
* @see #setSoundEffectsEnabled(boolean)
* @see #playSoundEffect(int)
* @attr ref android.R.styleable#View_soundEffectsEnabled
*/
@ViewDebug.ExportedProperty
public boolean isSoundEffectsEnabled() {
return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED);
}
看到这2个方法我就有底了。很明显,我们要查看isSoundEffectsEnabled的调用关系。
/**
* Play a sound effect for this view.
*
* <p>The framework will play sound effects for some built in actions, such as
* clicking, but you may wish to play these effects in your widget,
* for instance, for internal navigation.
*
* <p>The sound effect will only be played if sound effects are enabled by the user, and
* {@link #isSoundEffectsEnabled()} is true.
*
* @param soundConstant One of the constants defined in {@link SoundEffectConstants}
*/
public void playSoundEffect(int soundConstant) {
if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) {
return;
}
mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant);
}
接着我们看谁调用了它,找到在AudioServeice.java中
/** @see AudioManager#playSoundEffect(int) */
public void playSoundEffect(int effectType) {
playSoundEffectVolume(effectType, -1.0f);
}
/** @see AudioManager#playSoundEffect(int, float) */
public void playSoundEffectVolume(int effectType, float volume) {
sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
effectType, (int) (volume * 1000), null, 0);
}
发送MSG_PLAY_SOUND_EFFECT消息,发送的消息在AudioHandler的handleMessage中处理:
public class AudioService extends IAudioService.Stub
implements AccessibilityManager.TouchExplorationStateChangeListener,
AccessibilityManager.AccessibilityServicesStateChangeListener,
AudioSystemAdapter.OnRoutingUpdatedListener,
AudioSystemAdapter.OnVolRangeInitRequestListener {
private SoundEffectsHelper mSfxHelper;
/** Handles internal volume messages in separate volume thread. */
private class AudioHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_PLAY_SOUND_EFFECT:
mSfxHelper.playSoundEffect(msg.arg1, msg.arg2);
break;
}
}
}
调用SoundEffectsHelper的playSoundEffect方法
//frameworks/base/service/java/com/android/server/audio/SoundEffectsHelper.java
class SoundEffectsHelper {
/*package*/ void playSoundEffect(int effect, int volume) {
sendMsg(MSG_PLAY_EFFECT, effect, volume, null, 0);
}
}
发送MSG_PLAY_EFFECT消息:
//frameworks/base/service/java/com/android/server/audio/SoundEffectsHelper.java
class SoundEffectsHelper {
private class SfxHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_PLAY_EFFECT:
final int effect = msg.arg1, volume = msg.arg2;
onLoadSoundEffects(new OnEffectsLoadCompleteHandler() {
@Override
public void run(boolean success) {
if (success) {
onPlaySoundEffect(effect, volume);
}
}
});
break;
}
}
}
}
调用onLoadSoundEffects方法:
//frameworks/base/service/java/com/android/server/audio/SoundEffectsHelper.java
class SoundEffectsHelper {
private SoundPool mSoundPool;
private void onLoadSoundEffects(OnEffectsLoadCompleteHandler onComplete) {
if (mSoundPoolLoader != null) {
// Loading is ongoing.
mSoundPoolLoader.addHandler(onComplete);
return;
}
if (mSoundPool != null) {
if (onComplete != null) {
onComplete.run(true /*success*/);
}
return;
}
logEvent("effects loading started");
mSoundPool = new SoundPool.Builder()
.setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build())
.build(); //创建SoundPool对象
loadSoundAssets(); //加载声音资料
mSoundPoolLoader = new SoundPoolLoader(); //创建SoundPoolLoader对象
mSoundPoolLoader.addHandler(new OnEffectsLoadCompleteHandler() { //增加OnEffectsLoadComplete Handler
@Override
public void run(boolean success) {
mSoundPoolLoader = null;
if (!success) {
Log.w(TAG, "onLoadSoundEffects(), Error while loading samples");
onUnloadSoundEffects();
}
}
});
mSoundPoolLoader.addHandler(onComplete); //增加onComplete Handler
int resourcesToLoad = 0;
for (Resource res : mResources) {
String filePath = getResourceFilePath(res);
int sampleId = mSoundPool.load(filePath, 0);
if (sampleId > 0) {
res.mSampleId = sampleId;
res.mLoaded = false;
resourcesToLoad++;
} else {
logEvent("effect " + filePath + " rejected by SoundPool");
Log.w(TAG, "SoundPool could not load file: " + filePath);
}
}
if (resourcesToLoad > 0) {
sendMsg(MSG_LOAD_EFFECTS_TIMEOUT, 0, 0, null, SOUND_EFFECTS_LOAD_TIMEOUT_MS);
} else {
logEvent("effects loading completed, no effects to load");
mSoundPoolLoader.onComplete(true /*success*/);
}
}
}
直到追到这里我才惊觉,好像每个流程都正常!!!
于是我放在耳朵边上听,微弱的触摸音传出的时候,我心态崩了
但是问题还要继续,客户是上帝,所以要解决的是触摸声音小的问题
追踪SoundEffectsHelper.java的代码时发现:
SoundEffectsHelper(Context context, Consumer<PlayerBase> playerAvailableCb) {
mContext = context;
mSfxAttenuationDb = mContext.getResources().getInteger(
com.android.internal.R.integer.config_soundEffectVolumeDb);
mPlayerAvailableCb = playerAvailableCb;
startWorker();
}
触摸声音是由config_soundEffectVolumeDb这个值控制的:范围是-6到0,代码如下:
void onPlaySoundEffect(int effect, int volume) {
float volFloat;
// use default if volume is not specified by caller
if (volume < 0) {
volFloat = (float) Math.pow(10, (float) mSfxAttenuationDb / 20);
} else {
volFloat = volume / 1000.0f;
}
//android.util.Log.d("hqb","volFloat==="+volFloat);
Resource res = mResources.get(mEffects[effect]);
if (mSoundPool != null && res.mSampleId != EFFECT_NOT_IN_SOUND_POOL && res.mLoaded) {
mSoundPool.play(res.mSampleId, volFloat, volFloat, 0, 0, 1.0f);
} else {
MediaPlayer mediaPlayer = new MediaPlayer();
可以看出最大值应该是1.0f
但是即使调整到最大,其声音也是很细微
看网友有以下修改来增大音量:
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index f00a910..3ee0c85 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1757,7 +1757,7 @@
public static int[] DEFAULT_STREAM_VOLUME = new int[] {
4, // STREAM_VOICE_CALL
7, // STREAM_SYSTEM
- 5, // STREAM_RING
+ 7, // STREAM_RING
15, // STREAM_MUSIC
6, // STREAM_ALARM
7, // STREAM_NOTIFICATION
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 253b4e3..5733d8e 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -49,7 +49,7 @@
*rightVolume != std::clamp(*rightVolume, 0.f, 1.f)) {
ALOGI("volume l=%f r=%f out of (0.f, 1.f) bounds, using 1.f", *leftVolume, *rightVolume);
// for backward compatibility use 1.f.
- *leftVolume = *rightVolume = 1.f;
+ //*leftVolume = *rightVolume = 1.f;
}
return false;
}
diff --git a/services/core/java/com/android/server/audio/SoundEffectsHelper.java b/services/core/java/com/android/server/audio/SoundEffectsHelper.java
index 762f4d7..afd62c6 100644
--- a/services/core/java/com/android/server/audio/SoundEffectsHelper.java
+++ b/services/core/java/com/android/server/audio/SoundEffectsHelper.java
@@ -248,7 +248,8 @@
Resource res = mResources.get(mEffects[effect]);
if (mSoundPool != null && res.mSampleId != EFFECT_NOT_IN_SOUND_POOL && res.mLoaded) {
- mSoundPool.play(res.mSampleId, volFloat, volFloat, 0, 0, 1.0f);
+ // mSoundPool.play(res.mSampleId, volFloat, volFloat, 0, 0, 1.0f);
+ mSoundPool.play(res.mSampleId, volFloat*30, volFloat*30, 0, 0, 1.0f);
} else {
MediaPlayer mediaPlayer = new MediaPlayer();
try {
实测可行
但到这里因为设备是不带电话功能的 所以ring的音量条被移除了 然而触摸声音默认就是跟着这个走的,所以我们还需要对其修改:
--- a/alps-mp-u0/frameworks/base/services/core/java/com/android/server/audio/SoundEffectsHelper.java
+++ b/alps-mp-u0/frameworks/base/services/core/java/com/android/server/audio/SoundEffectsHelper.java
@@ -190,8 +190,8 @@ class SoundEffectsHelper {
mSoundPool = new SoundPool.Builder()
.setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
.setAudioAttributes(new AudioAttributes.Builder()
- .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
- .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .setUsage(AudioAttributes.USAGE_MEDIA)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build())
.build();
mPlayerAvailableCb.accept(mSoundPool);
@@ -265,7 +265,7 @@ class SoundEffectsHelper {
修改为AudioSystem.STREAM_MUSIC即可
至此 修改完成!