Call javascript function from Java - java

I develop an app using PhoneGap. I got a service which is in background and is coded natively (the service and the phone gap app is in the same project). Unfortunatly, I want to call a javascript function from this service. So I searched on the Web and founded something interesting : create a class extending Plugin and do some treatment in it. Then I found this :
this.ctx.sendJavascript("myJavascriptFunction");
I tested with this code, but something wrong happened :
java.lang.NullPointerException
Here is how I tested :
class c = new class();
c.execute("myFunction",null,null);
In the class c, the execute method is like this :
public PluginResult execute(String action, JSONArray args, String callbackId) {
if (action.equals("myFunction")){
Log.d(TAG,"start actions to do");
this.ctx.sendJavascript("nameOfFunctionToLaunch");
Log.d(TAG,"end actions to do");
return new PluginResult(PluginResult.Status.OK);
}
}
When the app start, I have the first
Log.d(TAG,"start actions to do");
How can I solve this problem ?

Finally I found the solution : in fact the NullPointerException was on ctx.
To fix it, I setup the Context value of my object c like this :
c.setContext(use_An_Object_Of_Type_PhonegapActivity);
To get the object, I grab it from the AppActivity in this method :
public class CloudPhoneAppActivity extends DroidGap {
private class NoScaleWebViewClient extends GapViewClient {
public NoScaleWebViewClient(DroidGap ctx) {
super(ctx);
myApp.ctx = ctx;
}
public void onScaleChanged(WebView view, float oldScale, float newScale) {
Log.d("NoScaleWebViewClient", "Scale changed: " + String.valueOf(oldScale) + " => " + String.valueOf(newScale));
}
}
/** other stuff after**/
}
So finally here is the solution :
class c = new class();
c.setContext(myApp.ctx);
c.execute("myFunction",null,null);
There is no change to do in the execute method which is describe before. But be careful of how you call the javascript function.
Erwan

You cant call object.loadUrl("javascript:function();"); from the plugin as plugin doesnt extend the WebView of Android.
To call loadUrl you would have to pass the call back to the Home class which extends DroidGap.
In the plugin you can define
Home home = null;
Looper.prepare();
home = new Home();
home.somefunc();
and in somefunc call
super.loadUrl("javascript:function();");

Related

Getting LiveStreamManager error -3 in DJI Mobile SDK when trying to stream to custom RTMP?

I'm trying to implement a app that sends live video from drone to my custom rtmp server. When I use de LiveStreamManager from DJI Mobile SDK it gives me error code -3, and the stream do not start. How can I use this API?
My app registers successfully, I can setup missions, and get telemetry from drone. But when I try to use the LiveStreamManeger it won't work no matter what. Even by implementing exactly the way it is implemented in Sample Code, it does not work. Documentation in DJI API reference seems to be missing a few methods as well.
Here is my implementation
private void setupLiveStream() {
DJISDKManager.getInstance().getLiveStreamManager().registerListener(listener);
initListener();
DJISDKManager.getInstance().getLiveStreamManager().setAudioStreamingEnabled(false);
DJISDKManager.getInstance().getLiveStreamManager().setVideoSource(LiveStreamManager.LiveStreamVideoSource.Primary);
liveURL = "rtmp://mycustomrtmp.com/drone/live_testDJI";
}
private void initListener() {
listener = new LiveStreamManager.OnLiveChangeListener() {
#Override
public void onStatusChanged(int i) {
setResultToToast("status changed : " + i);
}
};
}
private void StartStreaming(){
if (!isLiveStreamManagerOn()) {
return;
}
if (DJISDKManager.getInstance().getLiveStreamManager().isStreaming()) {
setResultToToast("already started the Stream!");
return;
}
new Thread() {
#Override
public void run() {
DJISDKManager.getInstance().getLiveStreamManager().setLiveUrl(liveURL);// + vehicleID);
int result = DJISDKManager.getInstance().getLiveStreamManager().startStream();
DJISDKManager.getInstance().getLiveStreamManager().setStartTime();
setResultToToast("LiveStream Start: " + result +
"\n isVideoStreamSpeedConfigurable:" + DJISDKManager.getInstance().getLiveStreamManager().isVideoStreamSpeedConfigurable() +
"\n isLiveAudioEnabled:" + DJISDKManager.getInstance().getLiveStreamManager().isLiveAudioEnabled());
}
}.start();
}
I always get a return code -3. When I use the sample code I can get it to work. The only diference is then I call the function isVideoStreamSpeedConfigurable(), it returns true on my code, and false on sample code. But I did not see where I can set this thing to false. How should I implement LiveStreamingManager?
Answering my own question...
I've managed to solve the issue. Apparently, to be able to use the LiveStreamManager you must first call the function VideoFeeder.getPrimaryVideoFeed() somewhere in your code or it will give error code -3.
Using the Sample Code there is a class in internal.utils.VideoFeedView that can be used to this purpose
I have first declared a private property VideoFeedView.
Then on my class constructor I call the initUI function.
private VideoFeedView primaryVideoFeed;
private void initUI() {
primaryVideoFeed.registerLiveVideo(VideoFeeder.getInstance().getPrimaryVideoFeed(),true);
startStreaming();
}
I don't know if I just was lucky, but for me, the following code solved my problem. I didn't have any need for anything more, like VideoFeedView. What is the reason for using that?
I running on a mavic 2 pro and streaming 30fps 720p to youtube.
private LiveStreamManager l;
public int live_streaming_start(String live_url){
Log.d("MavicMax", "LiveStream:live_streaming_start:" + live_url);
l = DJISDKManager.getInstance().getLiveStreamManager();
l.registerListener((x)->{Log.d("MavicMax", "LiveStream callback:" + x);});
l.setVideoSource(LiveStreamManager.LiveStreamVideoSource.Primary);
l.setVideoEncodingEnabled(true);
l.setLiveUrl(live_url);
int r = 0;
r = l.startStream();
return r;
}

Calling activity function from class

I'm using Kotlin in android studio to make an app.
In my main activity I have a function changeText() that changes the text of a textbox.
I have a class that I'm implementing called VerificationListener() that when created will do things then call onVerified(), however I cannot call changeText from onVerified, is there a way to do so? The example I'm working off of is in Java and does it.
Example I'm working off of
public void onVerified() {
mIsVerified = true;
Log.d(TAG, "Verified!");
hideProgressAndShowMessage(R.string.verified);
showCompleted();}
Above is within the class, below is just sitting in the activity
private void showCompleted() {
ImageView checkMark = (ImageView) findViewById(R.id.checkmarkImage);
checkMark.setVisibility(View.VISIBLE);
}
If by "I cannot call changeText from onVerified" you mean that you have a VerificationListener as a separate standalone class and from that class you cannot call methods on the Activity, you should either a) make the VerificationListener an inner class of the Activity, b) pass your activity into the VerificationListener when it's created (be aware of the lifecycle) c) implement some messaging solution (broadcast receiver, startActivity + onIntent(), observable, or even an event bus (not advisable). Here is a sample implementation for b:
class MyActivity : Activity(), VerificationListener.OnVerifiedCallback {
fun onVerified() {
changeText()
}
override fun onCreate(state: Bundle) {
super.onCreate(state)
VerificationListener(this).doStuff()
}
}
class VerificationListener(internal var callback: OnVerifiedCallback) {
interface OnVerifiedCallback {
fun onVerified()
}
fun whenSomethingGetsVerified() {
doThings()
callback.onVerified()
}
}
EDIT: forgot you are using Kotlin, changed to Kotlin implementation
You can't access the UI from a background thread, Kotlin or not. You have to run this on the UI thread:
runOnUiThread {
val checkMark: ImageView = findViewById(R.id.checkmarkImage)
checkMark.visibility = View.VISIBLE
}

How to call Java method (custom class) with an interface typed parameter in Nativescript

I'm creating a Nativescript plugin. It includes a custom Android Library (AAR) and I want to use it from the Typescript code. When I run a demo (in device or emulator) I get a TypeError: sender.registerListener is not a function error when calling this registerListener method, which is weird because I'm able to call other methods of the same object.
I think that it could be because I am not implementing properly the interface required as parameter. I think that I can explain it better with code:
Sender.java: the public class I will use in Typescript:
package com.berriart.android.myplugin;
public class Sender {
public static final String TAG = "Sender";
private Context _context = null;
public Sender(Context context) {
_context = context;
}
public void send(final String messagePath, final String messageToSend) {
if (Log.isLoggable(TAG, Log.INFO)) {
Log.i(TAG, "Send call: " + messagePath + " " + messageToSend);
}
}
public void registerListener(MessageListener listener) {
if (Log.isLoggable(TAG, Log.INFO)) {
Log.i(TAG, "registerListener");
}
}
// Other code here
}
MessageListener.java: the interface that must be implemented by the registerListener parameter:
package com.berriart.android.myplugin;
public interface MessageListener {
void receive(String messagePath, String messageReceived);
}
This is the Typescript (Nativescript) code of the plugin ( to ):
import * as app from "tns-core-modules/application";
export class WearMessaging {
public static send(messagePath: string, messageToSend: string) {
let sender = new com.berriart.android.myplugin.Sender(app.android.context);
sender.send(messagePath, messageToSend);
}
public static registerListener(receiveCallback: (messagePath: string, messageReceived: string) => void) {
let messageListener = new com.berriart.android.myplugin.MessageListener({
receive: receiveCallback
});
let sender = new com.berriart.android.myplugin.Sender(app.android.context);
sender.registerListener(messageListener);
}
}
If I include WearMessaging.send("/demo", "Hola"); in my nativescript application it compiles and run properly, it's call the Java method successfuly. But if I run:
WearMessaging.registerListener((messagePath: string, messageReceived: string) => {
console.log(messagePath);
console.log(messageReceived);
});
The application stops at run time and throws: TypeError: sender.registerListener is not a function refering to the myplugin.android.ts file.
I'm getting crazy trying to make this work, so, let me know if you have any clue. As I say I think that is because I'm missing something when implementing the interface and because the parameter type do not match them method is not being recognized, but maybe I'm wrong.
Here you can see some official doc:
https://docs.nativescript.org/runtimes/android/generator/extend-class-interface
Thanks in advance.
Ok, I solved it :S
It seems that the incremental build was doing something wrong. After deleting manually the build files of the demo everything went fine:
rm -rf platforms/android/build/*
rm -rf platforms/android/app/build/*
# Then build & deploy again
So, question code seems to be fine if you need to do something similar.

Accessing COM Interface with JNA

I'm trying to access the IDesktopWallpaper interface with JNA, but I've hit a wall.
I went through ShOljIdl_core.idl (from Windows 10 SDK) and discovered the GUID of the interface as follows
// IDesktopWallpaper
[
uuid(B92B56A9-8B55-4E14-9A89-0199BBB6F93B),
object
]
and the GUID of the concrete class that implements the interface
// CLSID_DesktopWallpaper
[uuid(C2CF3110-460E-4fc1-B9D0-8A1C0C9CC4BD)] coclass DesktopWallpaper { interface IDesktopWallpaper; }
So I followed the official example in the JDA github and wrote the following
#ComObject(clsId="{C2CF3110-460E-4fc1-B9D0-8A1C0C9CC4BD}")
public interface DesktopWallpaper extends IUnknown{
}
and in Main
Ole32.INSTANCE.CoInitializeEx(Pointer.NULL, Ole32.COINIT_MULTITHREADED);
try {
Factory factory = new Factory();
try {
DesktopWallpaper dw = factory.createObject(DesktopWallpaper.class);
} finally {
factory.disposeAll();
factory.getComThread().terminate(1 * 1000);
}
} finally {
Ole32.INSTANCE.CoUninitialize();
}
But the factory.createObject(DesktopWallpaper.class) throws No such interface supported(HRESULT: 80004002) (puArgErr=)and I don't know how to get around this or why it is happening.
Can any experts enlighten me on what's happening? (I am a complete noob) I will provide any further info that's necessary. Can JNA achieve what I want or do I have to use something else like Com4j?
TL;DR
After a lot of googling, I finally got it to work. The problem (at least to my current understanding) is that the current JNA helpers only work with interfaces that inherit from IDispatch. So if the interface in question such as IDesktopWallpaper does not inherit from IDispatch, then one should use vtable for function calls. I got this information from this amazing Google forum post in which the poster also provided a code sample that got me started.
Here is some working code for the SetWallpaper() function:
public class DesktopWallpaperHandler extends Unknown{
private static final GUID CLSID_DesktopWallpaper = new GUID("{C2CF3110-460E-4fc1-B9D0-8A1C0C9CC4BD}");
private static final GUID IID_IDesktopWallpaper = new GUID("{B92B56A9-8B55-4E14-9A89-0199BBB6F93B}");
private DesktopWallpaperHandler(Pointer pvInstance) {
super(pvInstance);
}
public static DesktopWallpaperHandler create(){
PointerByReference p = new PointerByReference();
WinNT.HRESULT hr = Ole32.INSTANCE.CoCreateInstance(CLSID_DesktopWallpaper, null, WTypes.CLSCTX_SERVER, IID_IDesktopWallpaper, p);
COMUtils.checkRC(hr);
DesktopWallpaperHandler handler = new DesktopWallpaperHandler(p.getValue());
return handler;
}
public void SetWallpaper(WTypes.LPWSTR monitor, WTypes.LPWSTR wallpaper){
int result = this._invokeNativeInt(3, new Object[]{this.getPointer(), monitor, wallpaper});
COMUtils.checkRC(new HRESULT(result));
}
}
And then in Main:
Ole32.INSTANCE.CoInitializeEx(Pointer.NULL, Ole32.COINIT_MULTITHREADED);
try {
WTypes.LPWSTR path = new LPWSTR("C:\\Users\\Harry\\Desktop\\1.jpg");
DesktopWallpaperHandler handler = DesktopWallpaperHandler.create();
handler.SetWallpaper(null, path);
} finally {
Ole32.INSTANCE.CoUninitialize();
}
The original motive to use IDesktopWallpaper was to access the fade in transition effect, and now that can be done by adding the following:
User32.INSTANCE.SendMessageTimeout(User32.INSTANCE.FindWindow("Progman", null), 0x52c, 0, 0, 0, 500, null);

Is there a way for push notifications in libGDX (Android and iOS projects)?

Does someone knows if it is possible to add push notifications(like Amazon Simple Notification Service) in an Android and iOS with RoboVM libGDX projects? And if it is possible, are there any good tutorials or good hints how to implement such things?
I would be happy about every hint how I can implement it.
Hi I know this is an old question but I was struggling to find a solution for this specially for iOS, but I finally found a way. If the explanation below is confusing and you prefer to see an example here is a github repo with a sample project:
Repo GitHub
I only show the code for iOS see the repo for Android.
The idea is simple you need to create a class that handles sending a notification for each platform on each of your projects (Android and iOS) and have it implement an interface called NotificationsHandler.
NotificationsHandler:
public interface NotificationsHandler {
public void showNotification(String title, String text);
}
iOS Adapter:
public class AdapteriOS implements NotificationsHandler {
public AdapteriOS () {
//Registers notifications, it will ask user if ok to receive notifications from this app, if user selects no then no notifications will be received
UIApplication.getSharedApplication().registerUserNotificationSettings(UIUserNotificationSettings.create(UIUserNotificationType.Alert, null));
UIApplication.getSharedApplication().registerUserNotificationSettings(UIUserNotificationSettings.create(UIUserNotificationType.Sound, null));
UIApplication.getSharedApplication().registerUserNotificationSettings(UIUserNotificationSettings.create(UIUserNotificationType.Badge, null));
//Removes notifications indicator in app icon, you can do this in a different way
UIApplication.getSharedApplication().setApplicationIconBadgeNumber(0);
UIApplication.getSharedApplication().cancelAllLocalNotifications();
}
#Override
public void showNotification(final String title, final String text) {
NSOperationQueue.getMainQueue().addOperation(new Runnable() {
#Override
public void run() {
NSDate date = new NSDate();
//5 seconds from now
NSDate secondsMore = date.newDateByAddingTimeInterval(5);
UILocalNotification localNotification = new UILocalNotification();
localNotification.setFireDate(secondsMore);
localNotification.setAlertBody(title);
localNotification.setAlertAction(text);
localNotification.setTimeZone(NSTimeZone.getDefaultTimeZone());
localNotification.setApplicationIconBadgeNumber(UIApplication.getSharedApplication().getApplicationIconBadgeNumber() + 1);
UIApplication.getSharedApplication().scheduleLocalNotification(localNotification);
}
});
}
}
Now by default Libgdx passes your ApplicationListener or Game object to AndroidLauncher and IOSLauncher along with a configuration object. The trick is to pass the class we created earlier to the ApplicationListener so that you can use it inside your Core project. Simple enough:
public class IOSLauncher extends IOSApplication.Delegate {
#Override
protected IOSApplication createApplication() {
IOSApplicationConfiguration config = new IOSApplicationConfiguration();
// This is your ApplicationListener or Game class
// it will be called differently depending on what you
// set up when you created the libgdx project
MainGame game = new MainGame();
// We instantiate the iOS Adapter
AdapteriOS adapter = new AdapteriOS();
// We set the handler, you must create this method in your class
game.setNotificationHandler(adapter);
return new IOSApplication(game, config);
}
public static void main(String[] argv) {
NSAutoreleasePool pool = new NSAutoreleasePool();
UIApplication.main(argv, null, IOSLauncher.class);
pool.close();
}
}
Now that you have a reference to the implementation of NotificationHandler you can simply call it through your Core project.
public class MainGame extends Game {
// This is the notificatino handler
public NotificationHandler notificationHandler;
#Override
public void create () {
// Do whatever you do when your game is created
// ...
}
#Override
public void render () {
super.render();
// This is just an example but you
// can now send notifications in your project
if(condition)
notificationHandler.showNotification("Title", "Content");
}
#Override
public void dispose() {
super.dispose();
}
// This is the method we created to set the notifications handler
public void setNotificationHandler(NotificationHandler handler) {
this.notificationHandler = handler;
}
}
One last thing
If you need to run the Desktop version then you will need to do the same thing for Desktop otherwise you might get errors, it will not do anything on the Desktop, or you can check the platform before calling the method showNotfication. You can clone the repo where I do this:
Repo GitHub
I've never done it myself. But you can use this tutorial to find out how to write Android specific code in your libGDX project. Your Android code could then receive the notifications and trigger a callback in libGDX. I hope this is at least a step in the right direction.
However I' not sure about doing the same for iOS.

Categories