Phonegap jabber plugin for android - java

For jabber support i use library Smack. Android port asmack.
I have class SmackAPI which implements MessageListener interface and contains methods to connect, login, send message. In the same time this class contains method:
#Override
public void processMessage(Chat chat, Message message) {
String from = message.getFrom();
String body = message.getBody();
System.out.println(String.format("Received message '%1$s' from %2$s", body, from));
this.recievedMessage = message;
}
It provides by MessageListener interface. All new messages processed by this method.
I write jabber plugin to connect, login, send message from phonegap.
My question: how i can in javascript listen for new messages?

I did it. I dont know however it is right way, but it works!
Cordova plugin class:
public class SmackJabber extends CordovaPlugin {
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
this.cbContext = callbackContext;
switch (action) {
case LISTEN_MESSAGE:
res = new PluginResult(PluginResult.Status.NO_RESULT);
res.setKeepCallback(true);
cordova.getThreadPool().execute(new Runnable() {
#Override
public void run() {
String callbackId = cbContext.getCallbackId();
while (true) {
String msg = getMsg();
if (msg != null) {
res = new PluginResult(PluginResult.Status.OK, msg);
res.setKeepCallback(true);
CallbackContext cb = new CallbackContext(callbackId, webView);
cb.sendPluginResult(res);
}
}
}
});
cbContext.sendPluginResult(res);
break;
And easy javascript. Just call plugin method:
window.plugins.smackJabber.listenMessage(function(result) {
alert(result)
}, function(error) {
alert(error)
}
);
Explanation:
I call plugin method "listenMessage" (calling "execute" method with action "LISTEN_MESSAGE"). There i start thread from cordova threadpool with runnable, in runnable i got recursive function which check message. But before start runnable i have to take callbackId of method who call method execute. Also, for exit from method, i create new PluginResult with status "NO_RESULT" and set it option "keepCallback" to true - it means, that method calls in javascript awaiting one more callback result from me. When i got message, i create new callbackcontext based on callbackid and my webview, do setKeepCallback to true for futher possible responses for pluginresult, putting in pluginresult my message with status "OK" and sending it to callbackcontext. That's all.

Related

Issues with converting java to c#

I'm attempting to convert the code located at How to use signalr in android Service from java to c# and have been making some progress. I'm now stuck at the final method. The java code is:
private void startSignalR() {
Platform.loadPlatformComponent(new AndroidPlatformComponent());
mInstance.setmHubConnection();
mInstance.setHubProxy();
ClientTransport clientTransport = new ServerSentEventsTransport(mInstance.mHubConnection.getLogger());
SignalRFuture<Void> signalRFuture = mInstance.mHubConnection.start(clientTransport);
try {
signalRFuture.get();
} catch (InterruptedException | ExecutionException e) {
Log.e("SimpleSignalR", e.toString());
return;
}
mInstance.sendMessage(MainActivity.unm,"Hello All!");
String CLIENT_METHOD_BROADAST_MESSAGE = "recievedMessage";
mInstance.mHubProxy.on(CLIENT_METHOD_BROADAST_MESSAGE,
new SubscriptionHandler2<String,LoginInfo>() {
#Override
public void run(final String msg,final LoginInfo loginInfo) {
final String finalMsg = loginInfo.FullName + " says " + loginInfo.Password;
Intent intent = new Intent();
intent.setAction(MY_ACTION);
intent.putExtra("DATAPASSED", finalMsg);
sendBroadcast(intent);
}
}
, String.class,LoginInfo.class);
}
Using a java to c# converter, this translated to:
private void startSignalR()
{
Platform.loadPlatformComponent(new AndroidPlatformComponent());
mInstance.setmHubConnection();
mInstance.setHubProxy();
ClientTransport clientTransport = new ServerSentEventsTransport(mInstance.mHubConnection.Logger);
SignalRFuture<Void> signalRFuture = mInstance.mHubConnection.Start(clientTransport);
try
{
signalRFuture.get();
}
catch (Exception e) when (e is InterruptedException || e is ExecutionException)
{
// Log.e("SimpleSignalR", e.ToString());
return;
}
mInstance.sendMessage("", "Hello All!");
string CLIENT_METHOD_BROADAST_MESSAGE = "recievedMessage";
//String CLIENT_METHOD_BROADAST_MESSAGE = "messageReceived";
mInstance.mHubProxy.on(CLIENT_METHOD_BROADAST_MESSAGE, new SubscriptionHandler2AnonymousInnerClass(this)
, typeof(string), typeof(LoginInfo));
}
private class SubscriptionHandler2AnonymousInnerClass : SubscriptionHandler2<string, LoginInfo>
{
private readonly SignalRSrv outerInstance;
public SubscriptionHandler2AnonymousInnerClass(SignalRSrv outerInstance)
{
this.outerInstance = outerInstance;
}
//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
//ORIGINAL LINE: #Override public void run(final String msg,final LoginInfo loginInfo)
public override void run(string msg, LoginInfo loginInfo)
{
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final String finalMsg = loginInfo.FullName + " says " + loginInfo.Password;
string finalMsg = loginInfo.FullName + " says " + loginInfo.Password;
Intent intent = new Intent();
intent.Action = MY_ACTION;
intent.PutExtra("DATAPASSED", finalMsg);
sendBroadcast(intent);
}
}
This, of course, generated several errors in Visual Studio 2017.
First, the line Platform.loadPlatformComponent(new AndroidPlatformComponent()); generated the error Platform is inaccessible due to its protection level. Platform in Xamarin for Visual Studio 2017 is indeed protected and is a internal class in System and I cannot change this, so I'm at a loss as how to proceed with it. The same line generates the error The type or namespace name 'AndroidPlatformComponent' could not be found, these errors a numerous and not unexpected I just can't find an equivalent to AndroidPlatformComponent in Visual Studio 2017 so I'm at a loss as how to solve this one.
Next, on this line ClientTransport clientTransport = new ServerSentEventsTransport(mInstance.mHubConnection.Logger); generates the error The type or namespace name 'ClientTransport' could not be found, I was also unable to find an equivalent to this and again I'm at a loss as to proceed. Also on this line, .Logger is not defined for the hub connection, apparently it's .getLogger() in java, I was unable to find an equivalent for this one as well.
Next the line SignalRFuture<Void> signalRFuture = mInstance.mHubConnection.Start(clientTransport);' generates the error 1The type or namespace name 'SignalRFuture<>' could not be found, this seemes to be specific to SignalR, again, I am unable to find an equivalent.
The next one has me totally stumped, the line private class SubscriptionHandler2AnonymousInnerClass : SubscriptionHandler2<string, LoginInfo> generates the error The type or namespace name 'SubscriptionHandler2<,>' could not be found. I've looked everywhere online and read up on AnonymousInnerClass, but it was not help with this.
I'm hoping that the users here are more familiar with SignalR and the differences between c# functionality and java functionality. I'm not at all familiar with java nor am I familiar with SignalR and foreground services.
As it turns out, the last method in the java code I was converting was wiring up an event to pass the message received from the hub to the activity. In c# / Visual Studio (2017), that's done very differently which is why I didn't understand/recognize what was going on. So I created a handler in C# and execute a popup message for the message. This in itself may pose problems, but at least I know what's going on. This is the code I wrote to start SignalR from within the service and WireUp the handler:
private void startSignalR()
{
// Company, Department, and section are private variables
// their values are pulled from the intent bundle
// in the OnBind method, that code is:
// Bundle bundlee = intent.GetBundleExtra("TheBundle");
// MyUser = bundlee.GetParcelable("MyUser") as User;
// This information is put into the bundle when the user is logged in.
// I then pass that information to the SignalR client
// when I set the hub connection and placed on the querystring to the hub.
mInstance.setmHubConnection(username, firstname,lastname,company,department,section);
mInstance.setHubProxy();
try
{
// Connect the client to the hup
mInstance.mHubConnection.Start();
// Set the event handler
mInstance.WireUp();
}
catch (System.Exception e) when (e is InterruptedException || e is ExecutionException)
{
ShowMessage("Error: + e.Message)
}
}
This is the WireUp code, this is a method in the client code:
public void WireUp()
{
// set the event handler
mHubProxy.On("broadcastMessage", (string platform, string message) =>
{
if (OnMessageReceived != null)
OnMessageReceived(this, string.Format("{0}: {1}", platform, message));
});
}
As I had anticipated, the popup message won't appear when the app is in the background, so I'm researching a workaround

Creating a basic custom Cordova Plugin

I am quite new in cordova and android native code
I had created my own plugin by using plugman.
plugman create --name myCustomPlugin --plugin_id myCustomPlugin --plugin_version 1.0
plugman had generated all the needed files for me to get started.
js file www/myCustomPlugin.js
var exec = require('cordova/exec');
exports.coolMethod = function(arg0, success, error) {
exec(success, error, "myCustomPlugin", "coolMethod", [arg0]);
};
java file src/android/myCustomPlugin.java, method execute
#Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
if (action.equals("coolMethod")) {
String message = args.getString(0);
this.coolMethod(message, callbackContext);
return true;
}
return false;
}
private void coolMethod(String message, CallbackContext callbackContext) {
if (message != null && message.length() > 0) {
callbackContext.success(message);
} else {
callbackContext.error("Expected one non-empty string argument.");
}
}
The question is:
On the cordova project js file. How do I call myCustomPlugin? and how do I know that it is working?
I am using angular in my cordova project, let say my controller is like this:
.controller('mainCtrl', function($scope){
// how to call myCustomPlugin here?
});
My motive is just to learn how to call and how it work only, maybe after click it will do a native alert or open native view or something.
Thanks in advance!
You can do:
www/myCustomPlugin.js
var MyCustomPlugin {
coolMethod : function(arg0, success, error) {
exec(success, error, "myCustomPlugin", "coolMethod", [arg0]);
}
}
module.exports = MyCustomPlugin
And in your js client just:
MyCustomPlugin.coolMethod("Arg1", function(){}, function(){});
Cordova will inject JavaScript file for you.
Hope it helps.

Android bluetooth get response with BluetoothGatt

I'm new in connection bluetooth. I use code of
https://github.com/Fakher-Hakim/android-BluetoothLeGatt. When I try to
obtain the information nothing happened.
public String response() {
if (mConnected) {
mBluetoothLeService.readCharacteristic(characteristica);
byte response[] = characteristica.getValue();
String respuesta = ReadBytes(response);
mBluetoothLeService.disconnect();
return respuesta;
} else {
return null;
}
}
I execute after function
private final ExpandableListView.OnChildClickListener servicesListClickListner
How I can obtain information of the Bluetoothdevice?
The BLE operations are asynchronous, you have to deal with the result in the callback.
In your example: https://github.com/Fakher-Hakim/android-BluetoothLeGatt/blob/master/Application/src/main/java/com/example/android/bluetoothlegatt/BluetoothLeService.java
Check the onCharacteristicRead method.

onStateChange is called multiple times in atmosphere framework

I'm using the atmosphere framework in my application.
https://github.com/Atmosphere/atmosphere
I've extended the AbstractReflectorAtmosphereHandler class and implemented the
-onRequest
-destroy
-onstatechanged
methods.
When a client wants to send a message to the server:
subSocket.push(jQuery.stringifyJSON({ data: "blahblah", source:"client" }));
The onRequest function is called; however the message
Object message = atmosphereResource.getAtmosphereResourceEvent().getMessage();
Is empty.
Than I tried using the onstatechanged which is called every time
(1) The remote connection gets closed, either by a browser or a proxy
(2) The remote connection reach its maximum idle time (AtmosphereResource.suspend))
(3) Everytime a broadcast operation is executed (broadcaster.broadcast)
However even after filtering out 1 and 2
public void onStateChange(AtmosphereResourceEvent event)
throws IOException {
if (source.equals("client") && !event.isResumedOnTimeout() && !event.isResuming()){
System.out.println("message form client");
System.out.println(message.toString());
} else {
//normal onstatechanged code from AbstractReflectorAtmosphereHandler
}
However the message is printed randomly between 2 and 4 times. It should only be called once.
So my question is: Can I acces the message inside the onRequest method or why is the onStateChange called so many times.
edit: from the answer given by jF I've been able to acces the message inside the onRequest function. (I'm not sure however if that is what he actually meant).
public void onRequest(AtmosphereResource resource) throws IOException {
//Object message = resource.getAtmosphereResourceEvent().getMessage(); //is empty why?
//leave connection open
resource.suspend();
BufferedReader reader = resource.getRequest().getReader();
Object message = reader.readLine();
if (message !=null){
System.out.println("**onRequest: "+message.toString());
}
}
You need to read the request's body by doing, in your onStateChange:
atmosphereResource.getRequest().getReader (or getInputStream).
Maybe this helpes other people:
public void onRequest(AtmosphereResource resource) throws IOException {
//Object message = resource.getAtmosphereResourceEvent().getMessage(); //is empty why?
//leave connection open
resource.suspend();
BufferedReader reader = resource.getRequest().getReader();
Object message = reader.readLine();
if (message !=null){
Object obj = JSONValue.parse(message.toString());
JSONObject jsonObject = (JSONObject) obj;
Object source = jsonObject.get("source");
System.out.println("**onRequest: "+message.toString());
ArrayList frame = new ArrayList();
frame.add(jsonObject.get("type"));
frame.add(jsonObject.get("data"));
writeQueue.add(frame);
}
}

How to upgrade javascript to utilize phonegap 2.3 custom plugin?

I have built a custom plugin called TCPIPCommPlugin that uses Phonegap/Cordova 1.6.1. Everything is all great and the callbacks/plugin results work just fine. However I need to get it upgraded to Cordova 2.3. The reason is that we are now starting dev on Win8 as well as iOS/Android.
That aside, I have the following code in javascript.
var TCPComm = function() {
};
TCPComm.prototype.Open = function(Cmd,successCallback, failureCallback) {
return PhoneGap.exec( successCallback, //Success callback from the plugin
failureCallback, //Error callback from the plugin
'TCPIPCommPlugin', //Tell PhoneGap to run "DirectoryListingPlugin" Plugin
'Open', //Tell plugin, which action we want to perform
[Cmd]); //Passing list of args to the plugin
};
This code continues with about 10-12 different function calls to the plugin, which is then concluded with...
PhoneGap.addConstructor(function() {
PhoneGap.addPlugin("TCPComm", new TCPComm());
});
Within the javascript itself, the actual function call looks like this.
window.plugins.TCPComm.Open(g_IpAddr, OpenOK,OpenFail);
Additionally here is what the JAVA Plugin looks like.
#Override
public PluginResult execute(String action, JSONArray data, String callbackId) {
PluginResult result = null;
try {
Actions currentAction = Actions.valueOf(action.toUpperCase());
JSONObject Resp = new JSONObject();
String RespStr;
switch(currentAction){
case OPEN:
{
//do work
}catch (JSONException jsonEx) {
System.out.println(jsonEx.toString());
result = new PluginResult(Status.JSON_EXCEPTION);
}
return result;}
This works great with Cordova 1.6.1. However not so much with Cordova 2.x.x. Now with all this said and done, I have perused the web trying to find a way to convert the JAVA. I came up with the following.
public boolean execute(String action, JSONArray data, CallbackContext callbackContext) {
PluginResult result = null;
try {
Actions currentAction = Actions.valueOf(action.toUpperCase());
JSONObject Resp = new JSONObject();
String RespStr;
switch(currentAction){
case OPEN:
{
//do work
}catch (JSONException jsonEx) {
System.out.println(jsonEx.toString());
result = new PluginResult(Status.JSON_EXCEPTION);
}
return true;
}
This seems to match the updated code. What I have not been able to find is a way to update the JAVASCRIPT calls to make this plugin work with the updated CORDOVA.
Any help/points in the right direction would be much appreciated!
I have used the following documentation with no success.
http://docs.phonegap.com/en/2.3.0/guide_plugin-development_index.md.html#Plugin%20Development%20Guide
https://github.com/apache/cordova-android/tree/master/framework/src/org/apache/cordova
UPDATE
Thanks for the response Simon. In the interim I had replaced my javascript with the following. Do I need to revert it back to what it was prior?
cordova.define("cordova/plugin/TCPIPCommPlugin", function(require, exports, module){
var exec = require('cordova/exec');
var TCPComm = function() {};
// var TCPCommError = function(code, message) {
// this.code = code || null;
// this.message = message || '';
// };
TCPComm.prototype.Open = function(success,fail) {
return cordova.exec( successCallback, //Success callback from the plugin
failureCallback, //Error callback from the plugin
'TCPIPCommPlugin', //Tell PhoneGap to run "DirectoryListingPlugin" Plugin
'Open', //Tell plugin, which action we want to perform
[Cmd]);
};
var TCPIPCommPlugin = new TCPComm();
module.exports = TCPIPCommPlugin;
});
UPDATE #2 - Fixed some errors
I went back to the old javascript and replaced it all so it looks like this now..
var TCPComm = function() {};
TCPComm.prototype.Open = function(Cmd, successCallback,failureCallback) {
return cordova.exec( successCallback, //Success callback from the plugin
failureCallback, //Error callback from the plugin
'TCPIPCommPlugin', //Tell PhoneGap to run "DirectoryListingPlugin" Plugin
'Open', //Tell plugin, which action we want to perform
[Cmd]);
};
I also replaced the constructor with..
if(!window.plugins) {
window.plugins = {};
}
if (!window.plugins.TCPComm) {
window.plugins.TCPComm = new TCPComm();
}
Now when I run it in Chrome, (UI debugging), I can see the plugin built with all the proper functions inside the function.
The Java was fine, I forgot to include the return on the forum code. Whoops.
Now I tried calling the function like I always have and I get a Object # has no method 'exec' at the first JAVASCRIPT call of either Close/Open..
window.plugins.TCPComm.Close("", Dummy, Dummy);
window.plugins.TCPComm.Open(g_IpAddr, OpenOK,OpenFail);
I have breakpoints set in the Java on the execute to let me know when the plugin has called successfully to the Java and still no luck.
Any other thoughts? Thanks again for your insight.
Replace PhoneGap.exec with the following code:
var TCPComm = function() {
};
TCPComm.prototype.Open = function(Cmd,successCallback, failureCallback) {
return cordova.exec( successCallback, //Success callback from the plugin
failureCallback, //Error callback from the plugin
'TCPIPCommPlugin', //Tell PhoneGap to run "DirectoryListingPlugin" Plugin
'Open', //Tell plugin, which action we want to perform
[Cmd]); //Passing list of args to the plugin
};
The add constructor method is deprecated so do:
if(!window.plugins) {
window.plugins = {};
}
if (!window.plugins.videoPlayer) {
window.plugins.TCPComm = new TCPComm();
}
For your Java code you are most of the way there but you need to return the result:
public boolean execute(String action, JSONArray data, CallbackContext callbackContext) {
PluginResult result = null;
try {
Actions currentAction = Actions.valueOf(action.toUpperCase());
JSONObject Resp = new JSONObject();
String RespStr;
switch(currentAction){
case OPEN:
//do work
this.callbackContext.sendPluginResult(
new PluginResult(PluginResult.Status.OK, results));
} catch (JSONException jsonEx) {
System.out.println(jsonEx.toString());
result = new PluginResult(Status.JSON_EXCEPTION);
}
return true;
}
That should get you upgraded.

Categories