admin管理员组

文章数量:1123198

From various SO posts I've put together code to change the ringtone depending on some app settings. A BroadcastReceiver subclass makes sure notifications are received and gets to pick up the incoming phone number:

public class IncomingCallFilter extends BroadcastReceiver {

    @Override
    public void onReceive(final Context context, Intent intent) {
        if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(intent.getAction())) {
            Log.d("onReceive@" + hashCode(), "Phone state changed");
            Optional.ofNullable(intent.getExtras())
                    .map(extras -> extras.getString(TelephonyManager.EXTRA_INCOMING_NUMBER))
                    .filter(s -> !s.isEmpty())
                    .ifPresent(number -> {
                        final RingtoneTelephonyCallback telephonyCallback = new RingtoneTelephonyCallback(context, number);
                        final TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
                        Log.d("onReceive", "Registering new TelephonyCallback");
                        telephony.registerTelephonyCallback(context.getMainExecutor(), telephonyCallback);
                        // note that RingtoneTelephonyCallback unregisters itself on TelephonyManager.CALL_STATE_IDLE
                    });
        }
    }
}

The RingtoneTelephonyCallback then handles the actual switch of the ringtone:

        final String ringtonePreference = sharedPreferences.getString(Constants.KEY_RINGTONE_PREFERENCE, Settings.System.DEFAULT_NOTIFICATION_URI.toString());
        final Uri ringtoneUri = Constants.SILENT_VALUE.equals(ringtonePreference) ? null : Uri.parse(ringtonePreference);
        defaultRingTone = RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE);
        if (!Objects.equals(ringtoneUri, defaultRingTone) && Settings.System.canWrite(context)) {
            Log.d("dynamicRingtone@" + hashCode(), "Switching ringtone for number " + incomingNumber + " to " + ringtoneUri);
            RingtoneManager.setActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE, ringtoneUri);
            needsRingtoneRevert = true;
        }

Running this in Android Studio on an emulated phone works, the logcat output shows

2025-01-10 15:47:31.839 12950-12950 onReceive@70713570      ch.want.dynamicringtone              D  Phone state changed
2025-01-10 15:47:31.844 12950-12950 onReceive@243035251     ch.want.dynamicringtone              D  Phone state changed
2025-01-10 15:47:31.845 12950-12950 RingtoneTe...@133654320 ch.want.dynamicringtone              D  Created
2025-01-10 15:47:31.846 12950-12950 onReceive               ch.want.dynamicringtone              D  Registering new TelephonyCallback
2025-01-10 15:47:31.864 12950-12950 RingtoneTe...@133654320 ch.want.dynamicringtone              D  Got new call state 1
2025-01-10 15:47:31.885 12950-12950 dynamicRin...@133654320 ch.want.dynamicringtone              D  Switching ringtone for number 6505551212 to content://media/external_primary/audio/media/1000000065?title=Gentle%20Gong&canonical=1
...
2025-01-10 15:47:36.960 12950-12950 RingtoneTe...@133654320 ch.want.dynamicringtone              D  Got new call state 0
2025-01-10 15:47:36.963 12950-12950 dynamicRin...@133654320 ch.want.dynamicringtone              D  Switching ringtone back to content://media/external_primary/audio/media/1000000072?title=Your%20New%20Adventure&canonical=1

and the desired "Gentle Gong" ringtone plays. Doing the same on a physical device results in pretty much the same logcat

2025-01-10 15:55:40.426 28222-28222 onReceive@102975571     ch.want.dynamicringtone              D  Phone state changed
2025-01-10 15:55:40.448 28222-28222 onReceive@4277648       ch.want.dynamicringtone              D  Phone state changed
2025-01-10 15:55:40.452 28222-28222 RingtoneTe...@207400585 ch.want.dynamicringtone              D  Created
2025-01-10 15:55:40.452 28222-28222 onReceive               ch.want.dynamicringtone              D  Registering new TelephonyCallback
2025-01-10 15:55:40.480 28222-28222 ActivityThread          ch.want.dynamicringtone              I  Performing receive of Intent { act=android.intent.action.PHONE_STATE flg=0x1000010 cmp=ch.want.dynamicringtone/.IncomingCallFilter (has extras) }: app=android.app.Application@b9016af, appName=ch.want.dynamicringtone, pkg=ch.want.dynamicringtone, comp={ch.want.dynamicringtone/ch.want.dynamicringtone.IncomingCallFilter}, dir=/data/app/~~MLS6TUSSv0EmvwgrNDKu0A==/ch.want.dynamicringtone-q3qpKiYRDyW7_aMt5CtnFg==/base.apk, duration=31
2025-01-10 15:55:40.480 28222-28222 RingtoneTe...@207400585 ch.want.dynamicringtone              D  Got new call state 1
2025-01-10 15:55:40.514 28222-28222 RingtoneManager         ch.want.dynamicringtone              D  getActualDefaultRingtoneUri+uriString=content://0@media/external/audio/media/1000034473?title=Black%20Woodpecker%20(Dryocopus%20martius)&canonical=1,type=1
2025-01-10 15:55:40.515 28222-28222 dynamicRin...@207400585 ch.want.dynamicringtone              D  Switching ringtone for number 01416287667 to content://media/external/audio/media/85?title=Calm&canonical=1
2025-01-10 15:55:40.536 28222-28222 RingtoneManager         ch.want.dynamicringtone              D  setActualDefaultRingtoneUri,ringtoneUri=content://media/external/audio/media/85?title=Calm&canonical=1,type=1, forceIgnoreSyncParent: false
2025-01-10 15:55:40.573 28222-28222 RingtoneManager         ch.want.dynamicringtone              D  [saveRingtoneCacheTitle]: Calm, setting: ringtone, type: 1
2025-01-10 15:55:40.573 28222-28222 RingtoneManager         ch.want.dynamicringtone              D  [loadRingtoneCacheTitle] Uri: content://0@settings/system/ringtones_title_cache
2025-01-10 15:55:40.577 28222-28222 RingtoneManager         ch.want.dynamicringtone              D  [loadRingtoneCacheTitle] data[0]: ringtone ,data[1]: Black Woodpecker (Dryocopus martius)
2025-01-10 15:55:40.577 28222-28222 RingtoneManager         ch.want.dynamicringtone              D  [loadRingtoneCacheTitle] data[0]: notification_sound ,data[1]: NewMailVip
2025-01-10 15:55:40.577 28222-28222 RingtoneManager         ch.want.dynamicringtone              D  [loadRingtoneCacheTitle] data[0]: alarm_alert ,data[1]: BusyBugs
2025-01-10 15:55:40.577 28222-28222 RingtoneManager         ch.want.dynamicringtone              D  [loadRingtoneCacheTitle] data[0]: ringtone_2 ,data[1]: Black Woodpecker (Dryocopus martius)
2025-01-10 15:55:40.933  1237-1339  ANDR-PERF-OPTSHANDLER   [email protected]  E  thermal_pol, detect_fps = 7, avg_fps=3, topApp=ch.want.dynamicringtone
...
2025-01-10 15:55:48.933 28222-28222 RingtoneTe...@207400585 ch.want.dynamicringtone              D  Got new call state 0
2025-01-10 15:55:48.934 28222-28222 dynamicRin...@207400585 ch.want.dynamicringtone              D  Switching ringtone back to content://media/external/audio/media/1000034473?title=Black%20Woodpecker%20(Dryocopus%20martius)&canonical=1

However the phone keeps ringing with the system default "Black Woodpecker" instead of the desired "Calm".

The logcat output tells me that the code is running as expected, RingtoneManager.setActualDefaultRingtoneUri() is called with the changed ringtone. I assume at the time this happens on the physical device, Android just won't pick up that change anymore. I've looked through and can't find any way to "force" a ringtone update. Is this simply not possible?

本文标签: javaChange ringtone while already ringing in Android appStack Overflow