Android 设置音量默认值

在车机 Audio 开发中,设置音量默认值是必要的,很多时候也需要定制化开发。还有很多场景需要设置音量的最大值和最小值问题,例如通话模式通常是禁止静音的,耳机模式调整到较大音量时开机后会恢复一个最大默认值等问题。而且通常情况下不通车型的默认值可能会不同,这篇文章就来看一下如何在一套代码中维护不同车型的默认音量。

一、系统默认音量

1、默认音量

源码位置:frameworks/base/media/java/android/media/AudioSystem.java

java 复制代码
public static int[] DEFAULT_STREAM_VOLUME = new int[] {
    4,  // STREAM_VOICE_CALL
    7,  // STREAM_SYSTEM
    5,  // STREAM_RING
    5, // STREAM_MUSIC
    6,  // STREAM_ALARM
    5,  // STREAM_NOTIFICATION
    7,  // STREAM_BLUETOOTH_SCO
    7,  // STREAM_SYSTEM_ENFORCED
    5, // STREAM_DTMF
    5, // STREAM_TTS
    5, // STREAM_ACCESSIBILITY
    5, // STREAM_ASSISTANT
};

2、 最大/小音量

源码位置**:**frameworks/base/services/core/java/com/android/server/audio/AudioService.java

java 复制代码
/** 音频流的最大音量索引值 */
protected static int[] MAX_STREAM_VOLUME = new int[] {
    5,  // STREAM_VOICE_CALL
    7,  // STREAM_SYSTEM
    7,  // STREAM_RING
    15, // STREAM_MUSIC
    7,  // STREAM_ALARM
    7,  // STREAM_NOTIFICATION
    15, // STREAM_BLUETOOTH_SCO
    7,  // STREAM_SYSTEM_ENFORCED
    15, // STREAM_DTMF
    15, // STREAM_TTS
    15, // STREAM_ACCESSIBILITY
    15  // STREAM_ASSISTANT
};

/** 音频流的最小音量索引值 */
protected static int[] MIN_STREAM_VOLUME = new int[] {
    1,  // STREAM_VOICE_CALL
    0,  // STREAM_SYSTEM
    0,  // STREAM_RING
    0,  // STREAM_MUSIC
    1,  // STREAM_ALARM
    0,  // STREAM_NOTIFICATION
    0,  // STREAM_BLUETOOTH_SCO
    0,  // STREAM_SYSTEM_ENFORCED
    0,  // STREAM_DTMF
    0,  // STREAM_TTS
    1,  // STREAM_ACCESSIBILITY
    0   // STREAM_ASSISTANT
};

3、默认值修改

虽然我们找到了默认值的定义位置,但是声音属性默认值最好不要在这里进行修改,否则可能修改无效。因为这两种音量属性被定义之后,还会在 AudioService 的构造方法中进行初始化。在此期间,之前定义的音量值会被覆盖掉。

java 复制代码
public AudioService(Context context, AudioSystemAdapter audioSystem, SystemServerAdapter systemServer) {
    ......
    int maxCallVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps", -1);
    if (maxCallVolume != -1) {
        MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxCallVolume;
    }

    int defaultCallVolume = SystemProperties.getInt("ro.config.vc_call_vol_default", -1);
    if (defaultCallVolume != -1 &&
                defaultCallVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] &&
                defaultCallVolume >= MIN_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
        AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = defaultCallVolume;
    } else {
        AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] =
                    (MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] * 3) / 4;
    }

    int maxMusicVolume = SystemProperties.getInt("ro.config.media_vol_steps", -1);
    if (maxMusicVolume != -1) {
        MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxMusicVolume;
    }

    int defaultMusicVolume = SystemProperties.getInt("ro.config.media_vol_default", -1);
    if (defaultMusicVolume != -1 &&
                defaultMusicVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] &&
                defaultMusicVolume >= MIN_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
        AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = defaultMusicVolume;
    } else {
        if (isPlatformTelevision()) {
            AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] / 4;
        } else {
            AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] / 3;
        }
    }

    int maxAlarmVolume = SystemProperties.getInt("ro.config.alarm_vol_steps", -1);
    if (maxAlarmVolume != -1) {
        MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM] = maxAlarmVolume;
    }

    int defaultAlarmVolume = SystemProperties.getInt("ro.config.alarm_vol_default", -1);
    if (defaultAlarmVolume != -1 &&
                defaultAlarmVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM]) {
        AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_ALARM] = defaultAlarmVolume;
    } else {
        // 默认值是7分中的6分(默认最大值),因此相应地缩放。
        AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_ALARM] =
                        6 * MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM] / 7;
    }
    
    int maxSystemVolume = SystemProperties.getInt("ro.config.system_vol_steps", -1);
    if (maxSystemVolume != -1) {
        MAX_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM] = maxSystemVolume;
    }

    int defaultSystemVolume = SystemProperties.getInt("ro.config.system_vol_default", -1);
    if (defaultSystemVolume != -1 && defaultSystemVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM]) {
        AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM] = defaultSystemVolume;
    } else {
        // 默认是使用maximum。
        AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM] = MAX_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM];
    }
    ......
}

以多媒体默认音量为例,我们可以看到,它最终的设置结果是最大音量的三分之一,即 15/3=5 格音量。

java 复制代码
int defaultMusicVolume = SystemProperties.getInt("ro.config.media_vol_default", -1);
if (defaultMusicVolume != -1 &&
                defaultMusicVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] &&
                defaultMusicVolume >= MIN_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
    AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = defaultMusicVolume;
} else {
    if (isPlatformTelevision()) {
        AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] / 4;
    } else {
        AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] / 3;
    }
}

所以,它的修改方式应该是这样的:

java 复制代码
//多媒体默认音量修改为10格
int defaultMusicVolume = SystemProperties.getInt("ro.config.media_vol_default", 10);

其实这里是系统一用来记录用户设置音量的,首先取出用户设置的音量,如果取出的值在最大值和最小值之间,直接使用该音量。否则设置最大音量的三分之一为默认音量。

一、自定义音量值

对于车机开发来说,为了方便维护我们也可以定义一套自定义音量值的 xml 文件。

1、配置默认值

通常情况下,需要在上面的文件中添加相关默认值属性。

config.xml

源码位置:/packages/services/Car/service/res/values/config.xml

XML 复制代码
<integer name="mediaMaxVolume">20</integer>
<integer name="mediaMinVolume">5</integer>
<integer name="alarmMaxVolume">20</integer>
<integer name="alarmMinVolume">5</integer>

这里设置了多媒体的最大音量为 20,最小音量为 10。设置了闹钟的最小音量为 5。

2、初始化数据

CarAudioService

源码位置:/packages/services/Car/service/src/com/android/car/CarAudioService.java

java 复制代码
public class CarAudioService extends ICarAudio.Stub implements CarServiceBase, PowerEventProcessingHandler {
    ......
    private static final String MEDIA_MIN_VOLUME  = "vendor.media.min.volume";
    private static final String MEDIA_MAX_VOLUME  = "vendor.media.max.volume";
    private static final String ALARM_MIN_VOLUME  = "vendor.alarm.min.volume";
    private static final String ALARM_MAX_VOLUME  = "vendor.alarm.max.volume";
	
    private int mMediaMinVolume;
    private int mMediaMaxVolume;
    private int mAlarmMinVolume;
    private int mAlarmMaxVolume;

    @Override
    public void init() {
        ......
        synchronized (mImplLock) {
            ......
            Resources res = mContext.getResources();
            mMediaMinVolume = res.getInteger(R.integer.mediaMinVolume);
            mMediaMaxVolume = res.getInteger(R.integer.mediaMaxVolume);
            mAlarmMinVolume = res.getInteger(R.integer.alarmMinVolume);
            mAlarmMaxVolume = res.getInteger(R.integer.alarmMaxVolume);
            SystemProperties.set(MEDIA_MIN_VOLUME, String.valueOf(mMediaMinVolume));
            SystemProperties.set(MEDIA_MAX_VOLUME, String.valueOf(mMediaMaxVolume));
            SystemProperties.set(ALARM_MIN_VOLUME, String.valueOf(mAlarmMinVolume));
            SystemProperties.set(ALARM_MAX_VOLUME, String.valueOf(mAlarmMaxVolume));
            ......
        }
        ......
    }
    ......
}

这里就是取出 xml 中的数据,存储到系统变量中,我们这里看一下存储方式。

SystemProperties

源码位置:/frameworks/base/core/java/android/os/SystemProperties.java

java 复制代码
/**
 * 提供对系统属性存储的访问权限。系统属性存储包含字符串键值对列表。
 * 该类仅用于本地的系统属性。
 */
public class SystemProperties {
    private static final boolean TRACK_KEY_ACCESS = false;

    public static String get(@NonNull String key) {
        if (TRACK_KEY_ACCESS) onKeyAccess(key);
        return native_get(key);
    }

    public static String get(@NonNull String key, @Nullable String def) {
        if (TRACK_KEY_ACCESS) onKeyAccess(key);
        return native_get(key, def);
    }
}

可以看到这就相当于一个用于存储系统属性的工具类。

3、获取数据

在上面的 AudioService 中可以使用这里存储的数据进行赋值,这样就使用了自定义数据。

java 复制代码
private static final String MEDIA_MIN_VOLUME  = "vendor.media.min.volume";
private static final String MEDIA_MAX_VOLUME  = "vendor.media.max.volume";
private static final String ALARM_MIN_VOLUME  = "vendor.alarm.min.volume";
private static final String ALARM_MAX_VOLUME  = "vendor.alarm.max.volume";
	
private int mMediaMinVolume;
private int mMediaMaxVolume;
private int mAlarmMinVolume;
private int mAlarmMaxVolume;

mMediaMinVolume = SystemProperties.get(MEDIA_MIN_VOLUME);
mMediaMaxVolume = SystemProperties.get(MEDIA_MAX_VOLUME);
mAlarmMinVolume = SystemProperties.get(ALARM_MIN_VOLUME);
mAlarmMaxVolume = SystemProperties.get(ALARM_MAX_VOLUME);

4、定制设置

如果只有一组设置,直接使用上面的代码就可以了。但是如果当前有多个车型,且对音量的边界值设置还不一样,这就需要定制化设置了。例如我们有 xx01 和 xx02 两个车型,他们的定制化文件存放在 /device/xiaoxu/xx01 和 /device/xiaoxu/xx02 下。这里配置默认值需要覆盖上面的配置信息,所以需要添加 overlay 路径。

xx01

源码位置:/device/xiaoxu/xx01/overlay/packages/services/Car/service/res/values/config.xml

XML 复制代码
<integer name="mediaMaxVolume">18</integer>
<integer name="mediaMinVolume">3</integer>
<integer name="alarmMaxVolume">18</integer>
<integer name="alarmMinVolume">3</integer>

xx02

源码位置:/device/xiaoxu/xx02/overlay/packages/services/Car/service/res/values/config.xml

XML 复制代码
<integer name="mediaMaxVolume">22</integer>
<integer name="mediaMinVolume">7</integer>
<integer name="alarmMaxVolume">22</integer>
<integer name="alarmMinVolume">7</integer>

这样该文件就会覆盖上面的设置,而对于数值的初始化和获取方式与上面的相同,这里就不再重复添加。

相关推荐
风往哪边走13 分钟前
创建自定义语音录制View
android·前端
用户20187928316713 分钟前
事件分发之“官僚主义”?或“绕圈”的艺术
android
用户20187928316713 分钟前
Android事件分发为何喜欢“兜圈子”?不做个“敞亮人”!
android
Kapaseker2 小时前
你一定会喜欢的 Compose 形变动画
android
QuZhengRong3 小时前
【数据库】Navicat 导入 Excel 数据乱码问题的解决方法
android·数据库·excel
zhangphil4 小时前
Android Coil3视频封面抽取封面帧存Disk缓存,Kotlin(2)
android·kotlin
程序员码歌10 小时前
【零代码AI编程实战】AI灯塔导航-总结篇
android·前端·后端
书弋江山11 小时前
flutter 跨平台编码库 protobuf 工具使用
android·flutter
来来走走14 小时前
Flutter开发 webview_flutter的基本使用
android·flutter
Jerry说前后端15 小时前
Android 组件封装实践:从解耦到架构演进
android·前端·架构