io.jxcore.node.jxcore.java Source code

Java tutorial

Introduction

Here is the source code for io.jxcore.node.jxcore.java

Source

// License information is available from LICENSE file

package io.jxcore.node;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;
import org.apache.cordova.PluginResult.Status;
import org.json.JSONArray;
import org.json.JSONException;

import android.app.Activity;
import android.content.Context;
import android.content.res.AssetManager;
import android.os.Looper;
import android.util.Log;

public class jxcore extends CordovaPlugin {

    static {
        System.loadLibrary("jxcore");
    }

    // Methods below are inherited from jxcore-cordova JNI
    // Make sure reach these methods under the same thread
    public native void setNativeContext(final Context context, final AssetManager assetManager);

    public native int loopOnce();

    public native void startEngine();

    public native void prepareEngine(String home, String fileTree);

    public native void stopEngine();

    public native void defineMainFile(String content);

    public native long evalEngine(String script);

    public native int getType(long id);

    public native String getString(long id);

    public native String convertToString(long id);

    public native long callCBString(String event_name, String param, int is_json);

    public native long callCBArray(String event_name, Object[] arr, int size);

    public static String LOGTAG = "JX-Cordova";
    public static Activity activity = null;
    public static jxcore addon;

    Map<String, CallbackContext> callbacks;
    static Map<String, JXcoreCallback> java_callbacks;
    public static CoreThread coreThread = null;
    public static boolean app_paused = false;
    public static boolean jxcoreInitialized = false;

    public static void CreateResult(Object value, String callback_id, boolean async, boolean is_error) {
        PluginResult result;

        if (value == null) {
            result = new PluginResult(is_error ? Status.ERROR : Status.OK, 0);
        } else if (is_error) {
            result = new PluginResult(Status.ERROR, (String) value);
        } else if (value.getClass().equals(Integer.class)) {
            result = new PluginResult(Status.OK, (Integer) value);
        } else if (value.getClass().equals(Boolean.class)) {
            result = new PluginResult(Status.OK, (Boolean) value);
        } else if (value.getClass().equals(Double.class)) {
            result = new PluginResult(Status.OK, (Float) value);
        } else if (value.getClass().equals(String.class)) {
            result = new PluginResult(Status.OK, (String) value);
        } else if (value.getClass().equals(byte[].class)) {
            result = new PluginResult(Status.OK, ((byte[]) value));
        } else if (value.getClass().equals(String[].class)) {
            String[] arr = (String[]) value;
            try {
                result = new PluginResult(Status.OK, new JSONArray(arr[0]));
            } catch (JSONException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return;
            }
        } else {
            result = new PluginResult(Status.OK, value.toString());
        }

        if (async) {
            result.setKeepCallback(true);
            if (addon.callbacks.containsKey(callback_id)) {
                activity.runOnUiThread(new CoreRunnable(callback_id, result) {
                    @Override
                    public void run() {
                        CallbackContext ctx = addon.callbacks.get(callback_id_);
                        ctx.sendPluginResult(result_);
                    }
                });
            }
        } else {
            CallbackContext ctx = addon.callbacks.remove(callback_id);
            ctx.sendPluginResult(result);
        }
    }

    public interface JXcoreCallback {
        public void Receiver(ArrayList<Object> params, String callbackId);
    }

    public static void jx_callback(Object value, Object error, String callbackId) {
        CreateResult(error == null ? value : error, callbackId, true, error != null);
    }

    public static void javaCall(ArrayList<Object> params) {
        if (params.size() < 2 || params.get(0).getClass() != String.class
                || params.get(params.size() - 1).getClass() != String.class) {
            Log.e(LOGTAG, "JavaCall recevied an unknown call");
            return;
        }

        String receiver = params.remove(0).toString();
        String callId = params.remove(params.size() - 1).toString();

        if (!java_callbacks.containsKey(receiver)) {
            Log.e(LOGTAG, "JavaCall recevied a call for unknown method " + receiver);
            return;
        }

        java_callbacks.get(receiver).Receiver(params, callId);
    }

    public static void RegisterMethod(String name, JXcoreCallback callback) {
        java_callbacks.put(name, callback);
    }

    private static void callJSMethod(String id, Object[] args) {
        long ret = addon.callCBArray(id, args, args.length);
        int tp = addon.getType(ret);

        // STRING 4, OBJECT 5, ERROR 9 - See jx_types
        if (tp == 4 || tp == 5 || tp == 9) {
            Log.e(LOGTAG, "jxcore.CallJSMethod :" + addon.getString(ret));
        }
    }

    private static void callJSMethod(String id, String args) {
        long ret = addon.callCBString(id, args, 1);
        int tp = addon.getType(ret);

        // STRING 4, OBJECT 5, ERROR 9 - See jx_types
        if (tp == 4 || tp == 5 || tp == 9) {
            Log.e(LOGTAG, "jxcore.CallJSMethod :" + addon.getString(ret));
        }
    }

    public static boolean CallJSMethod(String id, Object[] args) {
        if (jxcore.coreThread == null) {
            Log.e(LOGTAG, "JXcore wasn't initialized yet");
            return false;
        }

        if (Looper.myLooper() != coreThread.handler.getLooper()) {
            coreThread.handler.post(new CoreRunnable(id, args) {
                @Override
                public void run() {
                    callJSMethod(callback_id_, params_);
                }
            });
        } else {
            callJSMethod(id, args);
        }

        return true;
    }

    public static boolean CallJSMethod(String id, String json) {
        if (jxcore.coreThread == null) {
            Log.e(LOGTAG, "JXcore wasn't initialized yet");
            return false;
        }

        if (Looper.myLooper() != coreThread.handler.getLooper()) {
            coreThread.handler.post(new CoreRunnable(id, json) {
                @Override
                public void run() {
                    callJSMethod(callback_id_, str_param_);
                }
            });
        } else {
            callJSMethod(id, json);
        }

        return true;
    }

    @Override
    public boolean execute(final String action, final JSONArray data, final CallbackContext callbackContext) {

        PluginResult result = null;
        try {
            if (action.equals("isReady")) {
                result = new PluginResult(Status.OK, jxcoreInitialized);
            } else if (action.equals("Evaluate")) {
                final String json = data.get(0).toString() + ", '" + callbackContext.getCallbackId() + "')";
                callbacks.put(callbackContext.getCallbackId(), callbackContext);

                result = new PluginResult(Status.NO_RESULT);
                result.setKeepCallback(true);

                coreThread.handler.post(new CoreRunnable(callbackContext.getCallbackId(), json) {
                    @Override
                    public void run() {
                        long res = evalEngine(str_param_);
                        if (res >= 0) {
                            String str_err = getString(res);

                            CreateResult(str_err, callback_id_, true, true);
                        }
                    }
                });

            } else {
                result = new PluginResult(Status.OK);
            }
        } catch (Exception ex) {
            result = new PluginResult(Status.ERROR, ex.toString());
        }

        if (result != null)
            callbackContext.sendPluginResult(result);

        return true;
    }

    public void onStart(boolean multitasking) {
        super.onPause(multitasking);
        jxcore.CallJSMethod("JXcore_Device_OnPause", "{}");
        app_paused = true;
    }

    public void onStop(boolean multitasking) {
        super.onResume(multitasking);
        jxcore.CallJSMethod("JXcore_Device_OnResume", "{}");
        app_paused = false;
    }

    // Make sure calling this method under CoreThread!!
    private void Initialize(String home) {
        // assets.list is terribly slow, trick below is literally 100 times faster
        StringBuilder assets = new StringBuilder();
        assets.append("{");
        boolean first_entry = true;
        try {
            ZipFile zf = new ZipFile(activity.getBaseContext().getApplicationInfo().sourceDir);
            try {
                for (Enumeration<? extends ZipEntry> e = zf.entries(); e.hasMoreElements();) {
                    ZipEntry ze = e.nextElement();
                    String name = ze.getName();
                    if (name.startsWith("assets/www/jxcore/")) {
                        if (first_entry)
                            first_entry = false;
                        else
                            assets.append(",");
                        int size = FileManager.aproxFileSize(name.substring(7));
                        assets.append("\"" + name.substring(18) + "\":" + size);
                    }
                }
            } finally {
                zf.close();
            }
        } catch (Exception e) {
        }
        assets.append("}");

        prepareEngine(home + "/www/jxcore", assets.toString());

        String mainFile = FileManager.readFile("jxcore_cordova.js");

        String data = "process.setPaths = function(){ process.cwd = function() { return '" + home
                + "/www/jxcore';};\n" + "process.userPath ='"
                + activity.getBaseContext().getFilesDir().getAbsolutePath() + "';\n" + "};" + mainFile;

        defineMainFile(data);

        startEngine();

        jxcoreInitialized = true;
    }

    @Override
    protected void pluginInitialize() {
        final boolean new_instance = activity == null;
        activity = cordova.getActivity();
        if (!new_instance) {
            Log.d(LOGTAG, "jxcore cordova android initializing");
        }
        addon = this;

        callbacks = new HashMap<String, CallbackContext>();
        java_callbacks = new HashMap<String, JXcoreCallback>();

        RegisterMethod("  _callback_  ", new JXcoreCallback() {
            @Override
            public void Receiver(ArrayList<Object> params, String callbackId) {
                if (params.size() < 3 || !params.get(2).getClass().equals(String.class)) {
                    Log.e(LOGTAG, "Unkown _callback_ received");
                    return;
                }
                jxcore.jx_callback(params.get(0), params.get(1), params.get(2).toString());
            }
        });

        JXcoreExtension.LoadExtensions();
        JXMobile.Initialize();

        if (new_instance) {
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    setNativeContext(activity.getBaseContext(), activity.getAssets());
                    addon.Initialize(activity.getBaseContext().getFilesDir().getAbsolutePath());

                    Runnable runnable2 = new Runnable() {
                        @Override
                        public void run() {
                            int active = addon.loopOnce();
                            final int wait_long = app_paused ? 10 : 3;
                            if (active == 0)
                                coreThread.handler.postDelayed(this, wait_long);
                            else
                                coreThread.handler.postDelayed(this, 1);
                        }
                    };

                    coreThread.handler.postDelayed(runnable2, 1);
                }
            };

            if (coreThread != null) {
                coreThread.handler.getLooper().quit();
            }

            coreThread = new CoreThread(runnable);
            coreThread.start();
        } else {
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    setNativeContext(activity.getBaseContext(), activity.getAssets());
                }
            };
            coreThread.handler.post(runnable);
        }
    }
}