com.tribalyte.plugin.myo.MyoApi.java Source code

Java tutorial

Introduction

Here is the source code for com.tribalyte.plugin.myo.MyoApi.java

Source

/*
 * The MIT License (http://www.opensource.org/licenses/mit-license.html)
 * 
 * Copyright (c) 2014 Tribalyte Technologies S.L. (http://www.tribalyte.com/)
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE. 
 */

package com.tribalyte.plugin.myo;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.json.JSONArray;
import org.json.JSONException;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

import com.thalmic.myo.Hub;
import com.thalmic.myo.Myo;
import com.thalmic.myo.scanner.ScanActivity;

/**
 * Class implementing the communication between the Cordova plugin and the Myo SDK API for Android
 * 
 * @author rbarriuso
 *
 */
public class MyoApi extends CordovaPlugin {

    public static final boolean LOG_ENABLED = true;

    private static final String TAG = MyoApi.class.getSimpleName();

    /* Actions on Hub */
    private static final String ACTION_INIT = "init";
    private static final String ACTION_SHUTDOWN = "shutdown";
    private static final String ACTION_OPEN_SCAN_DLG = "openScanDialog";
    private static final String ACTION_ATTACH_ADJ = "attachToAdjacentMyo";
    private static final String ACTION_ATTACH_ADJS = "attachToAdjacentMyos";
    private static final String ACTION_ATTACH_MAC = "attachByMacAddress";
    private static final String ACTION_DETACH = "detach";
    private static final String ACTION_SET_LOCK_POLICY = "setLockingPolicy";
    private static final String ACTION_GET_LOCK_POLICY = "getLockingPolicy";
    private static final String ACTION_SET_SENDUSAGE = "setSendUsageData";
    private static final String ACTION_IS_SENDUSAGE = "isSendingUsageData";
    private static final String ACTION_GET_ATTACH_ALLOWANCE = "getMyoAttachAllowance";
    private static final String ACTION_SET_ATTACH_ALLOWANCE = "setMyoAttachAllowance";
    private static final String ACTION_GET_DEVICES = "getConnectedDevices";
    private static final String ACTION_NOW = "now";
    private static final String ACTION_ON = "on";
    private static final String ACTION_OFF = "off";
    private static final String ACTION_OPEN_BLUETOOTH_CONFIG = "openBluetoothConfig";
    private static final String ACTION_IS_BLUETOOTH_ENABLED = "isBluetoothEnabled";
    /* Actions on Myo */
    private static final String ACTION_MYO_IS_UNLOCKED = "myo_isUnlocked";
    private static final String ACTION_MYO_LOCK = "myo_lock";
    private static final String ACTION_MYO_UNLOCK = "myo_unlock";
    private static final String ACTION_MYO_REQUEST_RSSI = "myo_requestRssi";
    private static final String ACTION_MYO_VIBRATE = "myo_vibrate";
    private static final String ACTION_MYO_NOTIFY_USER = "myo_notifyUserAction";
    private static final String ACTION_MYO_GET_CONNECT_STATE = "myo_getConnectionState";
    private static final String ACTION_MYO_IS_CONNECTED = "myo_isConnected";

    private static final int REQ_CODE_ENABLE_BT = 1;

    private final MyoEventController mController = new MyoEventController();
    private Hub mHub = null;
    private CallbackContext mOpenBtConfigCbc = null;

    @Override
    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
        super.initialize(cordova, webView);
        mHub = Hub.getInstance();
        logd("Plugin initialized");
    }

    @Override
    public boolean execute(String action, JSONArray args, CallbackContext cbc) throws JSONException {
        boolean res = true;
        logd("Execute: " + action + ", args len: " + args.length() + ", args: " + args.toString());
        if (ACTION_INIT.equals(action)) {
            initHub(cbc);
        } else if (ACTION_SHUTDOWN.equals(action)) {
            mHub.shutdown();
            cbc.success();
        } else if (ACTION_OPEN_SCAN_DLG.equals(action)) {
            startScanActivity(cbc);
        } else if (ACTION_ATTACH_ADJ.equals(action)) {
            attachToAdjacentMyo(null, cbc);
        } else if (ACTION_ATTACH_ADJS.equals(action)) {
            attachToAdjacentMyo(args.getInt(0), cbc);
        } else if (ACTION_ATTACH_MAC.equals(action)) {
            attachToAdjacentMyo(args.getString(0), cbc);
        } else if (ACTION_DETACH.equals(action)) {
            mHub.detach(args.getString(0));
            cbc.success();
        } else if (ACTION_SET_LOCK_POLICY.equals(action)) {
            mHub.setLockingPolicy(Hub.LockingPolicy.valueOf(args.getString(0)));
            cbc.success();
        } else if (ACTION_GET_LOCK_POLICY.equals(action)) {
            String policy = mHub.getLockingPolicy().name();
            cbc.success(policy);
        } else if (ACTION_SET_SENDUSAGE.equals(action)) {
            mHub.setSendUsageData(args.getBoolean(0));
            cbc.success();
        } else if (ACTION_IS_SENDUSAGE.equals(action)) {
            cbc.success(mHub.isSendingUsageData() ? 1 : 0);
        } else if (ACTION_GET_ATTACH_ALLOWANCE.equals(action)) {
            cbc.success(mHub.getMyoAttachAllowance());
        } else if (ACTION_SET_ATTACH_ALLOWANCE.equals(action)) {
            mHub.setMyoAttachAllowance(args.getInt(0));
            cbc.success();
        } else if (ACTION_GET_DEVICES.equals(action)) {
            JSONArray myoList = new JSONArray();
            for (Myo myo : mHub.getConnectedDevices()) {
                myoList.put(JsonMapper.toJson(myo));
            }
            cbc.success(myoList);
        } else if (ACTION_NOW.equals(action)) {
            cbc.success(Long.toString(mHub.now()));
        } else if (ACTION_ON.equals(action)) {
            mController.setEventHandler(args.getString(0), cbc);
        } else if (ACTION_OFF.equals(action)) {
            mController.removeEventHandler(args.getString(0));
        } else if (ACTION_MYO_IS_UNLOCKED.equals(action)) {
            Myo myo = mController.getMyoOrErr(args.getString(0), cbc);
            if (myo != null) {
                cbc.success(myo.isUnlocked() ? 1 : 0);
            }
        } else if (ACTION_MYO_LOCK.equals(action)) {
            Myo myo = mController.getMyoOrErr(args.getString(0), cbc);
            if (myo != null) {
                myo.lock();
                cbc.success();
            }
        } else if (ACTION_MYO_UNLOCK.equals(action)) {
            Myo myo = mController.getMyoOrErr(args.getString(0), cbc);
            if (myo != null) {
                myo.unlock(Myo.UnlockType.valueOf(args.getString(1)));
                cbc.success();
            }
        } else if (ACTION_MYO_REQUEST_RSSI.equals(action)) {
            Myo myo = mController.getMyoOrErr(args.getString(0), cbc);
            if (myo != null) {
                myo.requestRssi();
                cbc.success();
            }
        } else if (ACTION_MYO_VIBRATE.equals(action)) {
            Myo myo = mController.getMyoOrErr(args.getString(0), cbc);
            if (myo != null) {
                myo.vibrate(Myo.VibrationType.valueOf(args.getString(1)));
                cbc.success();
            }
        } else if (ACTION_MYO_NOTIFY_USER.equals(action)) {
            Myo myo = mController.getMyoOrErr(args.getString(0), cbc);
            if (myo != null) {
                myo.notifyUserAction();
                cbc.success();
            }
        } else if (ACTION_MYO_GET_CONNECT_STATE.equals(action)) {
            Myo myo = mController.getMyoOrErr(args.getString(0), cbc);
            if (myo != null) {
                cbc.success(myo.getConnectionState().name());
            }
        } else if (ACTION_MYO_IS_CONNECTED.equals(action)) {
            Myo myo = mController.getMyoOrErr(args.getString(0), cbc);
            if (myo != null) {
                cbc.success(myo.isConnected() ? 1 : 0);
            }
        } else if (ACTION_IS_BLUETOOTH_ENABLED.equals(action)) {
            try {
                cbc.success(BluetoothAdapter.getDefaultAdapter().isEnabled() ? 1 : 0);
            } catch (Exception e) {
                loge("Error accessing Bluetooth adapter", e);
                cbc.error("Error accessing Bluetooth adapter");
            }
        } else if (ACTION_OPEN_BLUETOOTH_CONFIG.equals(action)) {
            startBluetoothConfigActivity();
            mOpenBtConfigCbc = cbc;
        } else {
            logw("Action not supported: " + action);
            res = false; //Will result in a "MethodNotFound" error
        }

        //TODO: add Hub.Scanner functionality?

        return res;
    }

    private void initHub(final CallbackContext cbc) {
        cordova.getActivity().runOnUiThread(new Runnable() {
            public void run() { //Need to call Hubg.init from the UI thread in order to use ScanActivity
                Context ctx = cordova.getActivity();
                String appId = ctx.getPackageName();
                if (mHub.init(ctx, appId)) {
                    mHub.addListener(mController);
                    logd("Myo Hub initialized with appId " + appId);
                    cbc.success();
                } else {
                    loge("Could not initialize the Hub", null);
                    cbc.error("Could not initialize the Hub");
                }
            }
        });
    }

    //The scan activity is only for test purposes
    private void startScanActivity(final CallbackContext cbc) {
        cordova.getActivity().runOnUiThread(new Runnable() {
            public void run() {
                Activity ctx = cordova.getActivity();
                ctx.startActivity(new Intent(ctx, ScanActivity.class));
                logd("Test scan activity started");
                cbc.success();
            }
        });
    }

    private void startBluetoothConfigActivity() {
        cordova.getActivity().runOnUiThread(new Runnable() {
            public void run() {
                cordova.setActivityResultCallback(MyoApi.this);
                cordova.getActivity().startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE),
                        REQ_CODE_ENABLE_BT);
                logd("BT configuration activity started");
            }
        });
    }

    private void attachToAdjacentMyo(final Object reqVal, final CallbackContext cbc) {
        cordova.getThreadPool().execute(new Runnable() {
            public void run() {
                boolean res = true;
                if (reqVal == null) {
                    mHub.attachToAdjacentMyo();
                } else if (reqVal instanceof Number) {
                    mHub.attachToAdjacentMyos((Integer) reqVal);
                } else if (reqVal instanceof String) {
                    mHub.attachByMacAddress((String) reqVal);
                } else {
                    res = false;
                }
                if (res) {
                    logd("Attaching...");
                    cbc.success();
                } else {
                    loge("Unsupported argument passed: " + reqVal, null);
                    cbc.error("Wrong argument passed: " + reqVal);
                }
            }
        });
    }

    private void logd(String msg) {
        if (LOG_ENABLED) {
            Log.d(TAG, msg);
        }
    }

    private void logw(String msg) {
        if (LOG_ENABLED) {
            Log.w(TAG, msg);
        }
    }

    private void loge(String msg, Throwable t) {
        if (LOG_ENABLED) {
            Log.d(TAG, msg, t);
        }
    }

    @Override
    public void onPause(boolean multitasking) {
        logd("onPause. Multitask: " + multitasking);
        super.onPause(multitasking);
    }

    @Override
    public void onResume(boolean multitasking) {
        super.onResume(multitasking);
        logd("onResume");
    }

    @Override
    public void onNewIntent(Intent intent) {
        logd("onNewIntent");
        super.onNewIntent(intent);
    }

    @Override
    public void onDestroy() {
        logd("onDestroy. Shutting down Hub");
        try {
            if (mHub != null) {
                mHub.removeListener(mController);
                mHub.shutdown();
            }
        } catch (Exception e) {
            logw("Exception while closing Hub: " + e.getLocalizedMessage());
        }
        super.onDestroy();
    }

    @Override
    public Object onMessage(String id, Object data) { //Receive messages from other plugins through the webView
        logd("onMessage. Id: " + id + ", data: " + data);
        return super.onMessage(id, data);
    }

    @Override
    public void onReset() {
        logd("onReset");
        super.onReset();
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
        logd("onActivityResult. requestCode: " + requestCode + ", resultCode: " + resultCode);
        if (REQ_CODE_ENABLE_BT == requestCode) {
            if (mOpenBtConfigCbc != null) {
                mOpenBtConfigCbc.success((resultCode == Activity.RESULT_OK) ? 1 : 0);
                mOpenBtConfigCbc = null;
            } else {
                loge("Received BT enable activity result but no callbacks were stored", null);
            }
        }
        super.onActivityResult(requestCode, resultCode, intent);
    }

}