Search code examples
androidtext-to-speechandroid-audiomanagerandroid-broadcastreceivergoogle-text-to-speech

Mute the ringer volume during a call in android


My aim is to let the user know the person who is calling.I am using TextToSpeech for this task in a service.

So I decided to mute the ringer volume during a call :

  mAudioManager=(AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
            volume = mAudioManager.getStreamVolume(AudioManager.STREAM_RING);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                mAudioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_MUTE, 0);
            } else {
                mAudioManager.setStreamMute(AudioManager.STREAM_MUSIC, true);
            }

I know that this is the code to add but where? Is it in the class which extends broadcast receiver?

My problem is that whenever a call occurs, the phone rings normally. I want to mute the ringtone and make my TextToSpeech object to speak

My manifest file is as follows:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.sairaman63yahoo.callerannouncer">
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <receiver android:name=".CalReceiver">
        <intent-filter>
            <action android:name="android.intent.action.PHONE_STATE"/>
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
        </intent-filter>


    </receiver>
    <service android:name=".CallService" android:enabled="true"></service>

    <activity
        android:name=".DetectPhoneCallsActivity"
        android:label="@string/app_name"
        android:theme="@style/AppTheme.NoActionBar">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

</manifest>

My PhoneCallReceiver class which extends broadcast receiver is :

public abstract class PhoneCallReceiverbase extends BroadcastReceiver {

private int mRingVolume=0;
public static int lastState= TelephonyManager.CALL_STATE_IDLE;
public  static Date callstartTime;
public static boolean isIncoming;
public static String savedNumber;
private static  AudioManager mAudioManager;
private int volume;

@Override
public void onReceive(Context context, Intent intent) {
    if(intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")){
        savedNumber=intent.getExtras().getString("android.intent.extra.PHONE_NUMBER");
    }
    else
    {
        String stateStr=intent.getExtras().getString(TelephonyManager.EXTRA_STATE);
        String number=intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
        int state=0;
        if(stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE))
            state=TelephonyManager.CALL_STATE_IDLE;
        else if(stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK))
            state=TelephonyManager.CALL_STATE_OFFHOOK;
        else  if(stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
            state= TelephonyManager.CALL_STATE_RINGING;
            onCallStateChaned(context,state,number);

        }



    }
}

private void onCallStateChaned(Context context, int state, String number) {
    if(lastState==state){
        return;
    }

  //  mAudioManager.setStreamMute(AudioManager.STREAM_RING, true);

    switch (state){
        case TelephonyManager.CALL_STATE_RINGING:
      //  AudioManager manager=(AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
            isIncoming = true;
          callstartTime = new Date();
          savedNumber = number;
          onIncomingCallReceived(context, number, callstartTime);
            break;
        case TelephonyManager.CALL_STATE_OFFHOOK:
            //offhook are pickup calls....nothing is done on them
            if(lastState!=TelephonyManager.CALL_STATE_RINGING)
            {
                isIncoming=false;
                callstartTime=new Date();
                onOutGoingCallStarted(context,number,callstartTime);

            }
            else
            {
                isIncoming=true;
                callstartTime=new Date();
                onIncomingCallAnswered(context,number,callstartTime);

            }
            break;
        case TelephonyManager.CALL_STATE_IDLE:
            if(lastState==TelephonyManager.CALL_STATE_RINGING){
                onMissedCall(context,number,callstartTime);
            }
            else if(isIncoming)
                onIncomingCallEnded(context,number,callstartTime,new Date());
            else
                onOutGoingCallEnded(context,number,callstartTime,new Date());
            break;
    }
    lastState=state;

}

protected abstract void onIncomingCallReceived(Context context,String number,Date start);
protected abstract void onIncomingCallAnswered(Context context,String number,Date start);
protected abstract void onIncomingCallEnded(Context context,String number,Date start,Date end);
protected abstract void onOutGoingCallStarted(Context context,String number,Date start);
protected abstract void onOutGoingCallEnded(Context context,String number,Date start,Date end);
protected abstract void onMissedCall(Context context,String number,Date start);
}

My CallReceiver class which extends PhoneCallReceiver class is :

public class CalReceiver extends PhoneCallReceiverbase {

TextToSpeech toSpeech;
private AudioManager mAudioManager;
private int volume;


@Override
protected void onIncomingCallReceived(Context context, String number, Date start) {

    mAudioManager=(AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
    volume = mAudioManager.getStreamVolume(AudioManager.STREAM_RING);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        mAudioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_MUTE, 0);
    } else {
        mAudioManager.setStreamMute(AudioManager.STREAM_MUSIC, true);
    }
    Intent intent1 = new Intent(context.getApplicationContext(), CallService.class);
    intent1.putExtra("call", "CALL RECEIVED");
    context.startService(intent1);

   // Toast.makeText(context, "CALL RECIEVED", Toast.LENGTH_LONG).show();


    final ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
    final List<ActivityManager.RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);

    for (ActivityManager.RunningServiceInfo runningServiceInfo : services) {
        if (runningServiceInfo.service.getClassName().equals(CallService.class)) {
            Log.v("SERVICE", "RUNNING");

        }
    }
}



@Override
protected void onIncomingCallAnswered(Context context, String number, Date start) {

}

@Override
protected void onIncomingCallEnded(Context context, String number, Date start, Date end) {
    Toast.makeText(context,"CALL ENDED",Toast.LENGTH_LONG).show();

}

@Override
protected void onOutGoingCallStarted(Context context, String number, Date start) {
    Toast.makeText(context,"CALL STARTED",Toast.LENGTH_LONG).show();




}

@Override
protected void onOutGoingCallEnded(Context context, String number, Date start, Date end) {
    Toast.makeText(context,"CALL ENDED",Toast.LENGTH_LONG).show();
}

@Override
protected void onMissedCall(Context context, String number, Date start) {
    Toast.makeText(context,"MISSED CALL",Toast.LENGTH_LONG).show();
}
}

Finally, my Service class which speaks something is:

public class CallService extends Service implements TextToSpeech.OnInitListener,TextToSpeech.OnUtteranceCompletedListener {

int volume=0;
private TextToSpeech tts;
private String spoken="call started sir!";
private AudioManager mAudioManager;

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public void onCreate() {
    tts=new TextToSpeech(this,this);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    spoken=(String)intent.getExtras().get("call");
    return super.onStartCommand(intent, flags, startId);
}

@Override
public void onInit(int status) {
if(status==TextToSpeech.SUCCESS)
{
    // mAudioManager.setStreamMute(AudioManager.STREAM_RING, true);
    tts.setLanguage(Locale.ENGLISH);
    //   toSpeech.speak("CALL IS COMING",TextToSpeech.QUEUE_FLUSH,null);
    if (Build.VERSION.RELEASE.startsWith("5")) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            tts.speak(spoken, TextToSpeech.QUEUE_FLUSH, null, null);
        }
    }
    else {
        tts.speak(spoken, TextToSpeech.QUEUE_FLUSH, null);
    }
}
}

@Override
public void onUtteranceCompleted(String utteranceId){
mAudioManager.setStreamMute(AudioManager.STREAM_RING, false);
mAudioManager.setStreamVolume(AudioManager.STREAM_RING,
volume, AudioManager.FLAG_ALLOW_RINGER_MODES);
    stopSelf();
}
}

Summarizing the query:

Aim: To mute the ringer volume during a call and make the TextToSpeech object speak something and continue the ringer volume after the speech

Problem : 1)Where to add the code which mutes the ringer volume 2) I've added the code in CallReceiver class, in the onIncomingCallReceived() but it doesn't seem to work.The ringtone doesn't stop

Please help!

I know that its a long question but I'm stuck here. Thanks for the help!


Solution

  • As I said in my comment, I could not find a way for my application to do what you want. I could only silence the current ringtone and was unable to start it, other than replicating the user's ringtone after the TTS had announced the call and monitoring their further interaction with the pending call, which is complex.

    To do this:

    public static void muteRinger(final Context ctx, final boolean mute) {
    
        final AudioManager am = (AudioManager) ctx.getSystemService(Context.AUDIO_SERVICE);
    
        switch (am.getRingerMode()) {
    
            case AudioManager.RINGER_MODE_NORMAL:
                Log.i("TAG", "getRingerMode: RINGER_MODE_NORMAL");
                break;
            case AudioManager.RINGER_MODE_SILENT:
                Log.i("TAG", "getRingerMode: RINGER_MODE_NORMAL");
                break;
            case AudioManager.RINGER_MODE_VIBRATE:
                Log.i("TAG", "getRingerMode: RINGER_MODE_NORMAL");
                break;
            default:
                Log.e("TAG", "getRingerMode: Default??");
                break;
        }
    
    
        if(mute){
            Log.i("TAG", "muting ringtone");
    
        // Save am.getRingerMode() to the shared preferences as the user's default            
    
            try {
                am.setRingerMode(AudioManager.RINGER_MODE_SILENT);
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        } else {
            Log.i("TAG", "restoring ringtone");
    
            try {
                am.setRingerMode(// The default you previously saved);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    Obviously, if you fail to restore the user's ringtone settings correctly, you'll have an annoyed user and if they miss an important call, you could be in trouble......