Android Question Turn Speakerphone On/Off over all versions of Android

William Hunter

Active Member
Licensed User
Longtime User
I am trying to create a Sub that will turn Speakerphone On/Off over all versions of Android. My code is based on what I have read on this forum as well as StackOverflow. This point may or may not be true, but it seems that the method using Reflector works with SDK 20 (KitKat 4.4) and below, while the JavaObject method is required for SDK 21 (Lollipop 5.0) and above. I made this assumption based the difficulties described by others.

It would be greatly appreciated if someone would review my code, and provide comment as to whether it is correct, or in need of some modification. I don’t have devices beyond SDK 20, so I don’t have the means of testing this fully. Any help greatly appreciated.

B4A Code
B4X:
Sub SpeakerPhoneOnOff
   'open/close speakerphone
   Dim phone1 As Phone
   Dim result As Int
   result=phone1.sdkVersion
   'Log("sdkVersion = " & result)
   If result < 21 Then ' KitKat 4.4 and below
     Dim rr As Reflector
     rr.Target = rr.GetContext
     rr.Target = rr.RunMethod2("getSystemService", "audio", "java.lang.String")
     If SpkrPhoneOnFlag = False Then
       SpkrPhoneOnFlag = True
       'Log("SpkrPhoneOnFlag = " & SpkrPhoneOnFlag)
       rr.RunMethod2("setSpeakerphoneOn", True, "java.lang.boolean") 'Turn on SpeakerPhone
       ToastMessageShow("SPEAKER ON!!", False)
     Else If SpkrPhoneOnFlag = True Then
       SpkrPhoneOnFlag = False
       'Log("SpkrPhoneOnFlag = " & SpkrPhoneOnFlag)
       rr.RunMethod2("setSpeakerphoneOn", False, "java.lang.boolean") 'Turn off SpeakerPhone
       ToastMessageShow("SPEAKER OFF!!", False)
     End If
   Else ' Lollipop 5.0 and above
     Dim java As JavaObject
     java.InitializeContext
     If SpkrPhoneOnFlag = False Then
       SpkrPhoneOnFlag = True
       'Log("SpkrPhoneOnFlag = " & SpkrPhoneOnFlag)
       java.RunMethod("setSpeakerOn", Null) 'Turn on SpeakerPhone
       ToastMessageShow("SPEAKER ON!!", False)
     Else If SpkrPhoneOnFlag = True Then
       SpkrPhoneOnFlag = False
       'Log("SpkrPhoneOnFlag = " & SpkrPhoneOnFlag)
       java.RunMethod("setSpeakerOff", Null) 'Turn off SpeakerPhone
       ToastMessageShow("SPEAKER OFF!!", False)
     End If
   End If
End Sub

Java Code
B4X:
#If JAVA
import android.media.AudioManager;
public void setSpeakerOn() {
   
  AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
  audioManager.setMode(AudioManager.MODE_IN_CALL);
  audioManager.setSpeakerphoneOn(true);
   }
   
public void setSpeakerOff() {
   
  AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
  audioManager.setMode(AudioManager.MODE_NORMAL);
   audioManager.setSpeakerphoneOn(false);
   }
#End if

Best regards :)
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Your code is equivalent to this (simpler) code:
B4X:
Sub SetSpeakerPhone(state As Boolean)
   Dim audioManager As JavaObject
   audioManager = audioManager.InitializeContext.RunMethodJO("getSystemService", Array("audio"))
   Dim mode As Int
   If state Then mode = 2 Else mode = 0 'MODE_IN_CALL or MODE_NORMAL
   audioManager.RunMethod("setMode", Array(mode))
   audioManager.RunMethod("setSpeakerphoneOn", Array(state))
End Sub

It doesn't seem to turn off the speaker on Android 6.0. At least not with MediaPlayer.
 
Upvote 0

William Hunter

Active Member
Licensed User
Longtime User
Your code is equivalent to this (simpler) code:
B4X:
Sub SetSpeakerPhone(state As Boolean)
   Dim audioManager As JavaObject
   audioManager = audioManager.InitializeContext.RunMethodJO("getSystemService", Array("audio"))
   Dim mode As Int
   If state Then mode = 2 Else mode = 0 'MODE_IN_CALL or MODE_NORMAL
   audioManager.RunMethod("setMode", Array(mode))
   audioManager.RunMethod("setSpeakerphoneOn", Array(state))
End Sub

It doesn't seem to turn off the speaker on Android 6.0. At least not with MediaPlayer.
Thank you Erel, I will use your code. As a related item, how would one use isSpeakerPhoneOn? Is the code below correct?
B4X:
Sub isSpkrOn
   Dim SpkrOn As Boolean
   Dim audioManager As JavaObject
   audioManager.InitializeStatic("android.media.AudioManager")
   SpkrOn = audioManager.GetField("isSpeakerphoneOn"))
   If SpkrOn = True Then
     ' do whatever
   End If
End Sub

I'm struggling a bit with JavaOject, and any help is greatly appreciated.

Best regards :)
 
Upvote 0

William Hunter

Active Member
Licensed User
Longtime User
No.

The correct way to get an AudioManager is with this code:
B4X:
Dim audioManager AsJavaObject
audioManager = audioManager.InitializeContext.RunMethodJO("getSystemService", Array("audio"))
Thank you for your reply. I am trying to find if SpeakerPhone is on or off. So far this eludes me. Will you please correct my code to show me how it's done. The code I have gives a Java RunTimeException.

My code
B4X:
Sub isSpeakerOn
   Dim SpkrOn As Boolean
   Dim audioManager As JavaObject
   audioManager = audioManager.InitializeContext.RunMethod("getSystemService",   Array("audio"))
   SpkrOn = audioManager.GetField("isSpeakerPhoneOn")
   Log("SpkrOn = " & SpkrOn)
   If SpkrOn = False Then
      SetSpeakerPhone(True)  
   End If
End Sub
Log
B4X:
LogCat connected to: emulator-5554
--------- beginning of main
--------- beginning of system~i:** Activity (main) Create, isFirst = true **~e:main_vvvvv4 (java line: 593)
java.lang.RuntimeException: Field: isSpeakerPhoneOn not found in: android.media.AudioManager
   at anywheresoftware.b4j.object.JavaObject$FieldCache.getField(JavaObject.java:306)
   at anywheresoftware.b4j.object.JavaObject.GetField(JavaObject.java:181)
   at wfh.videochat.main._vvvvv4(main.java:593)
   at wfh.videochat.main._activity_create(main.java:361)
   at java.lang.reflect.Method.invoke(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:372)
   at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
   at wfh.videochat.main.afterFirstLayout(main.java:103)
   at wfh.videochat.main.access$000(main.java:18)
   at wfh.videochat.main$WaitForLayout.run(main.java:81)
   at android.os.Handler.handleCallback(Handler.java:739)
   at android.os.Handler.dispatchMessage(Handler.java:95)
   at android.os.Looper.loop(Looper.java:135)
   at android.app.ActivityThread.main(ActivityThread.java:5257)
   at java.lang.reflect.Method.invoke(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:372)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
java.lang.RuntimeException: Field: isSpeakerPhoneOn not found in: android.media.AudioManager

Best Regards :)
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
Last edited:
Upvote 0

William Hunter

Active Member
Licensed User
Longtime User
public boolean isSpeakerphoneOn ()
That´s not a FIELD, it is a method.

Solution can be (not sure about this as i don´t use Javaobject and/or reflection much often!!)
Give it a try:
B4X:
SpkrOn = audioManager.RunMethod("isSpeakerPhoneOn",null)

See

http://developer.android.com/reference/android/media/AudioManager.html#isSpeakerphoneOn()
Thank you for your interest DonManfred. I tried your suggestion and got the same result. I've tried everything I can think of, and still no joy. Do you, or anyone else, have any other ideas. Below is my code and the log.

B4A Code
B4X:
Sub isSpeakerOn
   Dim SpkrOn As Boolean
   Dim audioManager As JavaObject
   audioManager = audioManager.InitializeContext.RunMethod("getSystemService", Array("audio"))
   SpkrOn = audioManager.RunMethod("isSpeakerPhoneOn", Null)
   Log("SpkrOn = " & SpkrOn)
   If SpkrOn = False Then
      SetSpeakerPhone(True)   
   End If
End Sub
Log
B4X:
** Activity (main) Create, isFirst = true **~e:main_vvvvv4 (java line: 592)
java.lang.RuntimeException: Method: isSpeakerPhoneOn not found in: android.media.AudioManager
   at anywheresoftware.b4j.object.JavaObject$MethodCache.getMethod(JavaObject.java:366)
   at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:119)
   at wfh.videochat.main._vvvvv4(main.java:592)
   at wfh.videochat.main._activity_create(main.java:360)
   at java.lang.reflect.Method.invoke(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:372)
   at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
   at wfh.videochat.main.afterFirstLayout(main.java:102)
   at wfh.videochat.main.access$000(main.java:17)
   at wfh.videochat.main$WaitForLayout.run(main.java:80)
   at android.os.Handler.handleCallback(Handler.java:739)
   at android.os.Handler.dispatchMessage(Handler.java:95)
   at android.os.Looper.loop(Looper.java:135)
   at android.app.ActivityThread.main(ActivityThread.java:5257)
   at java.lang.reflect.Method.invoke(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:372)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
java.lang.RuntimeException: Method: isSpeakerPhoneOn not found in: android.media.AudioManager

Best regards :)
 
Upvote 0

moster67

Expert
Licensed User
Longtime User
1) Check your spelling ;) The correct method name is "isSpeakerphoneOn" and not "isSpeakerPhoneOn".
2) I got it working using "AUDIO_SERVICE" (and not "audio") to get an instance of this class.

B4X:
Sub Activity_Create(FirstTime As Boolean)
    Log("The big question: Is the speaker phone on? --> " & isTheSpeakerPhoneOn)
End Sub

Sub isTheSpeakerPhoneOn As Boolean   
    Dim R As Reflector
    Dim audioManager As JavaObject
    Dim Context As JavaObject = R.GetContext
    audioManager = Context.RunMethod("getSystemService",Array As Object(Context.GetField("AUDIO_SERVICE")))
   
    Return audioManager.RunMethod("isSpeakerphoneOn",Null)
End Sub
 
Upvote 0

William Hunter

Active Member
Licensed User
Longtime User
1) Check your spelling ;) The correct method name is "isSpeakerphoneOn" and not "isSpeakerPhoneOn".
2) I got it working using "AUDIO_SERVICE" (and not "audio") to get an instance of this class.

B4X:
Sub Activity_Create(FirstTime As Boolean)
    Log("The big question: Is the speaker phone on? --> " & isTheSpeakerPhoneOn)
End Sub

Sub isTheSpeakerPhoneOn As Boolean
    Dim R As Reflector
    Dim audioManager As JavaObject
    Dim Context As JavaObject = R.GetContext
    audioManager = Context.RunMethod("getSystemService",Array As Object(Context.GetField("AUDIO_SERVICE")))

    Return audioManager.RunMethod("isSpeakerphoneOn",Null)
End Sub
Thank you moster67. Your help is very much appreciated. I was lost not knowing I had to get Reflector into it. The combination of your code and Erel's Sub SetSpeakerPhone is doing exactly what I needed to do. Thank you to all who offered assistance.

Best regards :cool:
 
Last edited:
Upvote 0

antonio.murtino

Member
Licensed User
Longtime User
Your code is equivalent to this (simpler) code:
B4X:
Sub SetSpeakerPhone(state As Boolean)
   Dim audioManager As JavaObject
   audioManager = audioManager.InitializeContext.RunMethodJO("getSystemService", Array("audio"))
   Dim mode As Int
   If state Then mode = 2 Else mode = 0 'MODE_IN_CALL or MODE_NORMAL
   audioManager.RunMethod("setMode", Array(mode))
   audioManager.RunMethod("setSpeakerphoneOn", Array(state))
End Sub

It doesn't seem to turn off the speaker on Android 6.0. At least not with MediaPlayer.
I'm sorry , but why the app crashes every time it is called the sub SetSpeakerPhone ( 2 ) ?
 
Upvote 0

antonio.murtino

Member
Licensed User
Longtime User
[ SOLVED ] , I have not used the sub SetSpeakerPhone , but simply the library ANSWERCALL , in this way:
B4X:
Dim Ac As AnswerCall
AC.enableSpeakerphone

when a call is active , the event I added these lines of code , it works without any problem.
 
Upvote 0
Top