Android Code Snippet Using StartActivityForResult with JavaObject

Erel

Administrator
Staff member
Licensed User
SubName: StartActivityForResult

Description: This code demonstrates how JavaObject can be used to call external APIs that should be called with Context.startActivityForResult.

This code should be added to an Activity. You should also declare a process global variable named ion:
B4X:
Sub Process_Globals
   Private ion As Object
End Sub
B4X:
Sub ion_Event (MethodName As String, Args() As Object) As Object
'Args(0) = resultCode
'Args(1) = intent
Return Null
End Sub

Sub StartActivityForResult(i As Intent)
   Dim jo As JavaObject = GetBA
   ion = jo.CreateEvent("anywheresoftware.b4a.IOnActivityResult", "ion", Null)
   jo.RunMethod("startActivityForResult", Array As Object(ion, i))
End Sub

Sub GetBA As Object
   Dim jo As JavaObject
   Dim cls As String = Me
   cls = cls.SubString("class ".Length)
   jo.InitializeStatic(cls)
   Return jo.GetField("processBA")
End Sub
For example we can show the Ringtone picker with this code:
B4X:
Sub Activity_Create(FirstTime As Boolean)
   If FirstTime Then
     ShowPicker
   End If   
End Sub

Sub ShowPicker
   Dim i As Intent
   i.Initialize("android.intent.action.RINGTONE_PICKER", "")
   i.PutExtra("android.intent.extra.ringtone.TYPE", 1)
   StartActivityForResult(i)
End Sub


Sub ion_Event (MethodName As String, Args() As Object) As Object
   If Args(0) = -1 Then 'resultCode = RESULT_OK
     Dim i As Intent = args(1)
     Dim jo As JavaObject = i
     Dim uri As String = jo.RunMethod("getParcelableExtra", _
       Array As Object("android.intent.extra.ringtone.PICKED_URI"))
     Log(uri)
   End If
   Return Null
End Sub
Dependencies: JavaObject v1.20+

Tags: StartActivityForResult, OnActivityResult
 
Last edited:

Erel

Administrator
Staff member
Licensed User
Accessing external APIs is an advanced issue which will usually require usage of JavaObject to extract the data. You can make a code module out of this code. Or compile it into a library. The result will be the same.
 

LucaMs

Expert
Licensed User
Description: ... can be used to call external APIs that should be called with Context.startActivityForResult.
It is possible to use it also to call internal activities? (Yes, you've already responded to me that I can use CallSubDelayed, but you did not developed this at that time :))
 

Erel

Administrator
Staff member
Licensed User
There are no advantages for this method over CallSubDelayed. CallSubDelayed is simpler to use and is actually more powerful (for internal activities).
 

bluedude

Well-Known Member
Licensed User
Could you provide a sample for the contactlist? I only target Android 4.x so I guess that will always work.
 

Erel

Administrator
Staff member
Licensed User
1. Add the following permission to the manifest editor:
B4X:
AddPermission(android.permission.READ_CONTACTS)
2. Use the following code:
B4X:
Sub Activity_Click
   Dim i As Intent
   i.Initialize(i.ACTION_PICK, "content://com.android.contacts/contacts")
   StartActivityForResult(i)
End Sub

Sub ion_Event (MethodName As String, Args() As Object) As Object
   If Args(0) = -1 Then 'resultCode = RESULT_OK
     Dim i As Intent = args(1)
     Dim id As String = i.GetData.SubString(i.GetData.LastIndexOf("/") + 1)
     Dim cu As ContactsUtils
     cu.Initialize
     Log(cu.GetNameFromId(id))
   End If
   Return Null
End Sub
Add the following sub to ContactsUtils:
B4X:
Public Sub GetNameFromId (id As String) As String
   Dim crsr As Cursor = cr.Query(dataUri, Array As String("contact_id", "display_name"), "contact_id = ?", _
     Array As String(id), "")
   Dim name As String
   If crsr.RowCount = 0 Then
     Log("Contact not found: " & id)
   Else
     crsr.Position = 0
     name = crsr.GetString2(1)
   End If
   crsr.Close
   Return name
End Sub
 

bluedude

Well-Known Member
Licensed User
Works great but wondering how to get the email address of the user? Tried a few things but could not get it.
 

geodesic

New Member
Licensed User
I may be missing something obvious, but I am still a novice and trying to figure out how values are reflected between Java and b4a. I had a need for an intent with a return, so I copied this code (almost) except I substituted ACCOUNT_PICKER instead of RINGTONE_PICKER.

My first attempt to read the return value failed, using the code:
B4X:
account = jo.RunMethod("getStringExtra", Array As Object("android.accounts.AccountManager.KEY_ACCOUNT_NAME"))
The result came back null. Strange, as eventually I figured out how to stop in the debugger and analyze the variables which clearly showed the data in jo.mExtras.mMap.mArray

I then changed the code to:

B4X:
 account = jo.RunMethod("getStringExtra", Array As Object("authAccount"))
And everything worked.

I am very puzzled why this is, since android.accounts.AccountManager.KEY_ACCOUNT_NAME is defined with constant value "authAccount". Is this because:

A) There is something wrong with my code
B) Because of a bug in b4a
C) Because there is a library missing and b4a can't evaluate the variable
D) Something else that I am not considering

If someone can answer this and explain to me what I should have done to save myself several hours of struggling it would be helpful for my education.

If the answer is C, how can I know which android.* libraries are included by default and which ones are not? There certainly were not any warning messages displayed.

Thank you for any assistance.
 

Erel

Administrator
Staff member
Licensed User
You are confusing the constant name (variable name) with the actual value. The value is "authAccount". You have passed a different string, so it didn't work.

Note that you can get the constant value with:
B4X:
Dim v As JavaObject
Dim constValue As String = v.InitializeStatic("android.accounts.AccountManager").GetField("KEY_ACCOUNT_NAME")
 

TheMightySwe

Active Member
Licensed User
Hi,

We have a java app that connects to a Cardterminal that has the name "se.iqpd.checkout.companion". We start that in B4A with the following code.

B4X:
Dim ISMP_Intent As Intent
    Dim InstalledPackages As PackageManager
    ISMP_Intent = InstalledPackages.GetApplicationIntent("se.iqpd.checkout.companion")
    ISMP_Intent.PutExtra("JobId","31271")
    ISMP_Intent.PutExtra("TransactionType","Purchase")
    ISMP_Intent.PutExtra("Amount",NumberFormat2(SubTotal_Double-SubTotal_Discount_Double,1,2,2,False))
    StartActivityForResult(ISMP_Intent)
We send the return with following JAVA-code

B4X:
Intent output = new Intent();
            output.putExtra("RESULT", RESULT_OK);
[....] ' Lots of  otherresultdata that we cant post because of confidentiallity agreement  
            getParent().setResult(Activity.RESULT_OK, output);
            finish();

But in B4A we get a error, nothing returns.

main_companion_event (B4A line: 1984)
ResultCode = Args(0)
java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
at se.iqpd.checkout.plus.main._companion_event(main.java:4069)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:159)
at anywheresoftware.b4j.object.JavaObject$1.invoke(JavaObject.java:191)
at $Proxy0.toString(Native Method)
at java.lang.String.valueOf(String.java:1649)
at anywheresoftware.b4a.debug.Debug.objectToString(Debug.java:384)
at anywheresoftware.b4a.debug.Debug.writeGlobals(Debug.java:303)
at anywheresoftware.b4a.debug.Debug.sendBPData(Debug.java:284)
at anywheresoftware.b4a.debug.Debug.access$9(Debug.java:279)
at anywheresoftware.b4a.debug.Debug$1.run(Debug.java:256)
at android.os.Handler.handleCallback(Handler.java:725)
at android.os.Handler.dispatchMessage(Handler.java:92)
at anywheresoftware.b4a.Msgbox.waitForMessage(Msgbox.java:200)
at anywheresoftware.b4a.Msgbox.debugWait(Msgbox.java:158)
at anywheresoftware.b4a.debug.Debug.wait(Debug.java:213)
at anywheresoftware.b4a.debug.Debug.reachBP(Debug.java:260)
at anywheresoftware.b4a.debug.Debug.ShouldStop(Debug.java:232)
at se.iqpd.checkout.plus.main._unitevents_batterychanged(main.java:23572)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:159)
at anywheresoftware.b4a.phone.PhoneEvents$ActionHandler$1.run(PhoneEvents.java:321)
at android.os.Handler.handleCallback(Handler.java:725)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5279)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869)
at dalvik.system.NativeStart.main(Native Method)

Why is that, anyone knows?

// TMS
 
Last edited:

TheMightySwe

Active Member
Licensed User
Hi,

StartActivityForResult code seems to call up the "Complete Action Using" - dialog after 4.30 update, anyone know why, and what to do to suppress it?

It happens in all calls to StartActivityForResult in my app.


Just an example

B4X:
Sub StartEmail

    Dim Email_Intent As Intent
    Dim InstalledPackages As PackageManager
    Email_Intent = InstalledPackages.GetApplicationIntent("com.google.android.email")

    StartActivityForResult(Email_Intent, "EMail")

End Sub
 

Erel

Administrator
Staff member
Licensed User
I'm pretty sure that it is not related to v4.30.

You can explicitly set the package name of the intent with:
B4X:
Dim jo As JavaObject = Email_Intent
jo.RunMethod("setPackage", Array("com.google.android.email"))
 

b4auser1

Well-Known Member
Licensed User
I used the code from the thread to pick a contact from Contacts intent and it worked good until Android 5.1.
On Nexus 5 with Android 5.1 it shows contacts list, but after selecting a contact nothing happened.
I checked the same apk on device with Android 4.4.2, 5.0.2 and there everything is Ok.
 

b4auser1

Well-Known Member
Licensed User
ion_Event is not called under Android 5.1
only "onActivityResult: IOnActivityResult was released" messaged is in Log.
 
Top