private boolean invokeBlinkup(
      final Activity activity, final BlinkupController controller, JSONArray data) {
    int timeoutMs;
    try {
      mApiKey = data.getString(BLINKUP_ARG_API_KEY);
      mDeveloperPlanId = data.getString(BLINKUP_ARG_DEVELOPER_PLAN_ID);
      timeoutMs = data.getInt(BLINKUP_ARG_TIMEOUT_MS);
      mGeneratePlanId = data.getBoolean(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;
    }

    Intent blinkupCompleteIntent = new Intent(activity, BlinkUpCompleteActivity.class);
    blinkupCompleteIntent.putExtra(Extras.EXTRA_DEVELOPER_PLAN_ID, mDeveloperPlanId);
    blinkupCompleteIntent.putExtra(Extras.EXTRA_TIMEOUT_MS, timeoutMs);
    controller.intentBlinkupComplete = blinkupCompleteIntent;

    // 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 boolean abortBlinkup(BlinkupController controller) {
   controller.cancelTokenStatusPolling();
   BlinkUpPluginResult.sendPluginErrorToCallback(ERROR_CANCELLED_BY_USER);
   return true;
 }