com.macadamian.blinkup.BlinkUpPlugin.java Source code

Java tutorial

Introduction

Here is the source code for com.macadamian.blinkup.BlinkUpPlugin.java

Source

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Created by Stuart Douglas (sdouglas@macadamian.com) on June 11, 2015.
 * Copyright (c) 2015 Macadamian. All rights reserved.
 */

package com.macadamian.blinkup;

import android.app.Activity;
import android.content.Intent;
import android.text.TextUtils;
import android.util.Log;

import com.electricimp.blinkup.BlinkupController;
import com.electricimp.blinkup.TokenStatusCallback;
import com.electricimp.blinkup.TokenAcquireCallback;
import com.electricimp.blinkup.ServerErrorHandler;
import com.macadamian.blinkup.util.PreferencesHelper;

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

/*********************************************
 * execute() called from Javascript interface,
 * which saves the arguments and presents the
 * BlinkUpPlugin interface from the SDK
 ********************************************/
public class BlinkUpPlugin extends CordovaPlugin {
    private static final String TAG = "BlinkUpPlugin";

    private static final String START_BLINKUP = "startBlinkUp";
    private static final String INVOKE_BLINKUP = "invokeBlinkUp";
    private static final String ABORT_BLINKUP = "abortBlinkUp";
    private static final String CLEAR_BLINKUP_DATA = "clearBlinkUpData";

    private static CallbackContext sCallbackContext;
    private static boolean sClearCache = false;

    // only needed in this class
    private String mApiKey;
    private Boolean mGeneratePlanId = false;
    private Boolean mIsInDevelopment = false;
    private String mDeveloperPlanId;

    static final int STATUS_DEVICE_CONNECTED = 0;
    static final int STATUS_GATHERING_INFO = 200;
    static final int STATUS_CLEAR_WIFI_COMPLETE = 201;
    static final int STATUS_CLEAR_WIFI_AND_CACHE_COMPLETE = 202;

    static final int ERROR_INVALID_ARGUMENTS = 100;
    static final int ERROR_PROCESS_TIMED_OUT = 101;
    static final int ERROR_CANCELLED_BY_USER = 102;
    static final int ERROR_INVALID_API_KEY = 103;
    static final int ERROR_VERIFY_API_KEY_FAIL = 301; // android only
    static final int ERROR_JSON_ERROR = 302; // android only

    // argument indexes from BlinkUp.js, the plugin's JS interface to Cordova
    private static final int INVOKE_BLINKUP_ARG_API_KEY = 0;
    private static final int INVOKE_BLINKUP_ARG_DEVELOPER_PLAN_ID = 1;
    private static final int INVOKE_BLINKUP_ARG_TIMEOUT_MS = 2;
    private static final int INVOKE_BLINKUP_ARG_GENERATE_PLAN_ID = 3;

    private static final int START_BLINKUP_ARG_API_KEY = 0;
    private static final int START_BLINKUP_ARG_DEVELOPER_PLAN_ID = 1;
    private static final int START_BLINKUP_IS_IN_DEVELOPMENT = 2;
    private static final int START_BLINKUP_ARG_TIMEOUT_MS = 3;

    /**********************************************************
     * method called by Cordova javascript
     *********************************************************/
    @Override
    public boolean execute(String action, JSONArray data, CallbackContext callbackContext) throws JSONException {
        sCallbackContext = callbackContext;
        final Activity activity = cordova.getActivity();
        final BlinkupController controller = BlinkupController.getInstance();

        if (START_BLINKUP.equalsIgnoreCase(action)) {
            return startBlinkUp(activity, controller, data);
        } else if (INVOKE_BLINKUP.equalsIgnoreCase(action)) {
            return invokeBlinkup(activity, controller, data);
        } else if (ABORT_BLINKUP.equalsIgnoreCase(action)) {
            return abortBlinkup(controller);
        } else if (CLEAR_BLINKUP_DATA.equalsIgnoreCase(action)) {
            return clearBlinkupData(activity, controller);
        }
        return false;
    }

    private boolean startBlinkUp(final Activity activity, final BlinkupController controller, JSONArray data) {
        int timeoutMs;
        try {
            mApiKey = data.getString(START_BLINKUP_ARG_API_KEY);
            mDeveloperPlanId = data.getString(START_BLINKUP_ARG_DEVELOPER_PLAN_ID);
            mIsInDevelopment = data.getBoolean(START_BLINKUP_IS_IN_DEVELOPMENT);
            timeoutMs = data.getInt(START_BLINKUP_ARG_TIMEOUT_MS);
        } catch (JSONException exc) {
            BlinkUpPluginResult.sendPluginErrorToCallback(ERROR_INVALID_ARGUMENTS);
            return false;
        }

        // if api key not valid, send error message and quit
        if (!apiKeyFormatValid()) {
            BlinkUpPluginResult.sendPluginErrorToCallback(ERROR_INVALID_API_KEY);
            return false;
        } else if (mDeveloperPlanId == null || mDeveloperPlanId.isEmpty()) {
            BlinkUpPluginResult.sendPluginErrorToCallback(ERROR_INVALID_ARGUMENTS);
            return false;
        }

        controller.intentBlinkupComplete = createBlinkUpCompleteIntent(activity, timeoutMs);

        // default is to run on WebCore thread, we have UI so need UI thread
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                presentBlinkUp(activity, controller);
            }
        });
        return true;
    }

    /**
     * Old Style of BlinkUp invocation.
     *
     * @deprecated use {@link #startBlinkUp()} instead.
     */
    @Deprecated
    private boolean invokeBlinkup(final Activity activity, final BlinkupController controller, JSONArray data) {
        int timeoutMs;
        try {
            mApiKey = data.getString(INVOKE_BLINKUP_ARG_API_KEY);
            mDeveloperPlanId = data.getString(INVOKE_BLINKUP_ARG_DEVELOPER_PLAN_ID);
            timeoutMs = data.getInt(INVOKE_BLINKUP_ARG_TIMEOUT_MS);
            mGeneratePlanId = data.getBoolean(INVOKE_BLINKUP_ARG_GENERATE_PLAN_ID);
        } catch (JSONException exc) {
            BlinkUpPluginResult.sendPluginErrorToCallback(ERROR_INVALID_ARGUMENTS);
            return false;
        }

        // if api key not valid, send error message and quit
        if (!apiKeyFormatValid()) {
            BlinkUpPluginResult.sendPluginErrorToCallback(ERROR_INVALID_API_KEY);
            return false;
        }

        controller.intentBlinkupComplete = createBlinkUpCompleteIntent(activity, timeoutMs);

        // default is to run on WebCore thread, we have UI so need UI thread
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                presentBlinkUp(activity, controller);
            }
        });
        return true;
    }

    private Intent createBlinkUpCompleteIntent(Activity activity, int timeoutMs) {
        Intent blinkupCompleteIntent = new Intent(activity, BlinkUpCompleteActivity.class);
        blinkupCompleteIntent.putExtra(Extras.EXTRA_DEVELOPER_PLAN_ID, mDeveloperPlanId);
        blinkupCompleteIntent.putExtra(Extras.EXTRA_TIMEOUT_MS, timeoutMs);
        return blinkupCompleteIntent;
    }

    private boolean abortBlinkup(BlinkupController controller) {
        controller.cancelTokenStatusPolling();
        BlinkUpPluginResult.sendPluginErrorToCallback(ERROR_CANCELLED_BY_USER);
        return true;
    }

    private boolean clearBlinkupData(final Activity activity, final BlinkupController controller) {
        PreferencesHelper.setPlanId(activity, null);
        sClearCache = true;
        controller.intentClearComplete = new Intent(activity, ClearCompleteActivity.class);

        // default is to run on WebCore thread, clearing shows UI so needs UI thread
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                controller.clearDevice(activity);
            }
        });
        return true;
    }

    /**********************************************************
     * shows BlinkUpPlugin activity and handles appropriate callbacks
     **********************************************************/
    private void presentBlinkUp(Activity activity, BlinkupController controller) {

        // show toast if can't acquire token
        final TokenAcquireCallback tokenAcquireCallback = new TokenAcquireCallback() {
            @Override
            public void onSuccess(String planId, String id) {
            }

            @Override
            public void onError(String s) {
                Log.e(TAG, s);
            }
        };

        // send back error if connectivity issue
        ServerErrorHandler serverErrorHandler = new ServerErrorHandler() {
            @Override
            public void onError(String s) {
                BlinkUpPluginResult.sendPluginErrorToCallback(ERROR_VERIFY_API_KEY_FAIL);
            }
        };

        // load cached planId if available. Otherwise, SDK generates new one automatically
        // see electricimp.com/docs/manufacturing/planids/ for info about planIDs
        String planId = null;
        if (mIsInDevelopment || org.apache.cordova.BuildConfig.DEBUG) {
            Log.w(TAG, "WARNING - Using Developer Plan. For production, set isInDevelopment flag to false.");
            planId = mDeveloperPlanId;
        } else if (!mGeneratePlanId) {
            planId = PreferencesHelper.getPlanId(activity);
        }

        if (planId != null || !planId.isEmpty()) {
            controller.setPlanID(planId);
        }

        controller.acquireSetupToken(activity, mApiKey, tokenAcquireCallback);
        controller.selectWifiAndSetupDevice(activity, mApiKey, serverErrorHandler);
    }

    /**********************************************************
     * @return true if mApiKey is 32 alpha-numeric characters
     *********************************************************/
    private boolean apiKeyFormatValid() {
        if (TextUtils.isEmpty(mApiKey) || TextUtils.getTrimmedLength(mApiKey) != 32) {
            return false;
        }

        String isAlphaNumericPattern = "^[a-zA-Z0-9]*$";
        return mApiKey.matches(isAlphaNumericPattern);
    }

    static boolean getClearCache() {
        return sClearCache;
    }

    static void setClearCache(boolean val) {
        sClearCache = val;
    }

    static CallbackContext getCallbackContext() {
        return sCallbackContext;
    }
}