Android Question (SOLVED) Receive data trough intent problems.

Paolo Pini

Member
Licensed User
Longtime User
Hi,
I am trying to receive some data via intent from a character reading application via camera.

I am trying to use this code:

B4X:
' *********************************************
Sub startVideoProcessing
    Dim i As Intent

    i.Initialize("android.intent.action.ACTION_VIEW", "")
    i.SetComponent("com.clientwithopencv/.activities.MainActivity")

    Dim Settings As Map
    Settings.Initialize
    Settings.Put("location", "ITA")
    Settings.Put("servicePath", "https://api.cloud.com/start")
    Settings.Put("apiKey", "API KEY")

    Dim jsonGen As JSONGenerator
    jsonGen.Initialize(settings)
    Dim jsonSettings As String = jsonGen.ToString

    i.PutExtra("settings", jsonSettings)
    jsonGen.Initialize(carmenSettings)

    Dim ActivityForResult As StartActivityForResult
    ActivityForResult.Initialize("Ion")
    ActivityForResult.Start(i,100)
End Sub

' *********************************************
Sub Activity_Resume
    
    'Log(Activity.GetStartingIntent) =
    (Intent) Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 pkg=it.myname.package cmp=it.myname.package/.main }
    
    Dim in As Intent

    in = Activity.GetStartingIntent    '
    
    If in <> Null Then
        If in.HasExtra("Settings") Then
        End If
    End If
End Sub

' *********************************************
Private Sub Ion_OnActivityResult (RequestCode As Int, ResultCode As Int, Data As Intent, ExtraParams() As Object)
    'RequestCode=100
    'ResultCode=0
    'Data=Not initialized
    'ExtraParams=null
    
    If ResultCode = StartActivityForResult.RESULT_OK And RequestCode = 100 Then

        '*not real parameters, only for test, anyway don't reach this code*
        Dim jo As JavaObject = Data
        Dim uri As String = jo.RunMethod("getParcelableExtra", Array As Object("android.intent.extra.ringtone.PICKED_URI"))
        Log(uri)
    End If
End Sub

But the data coming back is always null, the remote application starts and recognizes the passed parameters as extra.

The data in the example is not real but I just want only to understand if the procedure I use is correct.

I've tried both 'Receiver_receive' and 'StartActivityForResult' but I think I got a little confused.

Many thanks in advance.

Paolo
 

drgottjr

Expert
Licensed User
Longtime User
are you sure the other application calls setResult() ? that's the only way to get data back from startactivityforresult().

also in your Ion_OnActivityResult (RequestCode As Int, ResultCode As Int, Data As Intent, ExtraParams() As Object sub, you should log all those returned values to see if you got anything. as it is, you only test for what you're looking for, but you don't bother to see if there were things returned that you didn't expect.
 
Upvote 0

Paolo Pini

Member
Licensed User
Longtime User
are you sure the other application calls setResult() ? that's the only way to get data back from startactivityforresult().

also in your Ion_OnActivityResult (RequestCode As Int, ResultCode As Int, Data As Intent, ExtraParams() As Object sub, you should log all those returned values to see if you got anything. as it is, you only test for what you're looking for, but you don't bother to see if there were things returned that you didn't expect.
Thanks for your reply,

I am actually trying to translate this Java code of a working application into B4A, unfortunately I am not very experienced:

Java Code from Android Studio:
// MainActivity.java ***************************************************

private void startVideoProcessing() {
        JSONObject settings = new JSONObject();

        try {
            Settings.put("location", "ITA");
            Settings.put("servicePath", "https://api.cloud.com/start");
            Settings.put("apiKey", "API KEY");
            Settings.put("save",true);
            settings.put("receiverClass","com.integration.ResultReceiver");
.......

        } catch (JSONException e) {
            e.printStackTrace();
        }

        Intent launchIntent = new Intent(Intent.ACTION_VIEW);
        launchIntent.setComponent(new ComponentName("com.clientwithopencv", "com.clientwithopencv.activities.MainActivity"));

        if (launchIntent != null) {
            launchIntent.putExtra("settings", settings.toString());

            startActivity(launchIntent);
        }
        else {
            Log.e(TAG, "intent null");
        }
    }
}
   
   
// ResultReceiver.java *******************************************

public class ResultReceiver extends BroadcastReceiver {
   
    private static final String TAG = "ResultReceiver";
    private static Map<String, Handler> handlers;

    public ResultReceiver() {
        handlers = new HashMap<>();
        handlers.put(ResultHandler.Result, new ResultHandler());
        handlers.put(EventHandler.Event, new EventHandler());
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        final PendingResult pendingResult = goAsync();
        Task asyncTask = new Task(pendingResult, intent,context);
        asyncTask.execute();
    }

    private static class Task extends AsyncTask<String, Integer, String> {
        private final PendingResult pendingResult;
        private final Intent intent;
        private final Context context;

        private Task(PendingResult pendingResult, Intent intent, Context context) {
            this.pendingResult = pendingResult;
            this.intent = intent;
            this.context = context;
        }

        @Override
        protected String doInBackground(String... strings) {
            if(intent.getAction() != null)
            {
                Handler handler = handlers.get(intent.getAction());
                String json = intent.getStringExtra(handler.getExtra());

                if(json != null)
                {
                    handler.handle(json,context);
                    return json;
                }
            }
            return "";
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            // Must call finish() so the BroadcastReceiver can be recycled.
            pendingResult.finish();
        }
    }
}

of course then there are the manifest.xlm to configure.

I don't know if that makes it any clearer.

regards.
 
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
what seems clear to me - based on what you posted - is startactivityforresult() isn't going to work. the app whose result you are expecting needs to call setResult() before exiting. your app then receives that result (or some other result).

after a rather quick glance, i would say that activity is launching another activity with an intent containg that json string. it's looking for an activity called com.clientwithopencv. if that activity is yours, you can simply set up an intent filter in your manifest and receive the intent's extras.

i don't know what the mentioned broadcastreceiver is in this case. somebody is sending the app a broadcast. i don't know who. (and there may be a problem with one activity's sending a broadcast to somebody else's activity. i forget what the latest ruling is. you can send broadcasts to another activity of yours. but that is beside the point for now. it's unclear who is sending the broadcast to the app whose java code you posted.)

my understanding was that you are developing an activity that makes a request to some 3rd party activity for some information. you made the request using startactivityforresult(). the 3rd party activity needs to answer your b4a app using setResult() with an intent containing the information you want (or perhaps an error message). period. it's unusual for unrelated apps to communicate like that. the 3rd party app would have to have documentation indicating that it could be started "for result" and that it would return the result. both startactivity() and startactivityforresult() involve intents, but they are rather different.

if the 3rd party app launches an activity and passes information to it, and if you want to be the activity that receives that information, you need to handle an intent filter in your b4a app.

have you been given the source to the 3rd party app? and are trying to determine how it passes some information that you need for a b4a app? or are you trying to convert that java code into a b4a app? i'm not following...
 
Last edited:
Upvote 1

Paolo Pini

Member
Licensed User
Longtime User
what seems clear to me - based on what you posted - is startactivityforresult() isn't going to work. the app whose result you are expecting needs to call setResult() before exiting. your app then receives that result (or some other result).

after a rather quick glance, i would say that activity is launching another activity with an intent containg that json string. it's looking for an activity called com.clientwithopencv. if that activity is yours, you can simply set up an intent filter in your manifest and receive the intent's extras.

i don't know what the mentioned broadcastreceiver is in this case. somebody is sending the app a broadcast. i don't know who. (and there may be a problem with one activity's sending a broadcast to somebody else's activity. i forget what the latest ruling is. you can send broadcasts to another activity of yours. but that is beside the point for now. it's unclear who is sending the broadcast to the app whose java code you posted.)

my understanding was that you are developing an activity that makes a request to some 3rd party activity for some information. you made the request using startactivityforresult(). the 3rd party activity needs to answer your b4a app using setResult() with an intent containing the information you want (or perhaps an error message). period. it's unusual for unrelated apps to communicate like that. the 3rd party app would have to have documentation indicating that it could be started "for result" and that it would return the result. both startactivity() and startactivityforresult() involve intents, but they are rather different.

if the 3rd party app launches an activity and passes information to it, and if you want to be the activity that receives that information, you need to handle an intent filter in your b4a app.

have you been given the source to the 3rd party app? and are trying to determine how it passes some information that you need for a b4a app? or are you trying to convert that java code into a b4a app? i'm not following...
Many thanks for your extended response,

the application I need to connect to is a famous ANPR application and it comes with extensive documentation that I don't know if I am authorized to publish.

From what I understand the manual proposes 2 modes of interfacing:

From the manual:
// Start video processing with the following code in Android:

private void startVideoProcessing() {
    JSONObject settings = new JSONObject();
    try {
        settings.put("startVideo", true);
        settings.put("mode", "InMotion");
        settings.put("receiverClass", "com.my.integration.ResultReceiver");
    } catch (JSONException e) {
        e.printStackTrace();
    }
    
    Intent launchIntent = getPackageManager().getLaunchIntentForPackage("com.ar.anprclientwithopencv");
    
    if (launchIntent != null) {
        launchIntent.putExtra("settings", settings.toString());
        startActivity(launchIntent);
    }
}

and the Manifest:

Manifest:
<receiver android:name="com.my.integration.ResultReceiver"
android:exported="true" android:enabled="true">
    <intent-filter>
        <action android:name="com.ar.clientwithopencv.EVENT" />
        <action android:name="com.ar.clientwithopencv.RESULT" />
    </intent-filter>
</receiver>

"You can pass the following modes: InMotion, InFixPosition, Parking, InHand, Motorway, Custom.
After starting the app, you have to wait for establishing connection with the cloud. The video processing will be started automatically. The app will send events as Broadcast messages to your caller activity’s receiverClass in JSON format.
You will have to create a Broadcast receiver class in your application to receive the events,Here you can find the details how to create one:"


Broadcast receiver Example:
//Broadcast receiver Example Code

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;

public class ResultReceiver extends BroadcastReceiver {
    public ResultReceiver() {}

    @Override
    public void onReceive(Context context, Intent intent) {
        final PendingResult pendingResult = goAsync();
        Task asyncTask = new Task(pendingResult, intent,context);
        asyncTask.execute();
    }

    private static class Task extends AsyncTask<String, Integer, String> {
        private final PendingResult pendingResult;
        private final Intent intent;
        private final Context context;
        
        private Task(PendingResult pendingResult, Intent intent, Context context) {
            this.pendingResult = pendingResult;
            this.intent = intent;
            this.context = context;
        }

        @Override
        protected String doInBackground(String... strings) {
            if(intent.getAction() != null)
            {
                String json = intent.getStringExtra(handler.getExtra());

                if(json != null)
                {
                    // do whatever you want with your anpr result.
                }
            }

            return "";
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            pendingResult.finish();
        }
    }
}

The other way involves creating and registering a 'plugin' but it is too long for them posted here.

I don't want to abuse your time, feel free to respond briefly. :)

Regards.
 
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
the veil is lifting slightly.
your b4a code, while essentially correct - that is, legal - has nothing to do with your famous anpr application.

keeping things brief, i would say it appears you can use startactivity to log in (not startactivityforresult) and
then receive a "result" in a custom broadcast receiver. the java code uses the term "resultreceiver", so i
can see why you would think you were dealing with startactivityforresult(). you're not.

your receiver (in b4a), then runs a job on a different thread to obtain the information you wanted. unclear for the moment exactly what that job is.
 
Upvote 0

Paolo Pini

Member
Licensed User
Longtime User
Thanks for the reply,
I will keep trying with your advice.
In the meantime, the manufacturer passed me in contact of a technician to ask for information, I hope he can help me.

Have good day.

Paolo
 
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
one last thing from me: you've set your manifest up correctly. but i don't see your receiver.
here's an example of how i would handle it with the custom filters you show:
B4X:
' in the manifest:
AddReceiverText(areceiver, <intent-filter>
<action android:name="com.ar.clientwithopencv.EVENT" />
<action android:name="com.ar.clientwithopencv.RESULT" />
</intent-filter>)

SetReceiverAttribute(areceiver, android:exported, true)  ' or false, whatever

in your receiver module:
Private Sub Receiver_Receive (FirstTime As Boolean, StartingIntent As Intent)
    If StartingIntent.Action.Contains("EVENT") Then
    ...
    else If StartingIntent.Action.Contains("RESULT") Then
        Dim data As string = StartingIntent.GetExtra("json_data")
        run_some_background_job(data)
    else
        log("unknown action: " & startingintent.action
    end if
end sub
 
Upvote 0

Paolo Pini

Member
Licensed User
Longtime User
Your latest suggestions regarding manifest, StartActivity(), and receiver class have shown me the right way to solve the problem!

I had tried something similar before but evidently something was wrong, I thought receiver_receive was not returning anything but I had not looked for the specific keys. So I listed all the keys and saw that the values I was waiting for were present. It was then sufficient to parse the values to retrieve the specific data.

Working code - Main:
i.PutExtra() 'configurations list'
    ..........

StartActivity(i)

Working code - Manifest:
............
AddReceiverText(areceiver, <intent-filter>
<action android:name="com.clientwithopencv.EVENT" />
<action android:name="com.clientwithopencv.RESULT" />
</intent-filter>)

SetReceiverAttribute(areceiver, android:exported, true)  ' or false, whatever

Working code - areceiver (receiver module):
Private Sub Receiver_Receive (FirstTime As Boolean, StartingIntent As Intent)
    Log(StartingIntent.Action)

    ' check "event" key
    If StartingIntent.HasExtra("event") Then
        Dim jsonString As String = StartingIntent.GetExtra("event")
        Log("Received JSON: " & jsonString)
        
        ' JSON parsing with JSONParser
        Dim parser As JSONParser
        parser.Initialize(jsonString)
        
        ' JSON received is an object (map)
        Dim root As Map = parser.NextObject
        
        ' Acessing to keys and values
        If root.ContainsKey("plate") Then
            Dim plate As Map = root.Get("plate")
            Dim unicodeText As String = plate.Get("unicodeText")
            Dim country As String = plate.Get("country")
            Log("Plate: " & unicodeText & ", Country: " & country)
        End If
    Else
        Log("Extra 'event' not found.")
    End If

Many thanks for your time.

Paolo
 
Upvote 0
Top