Sunday, June 9, 2013

Android - Make a phone call with speaker on programatically

In this post, I'm sharing with you the Android code to turn on the speaker when making a call in a programatically way .

The idea behind is to place a call and to listen to the phone state change to switch on the speaker when the call is established.

package com.danielthat.loudspeaker;

import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class Loudspeaker extends Activity {

 Button mButton;
 EditText mEdit;
 TelephonyManager manager;
 StatePhoneReceiver myPhoneStateListener;
 boolean callFromApp=false; // To control the call has been made from the application
 boolean callFromOffHook=false; // To control the change to idle state is from the app call


 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.layout_loudspeaker);

  //To be notified of changes of the phone state create an instance
  //of the TelephonyManager class and the StatePhoneReceiver class
  myPhoneStateListener = new StatePhoneReceiver(this);
  manager = ((TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE));

  mEdit   = (EditText)findViewById(R.id.editText1);
      
  mButton = (Button) findViewById(R.id.button1);
  mButton.setOnClickListener(new View.OnClickListener() {
  
   public void onClick(View v) {
  
    String phoneNumber = mEdit.getText().toString();
    manager.listen(myPhoneStateListener,
    PhoneStateListener.LISTEN_CALL_STATE); // start listening to the phone changes
    callFromApp=true;
    Intent i = new Intent(android.content.Intent.ACTION_CALL,
                          Uri.parse("tel:+" + phoneNumber)); // Make the call       
    startActivity(i);   
   } 
  }); 
 }


 // Monitor for changes to the state of the phone
 public class StatePhoneReceiver extends PhoneStateListener {
     Context context;
     public StatePhoneReceiver(Context context) {
         this.context = context;
     }

     @Override
     public void onCallStateChanged(int state, String incomingNumber) {
         super.onCallStateChanged(state, incomingNumber);
        
         switch (state) {
        
         case TelephonyManager.CALL_STATE_OFFHOOK: //Call is established
          if (callFromApp) {
              callFromApp=false;
              callFromOffHook=true;
                  
              try {
                Thread.sleep(500); // Delay 0,5 seconds to handle better turning on loudspeaker
              } catch (InterruptedException e) {
              }
          
              //Activate loudspeaker
              AudioManager audioManager = (AudioManager)
                                          getSystemService(Context.AUDIO_SERVICE);
              audioManager.setMode(AudioManager.MODE_IN_CALL);
              audioManager.setSpeakerphoneOn(true);
           }
           break;
        
        case TelephonyManager.CALL_STATE_IDLE: //Call is finished
          if (callFromOffHook) {
                callFromOffHook=false;
                AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
                audioManager.setMode(AudioManager.MODE_NORMAL); //Deactivate loudspeaker
                manager.listen(myPhoneStateListener, // Remove listener
                      PhoneStateListener.LISTEN_NONE);
             }
          break;
         }
     }
 }
}

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.danielthat.loudspeaker"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />
  
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.danielthat.loudspeaker.Loudspeaker"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".Loudspeaker" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Number to call with loudspeaker on:" />

    <EditText
        android:id="@+id/editText1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView1"
        android:layout_below="@+id/textView1"
        android:ems="10"
        android:inputType="phone" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/editText1"
        android:layout_below="@+id/editText1"
        android:text="Call" />

</RelativeLayout>



6 comments:

  1. Excellent post. Very helpful

    ReplyDelete
  2. Hello, your code works perfectly fine. I have implemented it in different manner, as I have given a custom button on my custom screen from where user can set Speaker phone On/Off. this also works fine. but the problem is, When the User sets the Speaker Off, the Speaker sound gets normal. but the Native Speaker button still shows the Speaker On. How ca I handle it. My Code for On is,
    if(!audioManager.isSpeakerphoneOn()) {
    audioManager.setSpeakerphoneOn(true);
    }

    And for Off is:

    if(audioManager.isSpeakerphoneOn()) {
    audioManager.setSpeakerphoneOn(false);
    audioManager.setMode(AudioManager.MODE_NORMAL);
    }

    Please let me know any corrections i have to implement.

    ReplyDelete
    Replies
    1. Hi Azharuddin,

      I would say that when you are turning On the speaker you need do it as:

      if(!audioManager.isSpeakerphoneOn()) {
      audioManager.setMode(AudioManager.MODE_IN_CALL)
      audioManager.setSpeakerphoneOn(true);
      }

      If you need further support, please send the complete code of your app to support@danielthat.com and I will take a deeper look.


      Cheers,

      Daniel

      Delete
    2. Hi Daniel! Thanks for your quick reply.

      Yes, I am already setting the mode as "AudioManager.MODE_IN_CALL", as per your sample above. My Issue is, When I do setSpeakerOn(true), the loudspeaker is activated and also the default caller Loudspeaker button is highlighted (denoting the action).
      but when I call the setSpeakerOn(false), the loudspeaker is put to OFF but the default caller Loudspeaker button is still highlighted. How can I handle the default Speaker button to get Unhighlighted.

      Delete
    3. Hi again,

      Theoretically, when you set up the loudspeaker off, the default buttion should get unhighlighted as well...

      Please send me the code files and I will run it to see if I can sort out the problem.

      Send the files to support@danielthat.com

      Daniel

      Delete
    4. Ok, will send you. Please let me know If you found any Problem.

      Thanks & regards,
      Azhar

      Delete