com.mattrayner.vuforia.VuforiaPlugin.java Source code

Java tutorial

Introduction

Here is the source code for com.mattrayner.vuforia.VuforiaPlugin.java

Source

package com.mattrayner.vuforia;

import org.apache.cordova.CordovaWebView;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;

import org.json.JSONObject;
import org.json.JSONArray;
import org.json.JSONException;

import android.app.Activity;
import android.content.Intent;
import android.content.Context;
import android.content.pm.PackageManager;
import android.util.Log;
import android.Manifest;
import android.Manifest.permission;

import com.mattrayner.vuforia.app.ImageTargets;

public class VuforiaPlugin extends CordovaPlugin {
    static final String LOGTAG = "CordovaVuforiaPlugin";

    // Some public static variables used to communicate state
    public static final String CAMERA = Manifest.permission.CAMERA;
    public static final String PLUGIN_ACTION = "org.cordova.plugin.vuforia.action";
    public static final String DISMISS_ACTION = "dismiss";
    public static final String PAUSE_ACTION = "pause";
    public static final String RESUME_ACTION = "resume";
    public static final String UPDATE_TARGETS_ACTION = "update_targets";

    // Save some ENUM values to describe plugin results
    public static final int IMAGE_REC_RESULT = 0;
    public static final int MANUAL_CLOSE_RESULT = 1;
    public static final int ERROR_RESULT = 2;
    public static final int NO_RESULT = 3;

    // What access to the camera do we require?
    private static final int CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE = 200;

    // Save a copy of our starting vuforia context so that we can start reference it later is needs be
    private static CallbackContext persistantVuforiaStartCallback;

    // Some internal variables for storing state across methods
    private static String ACTION;
    private static JSONArray ARGS;

    static final int IMAGE_REC_REQUEST = 1;

    // Internal variables for holding state
    private boolean vuforiaStarted = false;
    private boolean autostopOnImageFound = true;
    CallbackContext callback;

    public VuforiaPlugin() {
    }

    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
        super.initialize(cordova, webView);

        Log.d(LOGTAG, "Plugin initialized.");
    }

    @Override
    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
        callback = callbackContext;

        // Handle all expected actions
        if (action.equals("cordovaStartVuforia")) {
            startVuforia(action, args, callbackContext);
        } else if (action.equals("cordovaStopVuforia")) {
            stopVuforia(action, args, callbackContext);
        } else if (action.equals("cordovaStopTrackers")) {
            stopVuforiaTrackers(action, args, callbackContext);
        } else if (action.equals("cordovaStartTrackers")) {
            startVuforiaTrackers(action, args, callbackContext);
        } else if (action.equals("cordovaUpdateTargets")) {
            updateVuforiaTargets(action, args, callbackContext);
        } else {
            return false;
        }

        return true;
    }

    // Start our Vuforia activities
    public void startVuforia(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
        // If we are starting Vuforia, set the public variable referencing our start callback for later use
        VuforiaPlugin.persistantVuforiaStartCallback = callbackContext;

        ACTION = action;
        ARGS = args;

        // Get all of our ARGS out and into local variables
        String targetFile = args.getString(0);
        String targets = args.getJSONArray(1).toString();
        String overlayText = (args.isNull(2)) ? null : args.getString(2);
        String vuforiaLicense = args.getString(3);
        Boolean closeButton = args.getBoolean(4);
        Boolean showDevicesIcon = args.getBoolean(5);
        autostopOnImageFound = args.getBoolean(6);

        Context context = cordova.getActivity().getApplicationContext();

        // Create a new intent to pass data to Vuforia
        Intent intent = new Intent(context, ImageTargets.class);

        intent.putExtra("IMAGE_TARGET_FILE", targetFile);
        intent.putExtra("IMAGE_TARGETS", targets);

        if (overlayText != null)
            intent.putExtra("OVERLAY_TEXT", overlayText);

        intent.putExtra("LICENSE_KEY", vuforiaLicense);
        intent.putExtra("DISPLAY_CLOSE_BUTTON", closeButton);
        intent.putExtra("DISPLAY_DEVICES_ICON", showDevicesIcon);
        intent.putExtra("STOP_AFTER_IMAGE_FOUND", autostopOnImageFound);

        // Check to see if we have permission to access the camera
        if (cordova.hasPermission(CAMERA)) {
            // Launch a new activity with Vuforia in it. Expect it to return a result.
            cordova.startActivityForResult(this, intent, IMAGE_REC_REQUEST);
            vuforiaStarted = true;
        } else {
            // Request the camera permission and handle the outcome.
            cordova.requestPermission(this, CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE, CAMERA);
        }
    }

    // Stop Vuforia
    public void stopVuforia(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
        // JSON we will send back to Cordova
        JSONObject json = new JSONObject();

        // Is Vuforia sterts?
        if (vuforiaStarted) {
            Log.d(LOGTAG, "Stopping plugin");

            // Stop Vuforia
            sendAction(DISMISS_ACTION);
            vuforiaStarted = false;

            json.put("success", "true");
        } else {
            Log.d(LOGTAG, "Cannot stop the plugin because it wasn't started");

            json.put("success", "false");
            json.put("message", "No Vuforia session running");
        }

        // Send an OK result back to Cordova
        PluginResult result = new PluginResult(PluginResult.Status.OK, json);
        callback.sendPluginResult(result);
    }

    // Stop Vuforia trackers
    public void stopVuforiaTrackers(String action, JSONArray args, CallbackContext callbackContext)
            throws JSONException {
        Log.d(LOGTAG, "Pausing trackers");

        sendAction(PAUSE_ACTION);

        sendSuccessPluginResult();
    }

    // Start Vuforia trackers
    public void startVuforiaTrackers(String action, JSONArray args, CallbackContext callbackContext)
            throws JSONException {
        Log.d(LOGTAG, "Resuming trackers");

        sendAction(RESUME_ACTION);

        sendSuccessPluginResult();
    }

    // Start Vuforia trackers
    public void updateVuforiaTargets(String action, JSONArray args, CallbackContext callbackContext)
            throws JSONException {
        Log.d(LOGTAG, "Updating targets");

        Log.d(LOGTAG, "ARGS: " + args);

        String targets = args.getJSONArray(0).toString();

        sendAction(UPDATE_TARGETS_ACTION, targets);

        sendSuccessPluginResult();
    }

    // Handle the results of our permissions request
    public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults)
            throws JSONException {
        for (int r : grantResults) {
            // Is the permission denied for our video request?
            if (r == PackageManager.PERMISSION_DENIED && requestCode == CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE) {
                // Send a plugin error
                this.callback
                        .sendPluginResult(new PluginResult(PluginResult.Status.ERROR, "CAMERA_PERMISSION_ERROR"));
                return;
            }
        }

        if (requestCode == CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE)
            execute(ACTION, ARGS, this.callback); // Re-call execute with all the same values as before (will re-check for permissions)
    }

    // Called when we receive a response from an activity we've launched
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        String name;

        // If we get to this point with no data  then we've likely got an error. Or the activity closed because of an error.
        if (data == null) {
            name = "ERROR";
        } else {
            name = data.getStringExtra("name");
        }

        Log.d(LOGTAG, "Plugin received '" + name + "' from Vuforia.");

        // Check which request we're responding to
        if (requestCode == IMAGE_REC_REQUEST) {
            JSONObject jsonObj = new JSONObject();

            // Check what result code we received
            switch (resultCode) {
            case IMAGE_REC_RESULT: // We've received an image (hopefully)
                // Attempt to build and send a result back to Cordova.
                try {
                    // Create our status object
                    JSONObject jsonStatus = new JSONObject();
                    jsonStatus.put("imageFound", true);
                    jsonStatus.put("message", "An image was found.");

                    // Create our result object
                    JSONObject jsonResult = new JSONObject();
                    jsonResult.put("imageName", name);

                    // Create our response object
                    jsonObj.put("status", jsonStatus);
                    jsonObj.put("result", jsonResult);

                    // Create the plugin result
                    PluginResult result = new PluginResult(PluginResult.Status.OK, jsonObj);

                    // Send a result specifically to our PERSISTANT callback i.e. the callback given to startVuforia.
                    // This allows us to receive other messages from start/stop tracker events without losing this particular callback.
                    persistantVuforiaStartCallback.sendPluginResult(result);
                } catch (JSONException e) { // We encounter a JSONException
                    Log.d(LOGTAG, "JSON ERROR: " + e);
                    // Send an error to the plugin (so we don't just die quietly)
                    persistantVuforiaStartCallback.sendPluginResult(new PluginResult(PluginResult.Status.ERROR,
                            "JSON ERROR BUILDING IMAGE FOUND RESPONSE: " + e));
                }
                break;
            case MANUAL_CLOSE_RESULT: // The user has manually closed the plugin.
                try {
                    // Create our status object
                    JSONObject jsonStatus = new JSONObject();
                    jsonStatus.put("manuallyClosed", true);
                    jsonStatus.put("message", "User manually closed the plugin.");

                    jsonObj.put("status", jsonStatus);

                    // Send the result back to the persistant callback
                    persistantVuforiaStartCallback
                            .sendPluginResult(new PluginResult(PluginResult.Status.OK, jsonObj));
                } catch (JSONException e) {
                    Log.d(LOGTAG, "JSON ERROR: " + e);
                    // Send an error to the plugin (so we don't just die quietly)
                    persistantVuforiaStartCallback.sendPluginResult(new PluginResult(PluginResult.Status.ERROR,
                            "JSON ERROR BUILDING MANUAL CLOSE RESPONSE: " + e));
                }
                break;
            default:
                Log.d(LOGTAG, "Error - received unexpected code on Activity close: " + resultCode);
            }
        }

        // Mark Vuforia as closed
        vuforiaStarted = false;
    }

    // Send a broadcast to our open activity (probably Vuforia)
    private void sendAction(String action) {
        Intent resumeIntent = new Intent(PLUGIN_ACTION);
        resumeIntent.putExtra(PLUGIN_ACTION, action);
        this.cordova.getActivity().sendBroadcast(resumeIntent);
    }

    // Send a broadcast to our open activity (probably Vuforia)
    private void sendAction(String action, String data) {
        Intent resumeIntent = new Intent(PLUGIN_ACTION);
        resumeIntent.putExtra(PLUGIN_ACTION, action);
        resumeIntent.putExtra("ACTION_DATA", data);
        this.cordova.getActivity().sendBroadcast(resumeIntent);
    }

    // Send a generic 'success' result to the last callback given
    private void sendSuccessPluginResult() {
        try {
            JSONObject json = new JSONObject();
            json.put("success", "true");
            callback.sendPluginResult(new PluginResult(PluginResult.Status.OK, json));
        } catch (JSONException e) {
            Log.d(LOGTAG, "JSON ERROR: " + e);
        }
    }

    // Send an asynchronous update when an image is found and Vuforia is set to stay open.
    public static void sendImageFoundUpdate(String imageName) {
        Log.d(LOGTAG, "Attempting to send an update for image: " + imageName);

        // Create an object to hold our response
        JSONObject jsonObj = new JSONObject();

        // Try to build a JSON response to send to Cordova
        try {
            JSONObject jsonStatus = new JSONObject();
            jsonStatus.put("imageFound", true);
            jsonStatus.put("message", "An image was found.");

            JSONObject jsonResult = new JSONObject();
            jsonResult.put("imageName", imageName);

            jsonObj.put("status", jsonStatus);
            jsonObj.put("result", jsonResult);
        } catch (JSONException e) {
            Log.d(LOGTAG, "JSON ERROR: " + e);
        }

        // Build our response
        PluginResult result = new PluginResult(PluginResult.Status.OK, jsonObj);
        result.setKeepCallback(true); // Don't clean up our callback (we intend on sending more messages to it)

        // Send the result to our PERSISTANT callback
        persistantVuforiaStartCallback.sendPluginResult(result);
    }
}