Android11系统默认铃声闹铃声音修改以及添加其他种类铃声

前景提示:
关于系统铃声闹铃的设置使用的是frameworks/base/media/java/android/media/RingtoneManager.java
设置铃声:RingtoneManager.setActualDefaultRingtoneUri()方法

public static void setActualDefaultRingtoneUri(Context context, int type, Uri ringtoneUri) {
        String setting = getSettingForType(type);
        if (setting == null) return;

        final ContentResolver resolver = context.getContentResolver();
        if (Settings.Secure.getIntForUser(resolver, Settings.Secure.SYNC_PARENT_SOUNDS, 0,
                    context.getUserId()) == 1) {
            // Parent sound override is enabled. Disable it using the audio service.
            disableSyncFromParent(context);
        }
        if(!isInternalRingtoneUri(ringtoneUri)) {
            ringtoneUri = ContentProvider.maybeAddUserId(ringtoneUri, context.getUserId());
        }
        Settings.System.putStringForUser(resolver, setting,
                ringtoneUri != null ? ringtoneUri.toString() : null, context.getUserId());

        // Stream selected ringtone into cache so it's available for playback
        // when CE storage is still locked
        if (ringtoneUri != null) {
//*******这里有个新增声音种类bug,添加一个过滤if直接return*****
//这块代码大概是要做一个声音的存储调取缓存的操作,若是我们新增声音进行存储调取的话,会出现io错误,还是直接屏蔽了,有大手子其他理解可交流下
 //过滤返回代码           if(setting .equals(Settings.System.MODEL_TIMER) ))return;
            final Uri cacheUri = getCacheForType(type, context.getUserId());
            try (InputStream in = openRingtone(context, ringtoneUri);
                    OutputStream out = resolver.openOutputStream(cacheUri)) {
                FileUtils.copy(in, out);
            } catch (IOException e) {
                Log.w(TAG, "Failed to cache ringtone: " + e);
            }
        }
    }

获取铃声:
RingtoneManager.getActualDefaultRingtoneUri();

关于默认铃声设置修改的方法
第一种:网上搜索到的几乎都是这种默认修改参数文件路径的方式
build/make/target/product/full_base.mk 或者是其他能编译到的.mk文件

PRODUCT_PROPERTY_OVERRIDES := \
    ro.config.ringtone=Ring_Synth_04.ogg \(这个对应的是铃声默认文件,Ring_Synth_04.ogg不过当你解析出来后title是 Flutey Phone,这是因为在数据库中被修改了title值)
    ro.config.notification_sound=pixiedust.ogg

/data/sounds下.mk文件中有很多铃声资源文件供查找替换.mk的Ring_Synth_04.ogg使用/frameworks/base/data/sounds/AudioPackageGo.mk

关于系统默认资源文件修改操作:
添加资源路径/frameworks/base/packages/SettingsProvider/res/values/defaults.xml

<string name="def_desk_dock_sound" translatable="false">/product/media/audio/ui/Dock.ogg</string>
    <string name="def_desk_undock_sound" translatable="false">/product/media/audio/ui/Undock.ogg</string>
    <string name="def_car_dock_sound" translatable="false">/product/media/audio/ui/Dock.ogg</string>
    <string name="def_car_undock_sound" translatable="false">/product/media/audio/ui/Undock.ogg</string>
    <integer name="def_lockscreen_sounds_enabled">1</integer>
    <string name="def_lock_sound" translatable="false">/product/media/audio/ui/Lock.ogg</string>
    <string name="def_unlock_sound" translatable="false">/product/media/audio/ui/Unlock.ogg</string>
    <string name="def_trusted_sound" translatable="false">/product/media/audio/ui/Trusted.ogg</string>
    <string name="def_wireless_charging_started_sound" translatable="false">/product/media/audio/ui/WirelessChargingStarted.ogg</string>
    <string name="def_charging_started_sound" translatable="false">/product/media/audio/ui/ChargingStarted.ogg</string>

存储默认值/frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
例如:loadSetting(stmt, Settings.System.VIBRATE_ON, vibrate);
存储安全等级可选择system global secure
第二种 新增铃声种类,这种方式可以使用上述“关于系统默认资源文件修改操作”方式添加默认资源文件并存储。
这里说一种参考ringtone设置来电铃声闹铃的默认存储方式/frameworks/base/media/java/android/media/RingtoneManager.java
网上有一些关于电铃声闹铃的默认扫描存储代码流程,但几乎都是Android11之前的mediaScan类说明,根据其提供的代码文件查找会发现都被删除或启用,本文是依据Android11的代码进行说明
关键方法ensureDefaultRingtones()方法

@SystemApi
    @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS)
    public static void ensureDefaultRingtones(@NonNull Context context) {
        for (int type : new int[] {
                TYPE_RINGTONE,
                TYPE_NOTIFICATION,
                TYPE_ALARM,
                TYPE_OTHER,//新增铃声类型,其需要全局对象配置
        }) {
            // Skip if we've already defined it at least once, so we don't
            // overwrite the user changing to null
            final String setting = getDefaultRingtoneSetting(type);
            if (Settings.System.getInt(context.getContentResolver(), setting, 0) != 0) {
                continue;
            }

            // Try finding the scanned ringtone
            final String filename = getDefaultRingtoneFilename(type);
            final Uri baseUri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;
            try (Cursor cursor = context.getContentResolver().query(baseUri,
                    new String[] { MediaColumns._ID },
                    MediaColumns.DISPLAY_NAME + "=?",
                    new String[] { filename }, null)) {
                if (cursor.moveToFirst()) {
                    final Uri ringtoneUri = context.getContentResolver().canonicalizeOrElse(
                            ContentUris.withAppendedId(baseUri, cursor.getLong(0)));
//设置默认的铃声值,这里说个区别为什么得到的uri是content://开头的原因,而不是绝对路径/product/media/audio/alarms/Alarm_Rooster_02.ogg 
//上述有特殊说明,当新增存储时需要setActualDefaultRingtoneUri方法中进行屏蔽
                    RingtoneManager.setActualDefaultRingtoneUri(context, type, ringtoneUri);
                    Settings.System.putInt(context.getContentResolver(), setting, 1);
                }
            }
        }
    }

private static String getDefaultRingtoneSetting(int type) {
        switch (type) {
            case TYPE_RINGTONE: return "ringtone_set";
            case TYPE_NOTIFICATION: return "notification_sound_set";
            case TYPE_ALARM: return "alarm_alert_set";
            case TYPE_OTHER: return "sound_timer_set";
            default: throw new IllegalArgumentException();
        }
    }
//该方法获取上述.mk中配置的默认值,然后根据文件名称去数据库中查找对应的uri*****ro.config.ringtone=Ring_Synth_04.ogg
    private static String getDefaultRingtoneFilename(int type) {
        switch (type) {
            case TYPE_RINGTONE: return SystemProperties.get("ro.config.ringtone");
            case TYPE_NOTIFICATION: return SystemProperties.get("ro.config.notification_sound");
            case TYPE_ALARM: return SystemProperties.get("ro.config.alarm_alert");
//这里直接使用了alerm的默认铃声,若是你需要其他默认铃声,可根据自己的具体需求提供路径文件名称
            case TYPE_OTHER: return SystemProperties.get("ro.config.alarm_alert");
            default: throw new IllegalArgumentException();
        }
    }

Android Studio中设置闹钟应用,包括添加、删除闹钟以及选择闹铃铃声,可以按照以下步骤进行: ### 1. 创建项目 首先,在Android Studio中创建一个新的项目,选择“Empty Activity”模板。 ### 2. 添加权限 在`AndroidManifest.xml`文件中添加必要的权限,例如: ```xml <uses-permission android:name="android.permission.SET_ALARM"/> ``` ### 3. 设计界面 在`activity_main.xml`中添加界面元素,例如: ```xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/btnAddAlarm" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="添加闹钟" /> <ListView android:id="@+id/listViewAlarms" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> ``` ### 4. 实现添加闹钟功能 在`MainActivity.java`中实现添加闹钟的功能: ```java Button btnAddAlarm = findViewById(R.id.btnAddAlarm); ListView listViewAlarms = findViewById(R.id.listViewAlarms); btnAddAlarm.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 打开时间选择器 Calendar calendar = Calendar.getInstance(); int hour = calendar.get(Calendar.HOUR_OF_DAY); int minute = calendar.get(Calendar.MINUTE); TimePickerDialog timePickerDialog = new TimePickerDialog(MainActivity.this, new TimePickerDialog.OnTimeSetListener() { @Override public void onTimeSet(TimePicker view, int hourOfDay, int minute) { // 设置闹钟 setAlarm(hourOfDay, minute); } }, hour, minute, true); timePickerDialog.show(); } }); private void setAlarm(int hour, int minute) { // 创建闹钟管理器 AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); Intent intent = new Intent(this, AlarmReceiver.class); PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0); // 设置闹钟时间 Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, hour); calendar.set(Calendar.MINUTE, minute); calendar.set(Calendar.SECOND, 0); // 设置闹钟 alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent); } ``` ### 5. 实现闹铃接收器 创建一个新的类`AlarmReceiver.java`,实现闹铃接收器: ```java public class AlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 播放闹铃铃声 MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.alarm_sound); mediaPlayer.start(); // 显示通知 NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); String channelId = "default_channel_id"; String channelName = "Default Channel"; int importance = NotificationManager.IMPORTANCE_HIGH; NotificationChannel notificationChannel = new NotificationChannel(channelId, channelName, importance); notificationManager.createNotificationChannel(notificationChannel); Notification notification = new Notification.Builder(context, channelId) .setContentTitle("闹钟") .setContentText("闹钟响了!") .setSmallIcon(R.drawable.ic_alarm) .setAutoCancel(true) .build(); notificationManager.notify(1, notification); } } ``` ### 6. 注册接收器 在`AndroidManifest.xml`中注册`AlarmReceiver`: ```xml <receiver android:name=".AlarmReceiver"/> ``` ### 7. 删除闹钟和选择铃声 在`MainActivity.java`中实现删除闹钟和选择铃声的功能: ```java ListView listViewAlarms = findViewById(R.id.listViewAlarms); ArrayList<String> alarms = new ArrayList<>(); ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, alarms); listViewAlarms.setAdapter(adapter); listViewAlarms.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { // 删除闹钟 alarms.remove(position); adapter.notifyDataSetChanged(); return true; } }); ``` ### 8. 选择铃声 在`setAlarm`方法中,可以添加代码选择铃声: ```java private void setAlarm(int hour, int minute) { // 创建闹钟管理器 AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); Intent intent = new Intent(this, AlarmReceiver.class); PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0); // 设置闹钟时间 Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, hour); calendar.set(Calendar.MINUTE, minute); calendar.set(Calendar.SECOND, 0); // 设置闹钟 alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent); // 添加到列表 alarms.add("闹钟时间: " + hour + ":" + minute); adapter.notifyDataSetChanged(); } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值