Incoming call dynamically override default ringtone
Asked Answered
B

2

13

My app allows you to specify a different ringtone for different incoming events. EG: incoming call, incoming SMS, etc.

What I am trying to accomplish is when I receive for example an incoming call, I check my apps database if a specific option is selected and if there is a ringtone option set play that ringtone.

However the problem I am having is I am unable to override / stop the default phone ringtone from playing.

I have tried several different ways, but from the docs most of those methods only stop the current instance and are not global methods.

I can't set the ringtone in the default phones ringtone settings as it needs to be dynamic based on the incoming call.

If anyone knows of a trick or a way to accomplish this that would be great. I hope that makes sense.

Bille answered 2/8, 2010 at 12:9 Comment(0)
J
12

There are a several steps to dynamically change the ringtone.

1. Prepare ringtone

    File k = new File("/sdcard/ringtone", "kolyan_.mp3");
    ContentValues values = new ContentValues();
    values.put(MediaStore.MediaColumns.DATA, k.getAbsolutePath());
    values.put(MediaStore.MediaColumns.TITLE, "My Song title");
    values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/mpeg");
    values.put(MediaStore.Audio.Media.ARTIST, "Some Artist");
    values.put(MediaStore.Audio.Media.IS_RINGTONE, true);
    values.put(MediaStore.Audio.Media.IS_NOTIFICATION, false);
    values.put(MediaStore.Audio.Media.IS_ALARM, false);
    values.put(MediaStore.Audio.Media.IS_MUSIC, false);

2. Insert it into the database

    Uri uri = MediaStore.Audio.Media.getContentUriForPath(k.getAbsolutePath());
    // Line below is major because we need to delete old entry
    getContentResolver().delete(uri, MediaStore.MediaColumns.DATA + "=\"" + k.getAbsolutePath() + "\"", null);
    mUri = getContentResolver().insert(uri, values);

3. Save the current default ringtone and subscribe to CallListener

    // Be careful by calling getActualDefaultRingtoneUri in CallListener, it could return null, better way to save it in OnCreate
    mOldUri = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_RINGTONE);

    TelephonyManager mTelephonyMgr = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
    mTelephonyMgr.listen(new MyCallListener(), PhoneStateListener.LISTEN_CALL_STATE);

4. Create MyCallListener class

class MyCallListener extends PhoneStateListener {
    @Override
    public void onCallStateChanged(int state, String incomingNumber) {
        switch (state) {
            case TelephonyManager.CALL_STATE_RINGING:
                // On call you replace the ringtone with your own mUri
                RingtoneManager.setActualDefaultRingtoneUri(
                        MainActivity.this,
                        RingtoneManager.TYPE_RINGTONE,
                        mUri
                );
                break;
            case TelephonyManager.CALL_STATE_IDLE:
                // Restore the default ringtone
                RingtoneManager.setActualDefaultRingtoneUri(
                        MainActivity.this,
                        RingtoneManager.TYPE_RINGTONE,
                        mOldUri
                );
                break;
            default:
                break;
        }

        super.onCallStateChanged(state, incomingNumber);
    }
}

5. Add permissions to you AndroidManifest.xml

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>

6. Done

The main idea is hooking for incoming call and replace the ringtone by your own. And of course you should restore default ringtone to saved value after call.

Jill answered 10/3, 2012 at 4:34 Comment(4)
Somehow for me, even tough the ringtone is effectively replaced it still play the old one... any clue?Airboat
Not enough information to figure out. Try look at logs. Try to check return value of getActualDefaultRingtoneUri after you set it.Jill
I did (getActualDefaultRingtoneUri) and the value is correct and it will be the default if I don't revert it back at CALL_STATE_IDLE. It seems as if the system acquire the Ringtone Uri to play before I change it.Airboat
I'm still asked to include WRITE_EXTERNAL_STORAGE permissionMatney
D
4

Starting with API 5 (Android 2.x), the Contacts database has a CUSTOM_RINGTONE field, see this page:

http://developer.android.com/reference/android/provider/ContactsContract.ContactOptionsColumns.html#CUSTOM_RINGTONE

The value for this field must be a content:// URI to a media file. You can obtain one from the MedciaStore content provider:

http://developer.android.com/reference/android/provider/MediaStore.MediaColumns.html

That may be enough to get you started. This is all standard content provider stuff; lots of existing material for both tasks.

Dniren answered 19/10, 2011 at 11:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.