新增预制铃声文件至 frameworks/base/data/sounds/ringtones/ogg/ 目录,注意文件格式为 .ogg
编译时拷贝文件至 out 中
frameworks/base/data/sounds/AllAudio.mk
LOCAL_PATH := frameworks/base/data/sounds
PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/newwavelabs/OrganDub.ogg:system/media/audio/ringtones/OrganDub.ogg \
$(LOCAL_PATH)/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg \
$(LOCAL_PATH)/ringtones/ogg/ring1.ogg:system/media/audio/ringtones/ring1.ogg \
$(LOCAL_PATH)/ringtones/ogg/ring2.ogg:system/media/audio/ringtones/ring2.ogg \
$(LOCAL_PATH)/ringtones/ogg/ring3.ogg:system/media/audio/ringtones/ring3.ogg \
....
设置默认铃声为 ring3, 替换原来 Ring_Synth_04.ogg
build/make/target/product/full_base.mk
# Additional settings used in all AOSP builds
PRODUCT_PROPERTY_OVERRIDES := \
- ro.config.ringtone=Ring_Synth_04.ogg \
+ ro.config.ringtone=ring3.ogg \
ro.config.notification_sound=pixiedust.ogg
最终编译后将写入到 default.prop 文件中
通过 adb 命令可以查看默认值
默认铃声
adb shell getprop ro.config.ringtone
ring1.ogg
默认通知声
adb shell getprop ro.config.notification_sound
OnTheHunt.ogg
默认闹钟声
adb shell getprop ro.config.alarm_alert
Alarm_Classic.ogg
资源文件对应URI
adb shell settings get system ringtone/notification_sound/alarm_alert
content://media/internal/audio/media/200
Q 版本编译后系统中是没有默认铃声的,也就是没有设置对应值,按照之前方法修改并未生效
搜索 ro.config.ringtone 发现有一堆地方,显然都不是这些,如果是那就会有默认铃声
./build/make/target/product/mainline.mk: ro.config.ringtone=Ring_Synth_04.ogg \
./build/make/target/product/gsi_common.mk: ro.config.ringtone=Ring_Synth_04.ogg \
./build/make/target/product/full_base.mk: ro.config.ringtone=Ring_Synth_04.ogg \
./packages/services/Car/car_product/build/car.mk: ro.config.ringtone=Girtab.ogg \
./device/generic/goldfish/sdk_phone_x86_vendor.mk: ro.config.ringtone=Ring_Synth_04.ogg \
./device/generic/armv7-a-neon/mini_common.mk: ro.config.ringtone=Ring_Synth_04.ogg \
./device/google/bonito/aosp_sargo.mk: ro.config.ringtone=Ring_Synth_04.ogg \
./device/google/bonito/aosp_bonito.mk: ro.config.ringtone=Ring_Synth_04.ogg \
修改位置
build/make/target/product/handheld_system.mk
PRODUCT_PROPERTY_OVERRIDES += \
ro.carrier=unknown \
+ ro.config.ringtone=ring3.ogg \
ro.config.notification_sound=OnTheHunt.ogg \
ro.config.alarm_alert=Alarm_Classic.ogg
预制文件位置不变, system 分区需要改为 product
frameworks/base/data/sounds/AllAudio.mk
LOCAL_PATH := frameworks/base/data/sounds
PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/newwavelabs/Noises3.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises3.ogg \
$(LOCAL_PATH)/newwavelabs/OrganDub.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/OrganDub.ogg \
$(LOCAL_PATH)/ringtones/ogg/Orion.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Orion.ogg \
+ $(LOCAL_PATH)/ringtones/ogg/ring1.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/ring1.ogg \
+ $(LOCAL_PATH)/ringtones/ogg/ring2.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/ring2.ogg \
+ $(LOCAL_PATH)/ringtones/ogg/ring3.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/ring3.ogg \
....
上面说到的通过 adb 指令可以获取对应资源值,系统播放最终对应的都是资源URI,也就对应着数据库
frameworks\base\media\java\android\media\MediaScanner.java
MediaScanner 读取 ro.config.ringtone 值后组装成 URI 写入 Settings.system 数据库
/** The filename for the default sound for the ringer ringtone. */
@UnsupportedAppUsage
private String mDefaultRingtoneFilename;
private static final String DEFAULT_RINGTONE_PROPERTY_PREFIX = "ro.config.";
private void setDefaultRingtoneFileNames() {
mDefaultRingtoneFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX
+ Settings.System.RINGTONE);
mDefaultNotificationFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX
+ Settings.System.NOTIFICATION_SOUND);
mDefaultAlarmAlertFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX
+ Settings.System.ALARM_ALERT);
}
// Setting a flag in order not to use bulk insert for the file related with
// notifications, ringtones, and alarms, because the rowId of the inserted file is
// needed.
else if (ringtones && !mDefaultRingtoneSet) {
if (TextUtils.isEmpty(mDefaultRingtoneFilename) ||
doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) {
needToSetSettings = true;
}
}
if(needToSetSettings) {
if (notifications) {
setRingtoneIfNotSet(Settings.System.NOTIFICATION_SOUND, tableUri, rowId);
mDefaultNotificationSet = true;
} else if (ringtones) {
setRingtoneIfNotSet(Settings.System.RINGTONE, tableUri, rowId);
mDefaultRingtoneSet = true;
} else if (alarms) {
setRingtoneIfNotSet(Settings.System.ALARM_ALERT, tableUri, rowId);
mDefaultAlarmSet = true;
}
}
private void setRingtoneIfNotSet(String settingName, Uri uri, long rowId) {
if (wasRingtoneAlreadySet(settingName)) {
return;
}
ContentResolver cr = mContext.getContentResolver();
String existingSettingValue = Settings.System.getString(cr, settingName);
if (TextUtils.isEmpty(existingSettingValue)) {
final Uri settingUri = Settings.System.getUriFor(settingName);
final Uri ringtoneUri = ContentUris.withAppendedId(uri, rowId);
RingtoneManager.setActualDefaultRingtoneUri(mContext,
RingtoneManager.getDefaultType(settingUri), ringtoneUri);
}
Settings.System.putInt(cr, settingSetIndicatorName(settingName), 1);
}
RingtoneManager 中从 Settings.system 读取指定类型对应的URI
frameworks\base\media\java\android\media\RingtoneManager.java
public static Uri getActualDefaultRingtoneUri(Context context, int type) {
String setting = getSettingForType(type);
if (setting == null) return null;
final String uriString = Settings.System.getStringForUser(context.getContentResolver(),
setting, context.getUserId());
Uri ringtoneUri = uriString != null ? Uri.parse(uriString) : null;
// If this doesn't verify, the user id must be kept in the uri to ensure it resolves in the
// correct user storage
if (ringtoneUri != null
&& ContentProvider.getUserIdFromUri(ringtoneUri) == context.getUserId()) {
ringtoneUri = ContentProvider.getUriWithoutUserId(ringtoneUri);
}
return ringtoneUri;
}
private static String getSettingForType(int type) {
if ((type & TYPE_RINGTONE) != 0) {
return Settings.System.RINGTONE;
} else if ((type & TYPE_NOTIFICATION) != 0) {
return Settings.System.NOTIFICATION_SOUND;
} else if ((type & TYPE_ALARM) != 0) {
return Settings.System.ALARM_ALERT;
} else {
return null;
}
}
Settings 中声音界面获取默认值对应名称显示
vendor\mediatek\proprietary\packages\apps\MtkSettings\src\com\android\settings\notification\RingtonePreferenceControllerBase.java
private void updateSummary(Preference preference) {
final Uri ringtoneUri = RingtoneManager.getActualDefaultRingtoneUri(
mContext, getRingtoneType());
final CharSequence summary = getSummary(ringtoneUri);
if (summary != null) {
ThreadUtils.postOnMainThread(() -> preference.setSummary(summary));
}
}
private CharSequence getSummary(Uri ringtoneUri) {
CharSequence summary = null;
try {
summary = Ringtone.getTitle(
mContext, ringtoneUri, false /* followSettingsUri */, true /* allowRemote */);
return summary;
}catch (Exception e){
e.printStackTrace();
return null;
}
}
Ringtone 中 getTitle 解析获取对应文本名称
frameworks\base\media\java\android\media\Ringtone.java
public static String getTitle(
Context context, Uri uri, boolean followSettingsUri, boolean allowRemote) {
ContentResolver res = context.getContentResolver();
String title = null;
if (uri != null) {
String authority = ContentProvider.getAuthorityWithoutUserId(uri.getAuthority());
if (Settings.AUTHORITY.equals(authority)) {
if (followSettingsUri) {
Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(context,
RingtoneManager.getDefaultType(uri));
String actualTitle = getTitle(
context, actualUri, false /*followSettingsUri*/, allowRemote);
title = context
.getString(com.android.internal.R.string.ringtone_default_with_actual,
actualTitle);
}
} else {
Cursor cursor = null;
try {
if (MediaStore.AUTHORITY.equals(authority)) {
final String mediaSelection = allowRemote ? null : MEDIA_SELECTION;
cursor = res.query(uri, MEDIA_COLUMNS, mediaSelection, null, null);
if (cursor != null && cursor.getCount() == 1) {
cursor.moveToFirst();
return cursor.getString(1);
}
// missing cursor is handled below
}
} catch (SecurityException e) {
IRingtonePlayer mRemotePlayer = null;
if (allowRemote) {
AudioManager audioManager =
(AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mRemotePlayer = audioManager.getRingtonePlayer();
}
if (mRemotePlayer != null) {
try {
title = mRemotePlayer.getTitle(uri);
} catch (RemoteException re) {
}
}
} finally {
if (cursor != null) {
cursor.close();
}
cursor = null;
}
if (title == null) {
title = uri.getLastPathSegment();
}
}
} else {
title = context.getString(com.android.internal.R.string.ringtone_silent);
}
if (title == null) {
title = context.getString(com.android.internal.R.string.ringtone_unknown);
if (title == null) {
title = "";
}
}
return title;
}