Android Question MediaSessions

Jmu5667

Well-Known Member
Licensed User
Longtime User

Erel

B4X founder
Staff member
Licensed User
Longtime User
Start with this code (put it in the Starter service):

B4X:
Sub Process_Globals
   Private session As JavaObject
End Sub

Sub Service_Create
   Dim context As JavaObject
   context.InitializeContext
   session.InitializeNewInstance("android.media.session.MediaSession", Array(context, "tag"))
   session.RunMethod("setActive", Array(True))
   Dim cb As JavaObject
   cb.InitializeNewInstance(Application.PackageName & ".starter.MyCallback", Null)
   session.RunMethod("setCallback", Array(cb))
End Sub

Sub Media_OnCommand(Command As String)
   Log(Command)
End Sub
#if java
import android.media.session.MediaSession.*;
import android.os.Bundle;
import android.os.ResultReceiver;
public static class MyCallback extends Callback {
   public MyCallback() {
   }
   public void onCommand(String command, Bundle args, ResultReceiver cb) {
     processBA.raiseEventFromUI(null, "media_oncommand", command);
   }
}
#end if
I'm not sure when onCommand is called. However it should raise the event and run the Media_OnCommand sub.
 
Upvote 0

Jmu5667

Well-Known Member
Licensed User
Longtime User
Start with this code (put it in the Starter service):

B4X:
Sub Process_Globals
   Private session As JavaObject
End Sub

Sub Service_Create
   Dim context As JavaObject
   context.InitializeContext
   session.InitializeNewInstance("android.media.session.MediaSession", Array(context, "tag"))
   session.RunMethod("setActive", Array(True))
   Dim cb As JavaObject
   cb.InitializeNewInstance(Application.PackageName & ".starter.MyCallback", Null)
   session.RunMethod("setCallback", Array(cb))
End Sub

Sub Media_OnCommand(Command As String)
   Log(Command)
End Sub
#if java
import android.media.session.MediaSession.*;
import android.os.Bundle;
import android.os.ResultReceiver;
public static class MyCallback extends Callback {
   public MyCallback() {
   }
   public void onCommand(String command, Bundle args, ResultReceiver cb) {
     processBA.raiseEventFromUI(null, "media_oncommand", command);
   }
}
#end if
I'm not sure when onCommand is called. However it should raise the event and run the Media_OnCommand sub.


Hi Erel

Application.PackageName & ".starter.MyCallback" , does .starter refer to the service name and .myCallback refer to a sub in the service ?

Regards

John.
 
Upvote 0

lemonisdead

Well-Known Member
Licensed User
Longtime User
I'll do it this afternoon John and come back to you. @Jmu5667

Edit : it does not work. I have immediately got an error (even on Lollipop ~ seen the API 21)
java.lang.ClassNotFoundException: android$media$session$MediaSession

Trying now on Nexus : no crash but no event received (nothing happens). I have to find another device using Android 5.1.1
Tested on a new Wiko Rainbow Lite 4G, no crash but nothing happens
 
Last edited:
Upvote 0

Jmu5667

Well-Known Member
Licensed User
Longtime User
I'll do it this afternoon John and come back to you. @Jmu5667

Edit : it does not work. I have immediately got an error (even on Lollipop ~ seen the API 21)


Trying now on Nexus : no crash but no event received (nothing happens). I have to find another device using Android 5.1.1
Tested on a new Wiko Rainbow Lite 4G, no crash but nothing happens


Mmm...I am collection a lollypop device tommorrow, @Erel any views on this ?
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
Is your android.jar set in Tools/Configure Paths >= API 21?
 
Upvote 0

lemonisdead

Well-Known Member
Licensed User
Longtime User
Hello,
I do confirm that I had set the path to C:\AndroidSDK\platforms\android-23\android.jar and <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21"/> in the Manifest
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
It compiles and runs without errors on my Nexus 7 (Android 6.0.1). I can't test the functionality as I don't know what else needs to be set up in order for it to do something, but the code as posted is running OK.
 
Upvote 0

lemonisdead

Well-Known Member
Licensed User
Longtime User
Could you plug a headset with a Media button on it and press the button ? The logs should print the command received ?
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
Upvote 0

stevel05

Expert
Licensed User
Longtime User
It doesn't log anything, the button is working as it calls up google search, but no log.
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
Not a problem, I've sort of got it working, you also need to set a flag, and it calls the onMediaButtonEvent method. I'll post it if I can get it working it properly.
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
This is as far as I have got:
B4X:
Sub Process_Globals
   Private session As JavaObject
End Sub

Sub Service_Create
   Dim context As JavaObject
   context.InitializeContext
   session.InitializeNewInstance("android.media.session.MediaSession", Array(context, "tag"))

   Dim cb As JavaObject
   cb.InitializeNewInstance(Application.PackageName & ".starter.MyCallback", Null)
    session.RunMethod("setCallback", Array(cb))
   
    session.RunMethod("setFlags",Array(3))
    session.RunMethod("setActive", Array(True))
End Sub

Sub Service_Start (StartingIntent As Intent)

End Sub

'Return true to allow the OS default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub

Sub Service_Destroy
    session.RunMethod("release",Null)
End Sub
Sub Media_OnCommand(Command As String)
   Log(Command)
End Sub
Sub Media_OnButton(Intent As Object)
    Log(Intent)
End Sub
#if java
import android.media.session.MediaSession.*;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.content.Intent;
public static class MyCallback extends Callback {
   public MyCallback() {
   }
   public void onCommand(String command, Bundle args, ResultReceiver cb) {
   BA.Log(command);
     processBA.raiseEventFromUI(null, "media_oncommand", command);
   }
   public boolean onMediaButtonEvent(Intent mediaButtonIntent) {
     processBA.raiseEvent(null, "media_onbutton", mediaButtonIntent);
     return false;
   }
}
#end if

There are a couple of issues to sort out:

1 - Wrapping the intent as a BA intent.
2 - Casting the returned Object from processBA.raiseEvent to a boolean so you can stop or allow the default button action.

I have run out of time now, but I'm sure Erel will be able to sort it out in much less time than it would take me.

But it does function, just :)
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
Updated Version,

Seems to work, but I only have one key on the headphones to test and It doesn't block the search from coming up, but I'm not sure that that isn't intended result in this case. Unless the cast in incorrect.

See what you think.

B4X:
Sub Process_Globals
   Private session As JavaObject
End Sub

Sub Service_Create
   Dim context As JavaObject
   context.InitializeContext
   session.InitializeNewInstance("android.media.session.MediaSession", Array(context, "tag"))

   Dim cb As JavaObject
   cb.InitializeNewInstance(Application.PackageName & ".starter.MyCallback", Null)
    session.RunMethod("setCallback", Array(cb))
 
    session.RunMethod("setFlags",Array(3))
    session.RunMethod("setActive", Array(True))
End Sub

Sub Service_Start (StartingIntent As Intent)

End Sub

'Return true to allow the OS default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub

Sub Service_Destroy
    session.RunMethod("release",Null)
End Sub
Sub Media_OnCommand(Command As String)
   Log(Command)
End Sub
Sub Media_OnButton(Intent As Intent) As Boolean
    Log(Intent.Action)
    Return True
End Sub
#if java
import android.media.session.MediaSession.*;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.content.Intent;
import anywheresoftware.b4a.objects.IntentWrapper;
public static class MyCallback extends Callback {
   public MyCallback() {
   }
   public void onCommand(String command, Bundle args, ResultReceiver cb) {
   BA.Log(command);
     processBA.raiseEventFromUI(null, "media_oncommand", command);
   }
   public boolean onMediaButtonEvent(Intent mediaButtonIntent) {
     IntentWrapper baIntent = new IntentWrapper();
     baIntent.setObject(mediaButtonIntent);
    Boolean b = (Boolean) processBA.raiseEvent(null, "media_onbutton", baIntent);
    return b == null ? false : b;
   }
}
#end if
 
Last edited:
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
There is a small bug in this code:
B4X:
 public boolean onMediaButtonEvent(Intent mediaButtonIntent) {
 IntentWrapper baIntent = new IntentWrapper();
 baIntent.setObject(mediaButtonIntent);
 return (Boolean) processBA.raiseEvent(null, "media_onbutton", baIntent);
 }
processBA.raiseEvent can return Null in some cases (if the target is paused for example). It will then cause a NullPointerException when it tries to cast Boolean to the primitive boolean.

Correct code:
B4X:
Boolean b = processBA.raiseEvent(...)
return b == null ? false : b;
 
Upvote 0
Top