Null Pointeer Exception in a Custom Cordova Plugin - java

Context : I'm creating a custom Cordova plugin that uses a scanner native functions such as scan, print, display scanned document (the scanner have a screen on it just like a tablet).
The code by itself is working fine (the scanner is running on an Android OS), things gets tricky when i want to "convert" the code to a Cordova Plugin (i have already done that for another project and it worked perfectly).
Problem : In order to use the method that starts the scan i have to make sure that the said method in ScanService.java (= it's an interface that has an Abstract Class Stub extends android.os.Binder implements my.package.name.ScanService ) is binded and can be used via an intent like this :
Context ctx = this.cordova.getActivity().getApplicationContext();
public boolean BindServiceContext(Context ctx)
{
Intent myintent = new Intent("name.of.package.ScanService");
myintent.setPackage("name.of.package");
ctx.startService(myintent);
return ctx.bindService(myintent, ScanServConn, ctx.BIND_AUTO_CREATE);
}
The ScanServConn variable :
public ScanService mService;
public ServiceConnection ScanServConn = new ServiceConnection()
{
#Override
public void onServiceConnected(ComponentName name, IBinder service)
{
mService = ScanService.Stub.asInterface(service);
try
{
mService.initService(mScanCK);
mService.registerSystemCallBack(mSysCK);
mService.mountScannerDevice();
}
catch (RemoteException e)
{
e.printStackTrace();
}
}
#Override
public void onServiceDisconnected(ComponentName name)
{
try
{
if (mService != null)
{
mService.unmountScannerDevice();
mService.unregisterSystemCallBack(mSysCK);
mService.unregisterCallBack(mScanCK);
mService.uninitService();
}
}
catch (RemoteException e)
{
e.printStackTrace();
}
mService = null;
mSysCK = null;
mScanCK = null;
}
};
At this point, the BindingServiceContext method returns false.
private void StartScan(String strScanProfilePath) //
{
try
{
int iRet = mService.getScannerDeviceStatus();
if ( iRet == Defination.PAPER_STATUS_ON_TRAY)
{
int ret = mService.setScanProfile(strScanProfilePath);
if (ret == Defination.ERROR_SUCCESS)
{
// Start scanning.
mService.scanStart();
}
}
}
catch (RemoteException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
The precise error i have when adding the plugin into a cordova project and testing it :
Attempt to invoke interface method 'int my.package.name.ScanService.getScannerDeviceStatus()' on a null object reference.
In my plugin.xml i have added this line, so in the AndroidManifest.xml of the project my service is declared :
<config-file target="AndroidManifest.xml" parent="/manifest/application">
<service android:name="my.package.name.ScanService" />
</config-file>

Related

Interface null pointer exception in Network Callback onAvailable method

Below is my code, i tried to implement interface to intercept respond from Connectivity Manager Network Callback, but Android Studio is throwing error at this interface internetListener.onInternetStatusUpdate(true) in onAvailable method.
I also implemented this interface at my main activity. I follow a few example too but failed. Is it that onAvailable method, my interface is not reachable?
public class CheckInternetAsyncTask extends ConnectivityManager.NetworkCallback
{
private static final String TAG = "CheckInternetAsyncTask";
private Context context;
public InternetListener internetListener;
private ConnectivityManager connectivityManager;
private Network network;
private NetworkCapabilities networkCapabilities;
public interface InternetListener{
void onInternetStatusUpdate(boolean hasInternet);
}
public CheckInternetAsyncTask(Context _context) {
this.context = _context;
this.connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
connectivityManager.registerDefaultNetworkCallback(this);
}
try {
new SendInternetRequest().execute().get(5, TimeUnit.SECONDS);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
public void TestInternetRequest(){
try {
new SendInternetRequest().execute().get(5, TimeUnit.SECONDS);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
#Override
public void onAvailable(Network network) {
super.onAvailable(network);
this.network = network;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
connectivityManager.bindProcessToNetwork(network);
this.network = connectivityManager.getActiveNetwork();
}else{
ConnectivityManager.setProcessDefaultNetwork(network);
}
this.networkCapabilities = connectivityManager.getNetworkCapabilities(network);
if(networkCapabilities != null && networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)){
internetListener.onInternetStatusUpdate(true);
}else{
try {
new SendInternetRequest().execute().get(5, TimeUnit.SECONDS);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
class SendInternetRequest extends AsyncTask<Void,Void, Void>{
private static final String TAG = "SendInternetRequest";
CheckInternetAsyncTask.InternetListener internetListener;
#Override
protected Void doInBackground(Void... voids) {
try {
Socket sock = new Socket();
sock.connect(new InetSocketAddress("8.8.8.8", 53), 1500);
sock.close();
internetListener.onInternetStatusUpdate(true);
} catch (IOException e) {
internetListener.onInternetStatusUpdate(false);
}
return null;
}
}
Stacktrace
2019-09-25 10:08:02.566 29555-29578/com.kioskactionandnotification E/AndroidRuntime: FATAL EXCEPTION: ConnectivityThread
Process: com.kioskactionandnotification, PID: 29555
java.lang.NullPointerException: Attempt to invoke interface method 'void com.kioskactionandnotification.Model.Helper.CheckInternetAsyncTask$InternetListener.onInternetStatusUpdate(boolean)' on a null object reference
at com.kioskactionandnotification.Model.Helper.CheckInternetAsyncTask.onAvailable(CheckInternetAsyncTask.java:85)
at android.net.ConnectivityManager$NetworkCallback.onAvailable(ConnectivityManager.java:2770)
at android.net.ConnectivityManager$CallbackHandler.handleMessage(ConnectivityManager.java:2969)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.os.HandlerThread.run(HandlerThread.java:65)
MainActivity.java
I implemented the interface
#Override
public void onInternetStatusUpdate(boolean hasInternet) {
this.hasInternet = hasInternet;
Log.d(TAG, "onInternetStatusUpdate: hasInternet : "+hasInternet);
}
That's all i have.
It seems like you're trying to access an uninitialized object of type internetListener.
You need to initialize it:
internetListener = new InternetListener();
Or check if it was already initialized:
if (internetListener != null) {
internetListener.onInternetStatusUpdate(true);
}
NOTE
Any abstract class you are using should be extended by a subclass that provides implementations for any of the abstract data/methods used from the abstract class.
Abstract class in Java
In my constructor below, i added a listener. Its basically my interface.
public CheckInternetAsyncTask(Context _context, InternetListener internetListener) {
this.context = _context;
this.internetListener = internetListener;
}
Then in my main activity where i am implementing this interfaces, I had to push "this" keyword, to my listener.
I am still studying the difference between context and "this" keyword and how they work on interfaces
new CheckInternetAsyncTask(context, this);
Reference: How to create our own Listener interface in android?

J2ME media player doesn't play

public class Midlet extends MIDlet implements CommandListener{
Player p;
public void startApp() {
Display.getDisplay(this).setCurrent(new SongsList(this));
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
notifyDestroyed();
}
public void commandAction(Command cmnd, Displayable dsplbl) {
if (cmnd.getLabel().equals("Exit"))
{
destroyApp(true);
}
else
{
try {
//InputStream is = getClass().getResourceAsStream("/res/getlucky.mpeg");
//p = Manager.createPlayer(is, "audio/mpeg");
p = Manager.createPlayer("http://puu.sh/6n9jC.mp3");
p.realize();
p.start();
} catch (IOException ex) {
ex.printStackTrace();
} catch (MediaException ex) {
ex.printStackTrace();
}
}
}
}
this is the songslist class :
public class SongsList extends List{
public SongsList(Midlet midlet)
{
super("Songs", List.IMPLICIT);
append("get lucky", null);
addCommand(new Command("Exit", Command.EXIT, 0));
addCommand(new Command("Select", Command.OK, 0));
setCommandListener(midlet);
}
}
tried use via file stored in project (its under src/res):
inputStream = getClass().getResourceAsStream("res/getlucky.mpg");
audioPlayer = Manager.createPlayer(inputStream, "audio/mpg");
as well as from HTTP:
//audioPlayer = Manager.createPlayer("http://puu.sh/6n9jC.mp3");
Nothing works, what am I doing wrong?
EDIT:
I've tried to delete my application and just copy paste it to a new project and it worked for some reason.. now I encounter new problems:
1) I try to play a song - this is the link http://puu.sh/6n9jC.mp3
its not playing so I guess there's a limited file size for what can be played can someone tell me what is this limit ?
2) Im trying to record the audio with RecordPlayer but its always null
public AudioAnalyzer()
{
try {
thread = new Thread(this);
recordFinished = false;
//inputStream = getClass().getResourceAsStream("res/getlucky.mpg");
//audioPlayer = Manager.createPlayer(inputStream, "audio/mpg");
audioPlayer = Manager.createPlayer("http://puu.sh/35YTG.mp3");
//audioPlayer = Manager.createPlayer("http://puu.sh/6n9jC.mp3");
audioPlayer.realize();
System.out.println(System.getProperty("supports.audio.capture"));
recordControl = (RecordControl)audioPlayer.getControl("RecordControl");
recordOutput = new ByteArrayOutputStream();
recordControl.setRecordStream(recordOutput);
recordControl.startRecord();
audioPlayer.start();
//thread.start();
} catch (MediaException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
}
I even tried to print if the system is supporting audio capture and the result were true but I get NullPointException at this line :
recordOutput = new ByteArrayOutputStream();
although I tried to get the recordcontrol from the player it is still null :
recordControl = (RecordControl)audioPlayer.getControl("RecordControl");
I think I read that it'll always give NullPointerException unless you run it on a real device and not an emulator is that true ? can someone verify it ? and if so what can I do if I don't own a device currently any other way to use recordcontrol feature in emulator (assuming recordcontrol isn't working on emulators).
File size is 8MB (maybe play on your phone), try to this code
public void initMedia(final String aFileUrl) {
if (m_player == null) {
try {
m_player = Manager.createPlayer(aFileUrl);
m_player.addPlayerListener(this);
m_player.realize();
m_player.prefetch();
m_volumeControl = (VolumeControl) m_player.getControl("VolumeControl");
} catch (IOException ex) {
} catch (Exception ex) {
} catch (OutOfMemoryError e) {
}
}
}
In your code, i guess you miss "m_player.prefetch()", try this. And print your Exception message...
This code in general for file, resourcce, http...
public void initMedia(final String aProtocol, final String aMediaSource) {
if (m_player == null) {
try {
if (aMediaSource.indexOf("file://") == 0) {
InputStream iRecordStream = Connector.openInputStream(aMediaSource);
m_player = Manager.createPlayer(iRecordStream, "audio/amr");
} else {
m_player = Manager.createPlayer(aProtocol);
}
m_player.addPlayerListener(this);
m_player.realize();
boolean isPrefetch = true;
try {
m_player.prefetch();
} catch (Exception ex) {
isPrefetch = false;
}
// trick to pass prefetch error
if (!isPrefetch) {
if (m_player != null) {
m_player.close();
m_player = null;
}
if (aMediaSource.indexOf("file://") == 0) {
InputStream iRecordStream = Connector.openInputStream(aMediaSource);
m_player = Manager.createPlayer(iRecordStream, "audio/amr");
} else {
m_player = Manager.createPlayer(aProtocol);
}
m_player.addPlayerListener(this);
m_player.realize();
m_player.prefetch();
}
m_volumeControl = (VolumeControl) m_player.getControl("VolumeControl");
} catch (IOException ex) {
} catch (Exception ex) {
} catch (OutOfMemoryError e) {
}
}
}
In general when it comes to J2ME development, you should always test your app on multiple real devices.
Emulators can't be trusted.
Also, J2ME is very fragmented, and various devices have various bugs and behaves differently with the same code. This will affect any app on many areas. One area being audio playback.
For example, some devices requires that you use the realize() and prefetch() methods, while other devices will crash if you use prefetch(). The only possible solution (if you wish to support as many devices as possible) is to use multiple try/catch blocks.
See this link for a detailed explanation and other tips'n'tricks on audio playback with MIDP2.0
http://indiegamemusic.com/help.php?id=1

Java - Signals events Pattern

I been inspired by Signals events pattern in AS3, that replace the native events of flash. And it's work much better, both in performance and readability.
So I am trying to implement it in Java.
the main Idea of this pattern is that you are working with objects instead of types, saving by this the time to find the "Dispatcher" class to handle your event dispatch.(Dispatching event is sending event to all the listeners)
So lets jump into the code:
In this sample I will create AlarmManager and handle his alarm event.
First we need to create our Interface for this event
public interface IAlarmEvent {
void alarmEventHandler(String alert);
}
Now the event itself:
public class AlarmEvent extends Signal<IAlarmEvent> implements IAlarmEvent {
public void alarmEventHandler(String alert) {
dispatch("alarmEventHandler", alert);
}
}
And here is the AlarmManger:
public class AlarmManager {
public final AlarmEvent alarmEvent = new AlarmEvent();
public void init(){
// Dispatching the event
alarmEvent.alarmEventHandler("Wake up");
}
}
Here is an Activity who is listening for this event:
public class MainActivity extends Activity implements IAlarmEvent{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AlarmManager alarmManager = new AlarmManager();
alarmManager.alarmEvent.addListener(this);
alarmManager.init();
}
public void alarmEventHandler(String alert) {
Log.d("MyLog", "Event : " + alert);
}
}
And here is how I wrote the Signal class
public abstract class Signal<T> {
private LinkedHashMap<T, T> listeners = new LinkedHashMap<T, T>();
protected void dispatch(String methodName, Object...arguments){
Set<T> keySet = listeners.keySet();
if(keySet.size() == 0){
return;
}
Iterator<T> iterator = keySet.iterator();
Method method = null;
do{
T listener = iterator.next();
if(method == null){
try {
Class<?>[] classes = new Class<?>[arguments.length];
for(int i = 0; i < arguments.length; i++){
classes[i] = arguments[i].getClass();
}
method = listener.getClass().getMethod(methodName, classes);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
try {
method.invoke(listener, arguments);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}while(iterator.hasNext());
}
public void addListener(T listener) {
listeners.put(listener, listener);
}
public void removeListener(T listener) {
listeners.remove(listener);
}
}
This pattern is:
fast - no need to search for type and trigger the eventDispatcher, it's done immediately.
have great readability - Just by looking at the class you know exactly what events he dispatch, and how each event looks like.
However it's not working well. If I am using primitives for my interface, the Signal fails to find the Method and invoke it. And I don't like the idea passing the Method name to the signal. Any Ideas how to improve this? And what do you think about this pattern?
Seems like this pattern is already implemented in these classes
java.util.Observable
java.util.Observer

handle toolbar actions on eclipse plugin

i'm writing a plugin for eclipse. my problem is: i wrote a class MyEditor extends MultiPageEditorPart to edit my files, and a class MyContributor extends MultiPageEditorActionBarContributor to add actions to the toolbar.
so far i can see the buttons on the toolbar added by MyContributore.contributeToolbar() but they are always deactivated, even when i select some editparts in my editor.
i can get it working with "normal" editors (i.e. extending EditorPart), but i don't know why it doesn't work for multi page editor.
besides the usual implemented methods, here are the init and createPage overridden method I wrote in MyEditor (named XALDesignerMultiPage, in the snippet below), as required by the comment:
#Override
public void init(IEditorSite site, IEditorInput input) throws PartInitException
{
super.init(site, input);
this.setPartName(input.getName());
XALDesignerMultiPage.site = this.getSite();
//this.model = new Program();
try {
this.model = XALInput.parseXALFile((FileEditorInput)input);
} catch (Exception e) {
// ... do something
}
}
...
#Override
protected void createPages() {
try
{
for (Automaton currAut : this.model.getAutomata())
{
createGraphicalEditor(currAut);
}
}
catch (Exception e)
{
// ... do something
}
// ... other stuff
}
...
private void createGraphicalEditor(Automaton currAut)
{
try
{
IEditorPart editor = new XALDesigner(); // XALDesigner is an instance of single page editor
int index = this.getPageCount();
addPage(index, editor, new AutomatonInput(((FileEditorInput)getEditorInput()).getFile(), currAut)); // AutomatonInput wraps the single page input
String autName = AutomatonInput.defaultName;
if (currAut != null)
{
autName = currAut.getName();
}
setPageText(index, autName);
}
catch (PartInitException e)
{
// ... do something
}
catch (Throwable t)
{
// ... do something
}
}
thanks in advance

How to get an android service return message from a phonegap plugin

I am trying to make a plugin for Phonegap (Android) that allows my javascript to send and receive messages to / from a service.
My exact problem is, that because the messages return asynchronous, I cannot send the PluginResult to the execute function of the plugin.
This is the plugin code:
public class ServiceClient_plugin extends Plugin {
Messenger messenger_service=null;
boolean connected_to_service=false;
final Messenger messenger_receive = new Messenger(new IncomingHandler());
#Override
public PluginResult execute(String action, JSONArray data, String callbackId) {
PluginResult result = null;
try {
if (action.toUpperCase().equals("CONNECT")) {
result = ConnectService();
} else if (action.toUpperCase().equals("DISCONNECT")) {
result = DisconnectService();
} else if (action.toUpperCase().equals("IS_CONNECTED")) {
result = new PluginResult(Status.OK,connected_to_service);
} else if (action.toUpperCase().equals("COMMAND")) {
sendMSG (data.getString(0));
result = new PluginResult(Status.OK);
} else {
result = new PluginResult(Status.INVALID_ACTION);
}
} catch(JSONException e) {
result= new PluginResult(PluginResult.Status.JSON_EXCEPTION);
}
return result;
}
private PluginResult ConnectService() {
doBindService();
return new PluginResult(Status.OK);
}
private PluginResult DisconnectService() {
doUnbindService();
return new PluginResult(Status.OK);
}
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MoMe_Service.MSG_COMMAND:
Log.i("CLIENT","Received from service: " + msg.getData().getString("MSG"));
break;
default:
super.handleMessage(msg);
}
}
}
private ServiceConnection service_connection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
messenger_service = new Messenger(service);
connected_to_service=true;
try {
Message msg = Message.obtain(null, My_Service.MSG_REGISTERED);
msg.replyTo = messenger_receive;
messenger_service.send(msg);
} catch (RemoteException e) {
// In this case the service has crashed before we could even
// do anything with it; we can count on soon being
// disconnected (and then reconnected if it can be restarted)
// so there is no need to do anything here.
}
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
messenger_service = null;
connected_to_service=false;
}
};
private void doBindService() {
// Establish a connection with the service. We use an explicit
// class name because there is no reason to be able to let other
// applications replace our component.
this.ctx.bindService(new Intent(this.ctx, My_Service.class), service_connection, Context.BIND_AUTO_CREATE);
}
private void doUnbindService() {
if (connected_to_service) {
if (messenger_service != null) {
try {
Message msg = Message.obtain(null, My_Service.MSG_UNREGISTERED);
msg.replyTo = messenger_receive;
messenger_service.send(msg);
} catch (RemoteException e) {
// There is nothing special we need to do if the service
// has crashed.
}
}
// Detach our existing connection.
this.ctx.unbindService(service_connection);
connected_to_service = false;
}
}
private void sendMSG (String message) {
try {
Message msg=Message.obtain(null, My_Service.MSG_COMMAND);
Bundle msg_bundle=new Bundle();
msg_bundle.putString("MSG", message);
msg.setData(msg_bundle);
messenger_service.send(msg);
} catch (RemoteException e) {
doUnbindService();
}
}
}
From this plugin the real trouble comes with this part of code, which handles the return messages and the plugin return (which goes to the javascript):
#Override
public PluginResult execute(String action, JSONArray data, String callbackId) {
PluginResult result = null;
try {
result = new PluginResult(Status.ok);
}
} catch(JSONException e) {
result= new PluginResult(PluginResult.Status.JSON_EXCEPTION);
}
return result;
}
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MoMe_Service.MSG_COMMAND:
msg.getData().getString("MSG")); // THIS IS THE DATA I NEED RETURNED
break;
default:
super.handleMessage(msg);
}
}
}
The only solution I can think of, is storing the response in either a database or a variable and have the javascript do a setInterval to keep checking for changes. However I am not very fond of this solution. I would like to use some sort of callback function to let the javascript know the message has returned but I have no idea how. I would greatly appreciate any help and ideas.
Thank you,
Vlad
This might be a late answer but I started to work with Cordova Plugin around 5 months ago and I just saw your question. Since you did not choose the correct answer I wanted to answer your question.
Assuming you have asynchronous process and you have a listener and methods, success and fail , lets call it onSuccess() and onFail(). As long as you send true with pluginResult.setKeepCallback(true), the process will remain as unfinished, so you can send your plugin result data later on when you are done with background process. Here is an example take a look.
#Override
public boolean execute(String action, JSONArray data, String callbackId) throws JSONException {
if (action.equals("start")) {
start();
} else {
PluginResult pluginResult = new PluginResult(PluginResult.Status.INVALID_ACTION);
callbackContext.sendPluginResult(pluginResult);
return false;
}
}
private boolean start() throws JSONException {
MyClass.startProcess(new MyInterface() {
#Override
public void onSuccess(String data) {
PluginResult result = new PluginResult(PluginResult.Status.OK, data);
result.setKeepCallback(false);
callbackContext.sendPluginResult(result);
}
#Override
public void onFail() {
PluginResult result = new PluginResult(PluginResult.Status.ERROR);
result.setKeepCallback(false);
callbackContext.sendPluginResult(result);
}
});
PluginResult.Status status = PluginResult.Status.NO_RESULT;
PluginResult pluginResult = new PluginResult(status);
pluginResult.setKeepCallback(true);
callbackContext.sendPluginResult(pluginResult);
return true;
}
The answer to my problem was actually in the the PluginResult object and success method.
I've found a plugin that had to face the same problem in order to work, and from this code i was able to figure out my answer.This is a onPhoneStatusChange plugin, which can be found here!
The mystery lies in these lines:
PluginResult res = new PluginResult(PluginResult.Status.OK, obj);
res.setKeepCallback(true);
success(res, callbackId);
The generic solution to this problem is to have the service store the response into persistent storage (like a database) and then fire off a broadcast intent. Then just have a BroadcastReciever in your ServiceClient_plugin class listening for the broadcast. This way you woun't have to keep polling to see if the data has arrived yet.
You can send PluginResult using success() function like this:
public PluginResult execute(String action, JSONArray data, String callbackId) {}
private BroadcastReceiver Wifi_Receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
MyClass.this.success(new PluginResult(PluginResult.Status.OK,"count"+count),callback);
}
}
here callback is callbackId of execute() function

Categories

Resources