private Boolean updateMarkers(ReadableArray markerArray) {
    try {
      // First clear all markers from the map
      for (Marker marker : mapMarkers) {
        marker.remove();
      }
      mapMarkers.clear();
      markerLookup.clear();

      // All markers to map
      for (int i = 0; i < markerArray.size(); i++) {
        ReadableMap markerJson = markerArray.getMap(i);
        if (markerJson.hasKey("coordinates")) {
          Marker marker = map.addMarker(createMarker(markerJson));

          if (markerJson.hasKey("id")) {
            // As we have to lookup it either way, switch it around
            markerLookup.put(marker.getId(), markerJson.getString("id"));
            markerLookup.put(markerJson.getString("id"), marker.getId().replace("m", ""));
          }

          mapMarkers.add(marker);

        } else break;
      }

      return true;
    } catch (Exception e) {
      e.printStackTrace();
      return false;
    }
  }
  public void updateDataSetOptions(DataSetClass dataSet, ReadableMap map) {
    if (map.hasKey("values")) {
      ReadableArray valueArray = map.getArray("values");
      for (int j = 0; j < valueArray.size(); j++) {
        Entry entry;
        try {
          entry = entryConstructor.newInstance((float) valueArray.getDouble(j), j);
        } catch (Exception e) {
          throw new Error("Entry failed to instantiate");
        }

        dataSet.addEntry(entry);
      }
    }

    if (map.hasKey("colors")) {
      ReadableArray colorsArray = map.getArray("colors");
      ArrayList<Integer> colors = new ArrayList<>();

      for (int c = 0; c < colorsArray.size(); c++) {
        colors.add(Color.parseColor(colorsArray.getString(c)));
      }

      dataSet.setColors(colors);
    }

    if (map.hasKey("drawValues")) {
      dataSet.setDrawValues(map.getBoolean("drawValues"));
    }

    // TODO: add other properties to dataSet here

  }
  // NOTE: Currently not reentrant / doesn't support concurrent requests
  @ReactMethod
  public void launchImageLibrary(final ReadableMap options, final Callback callback) {
    response = Arguments.createMap();

    if (options.hasKey("noData")) {
      noData = options.getBoolean("noData");
    }
    if (options.hasKey("maxWidth")) {
      maxWidth = options.getInt("maxWidth");
    }
    if (options.hasKey("maxHeight")) {
      maxHeight = options.getInt("maxHeight");
    }
    if (options.hasKey("aspectX")) {
      aspectX = options.getInt("aspectX");
    }
    if (options.hasKey("aspectY")) {
      aspectY = options.getInt("aspectY");
    }
    if (options.hasKey("quality")) {
      quality = (int) (options.getDouble("quality") * 100);
    }
    tmpImage = true;
    if (options.hasKey("storageOptions")) {
      tmpImage = false;
    }
    if (options.hasKey("allowsEditing")) {
      allowEditing = options.getBoolean("allowsEditing");
    }
    forceAngle = false;
    if (options.hasKey("angle")) {
      forceAngle = true;
      angle = options.getInt("angle");
    }
    if (options.hasKey("assetProperties")) {
      assetProperties = options.getBoolean("assetProperties");
    }

    Intent libraryIntent =
        new Intent(
            Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);

    if (libraryIntent.resolveActivity(mMainActivity.getPackageManager()) == null) {
      response.putString("error", "Cannot launch photo library");
      callback.invoke(response);
      return;
    }

    mCallback = callback;

    try {
      mMainActivity.startActivityForResult(libraryIntent, REQUEST_LAUNCH_IMAGE_LIBRARY);
    } catch (ActivityNotFoundException e) {
      e.printStackTrace();
    }
  }
  private MarkerOptions createMarker(ReadableMap markerJson) {
    MarkerOptions options = new MarkerOptions();
    options.position(
        new LatLng(
            markerJson.getMap("coordinates").getDouble("lat"),
            markerJson.getMap("coordinates").getDouble("lng")));

    if (markerJson.hasKey("title")) {
      options.title(markerJson.getString("title"));
    }
    if (markerJson.hasKey("color")) {
      options.icon(BitmapDescriptorFactory.defaultMarker((float) markerJson.getDouble("color")));
    }
    if (markerJson.hasKey("snippet")) {
      options.snippet(markerJson.getString("snippet"));
    }
    if (markerJson.hasKey("icon")) {
      String varName = "";
      ReadableType iconType = markerJson.getType("icon");
      if (iconType.compareTo(ReadableType.Map) >= 0) {
        ReadableMap icon = markerJson.getMap("icon");
        try {
          int resId = getResourceDrawableId(icon.getString("uri"));
          Bitmap image = BitmapFactory.decodeResource(reactContext.getResources(), resId);

          options.icon(
              BitmapDescriptorFactory.fromBitmap(
                  Bitmap.createScaledBitmap(
                      image, icon.getInt("width"), icon.getInt("height"), true)));
        } catch (Exception e) {
          varName = icon.getString("uri");
        }
      } else if (iconType.compareTo(ReadableType.String) >= 0) {
        varName = markerJson.getString("icon");
      }
      if (!varName.equals("")) {
        // Changing marker icon to use resource
        int resourceValue = getResourceDrawableId(varName);
        Log.i(REACT_CLASS, varName + markerJson.toString());
        options.icon(BitmapDescriptorFactory.fromResource(resourceValue));
      }
    }
    if (markerJson.hasKey("anchor")) {
      ReadableArray anchor = markerJson.getArray("anchor");
      options.anchor((float) anchor.getDouble(0), (float) anchor.getDouble(1));
    }
    return options;
  }
  // NOTE: Currently not reentrant / doesn't support concurrent requests
  @ReactMethod
  public void launchCamera(ReadableMap options, Callback callback) {
    if (options.hasKey("noData")) {
      noData = options.getBoolean("noData");
    }

    Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if (cameraIntent.resolveActivity(mMainActivity.getPackageManager()) == null) {
      callback.invoke(true, "error resolving activity");
      return;
    }

    // we create a tmp file to save the result
    File imageFile;
    try {
      imageFile =
          File.createTempFile(
              "exponent_capture_",
              ".jpg",
              Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES));
    } catch (IOException e) {
      e.printStackTrace();
      return;
    }
    if (imageFile == null) {
      callback.invoke(true, "error file not created");
      return;
    }
    cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(imageFile));
    mCameraCaptureURI = Uri.fromFile(imageFile);
    mCallback = callback;
    mMainActivity.startActivityForResult(cameraIntent, REQUEST_LAUNCH_CAMERA);
  }
 public void addMarker(ReadableMap config) {
   MarkerOptions options = createMarker(config);
   Marker marker = map.addMarker(options);
   mapMarkers.add(marker);
   if (config.hasKey("id")) {
     // As we have to lookup it either way, switch it around
     markerLookup.put(marker.getId(), config.getString("id"));
     markerLookup.put(config.getString("id"), marker.getId().replace("m", ""));
   }
 }
  @ReactProp(name = "data")
  public void setData(ChartClass chart, ReadableMap map) {
    ChartData chartData;
    try {
      chartData = chartDataConstructor.newInstance();
    } catch (Exception e) {
      throw new RuntimeException("ChartData failed to instantiate");
    }

    if (map.hasKey("xValues")) {
      ReadableArray xValuesArray = map.getArray("xValues");
      for (int k = 0; k < xValuesArray.size(); k++) {
        chartData.addXValue(xValuesArray.getString(k));
      }
    }

    if (map.hasKey("dataSets")) {
      ReadableArray dataSetsArray = map.getArray("dataSets");
      for (int i = 0; i < dataSetsArray.size(); i++) {

        ReadableMap dataSetMap = dataSetsArray.getMap(i);
        DataSetClass dataSet;

        try {
          dataSet =
              (DataSetClass)
                  this.dataSetConstructor.newInstance(new ArrayList<>(), "Data Set " + i);
        } catch (Exception e) {
          throw new RuntimeException("DataSet failed to instantiate");
        }

        updateDataSetOptions(dataSet, dataSetMap);
        chartData.addDataSet(dataSet);
      }

      chart.notifyDataSetChanged();
    }

    // TODO: add other properties to data here

    chart.setData(chartData);
    chart.invalidate();
  }
  public ShowOptions(@Nullable ReadableMap options) {
    if (options == null) {
      return;
    }

    if (options.hasKey(CLOSABLE_KEY)) {
      closable = options.getBoolean(CLOSABLE_KEY);
      Log.d(TAG, CLOSABLE_KEY + closable);
    }

    if (options.hasKey(USE_MAGIC_LINK_KEY)) {
      useMagicLink = options.getBoolean(USE_MAGIC_LINK_KEY);
      Log.d(TAG, USE_MAGIC_LINK_KEY + useMagicLink);
    }

    if (options.hasKey(AUTH_PARAMS_KEY)) {
      ReadableMap reactMap = options.getMap(AUTH_PARAMS_KEY);
      authParams = OptionsHelper.convertReadableMapToMap(reactMap);
      Log.d(TAG, AUTH_PARAMS_KEY + authParams);
    }

    if (options.hasKey(CONNECTIONS_KEY)) {
      ReadableArray connections = options.getArray(CONNECTIONS_KEY);
      List<String> list = new ArrayList<>(connections.size());
      for (int i = 0; i < connections.size(); i++) {
        String connectionName = connections.getString(i);
        switch (connectionName) {
          case LockReactModule.CONNECTION_EMAIL:
            connectionType = LockReactModule.CONNECTION_EMAIL;
            break;
          case LockReactModule.CONNECTION_SMS:
            connectionType = LockReactModule.CONNECTION_SMS;
            break;
        }
        list.add(connectionName);
      }
      this.connections = new String[list.size()];
      this.connections = list.toArray(this.connections);
      Log.d(TAG, CONNECTIONS_KEY + list);
    }
  }
  // NOTE: Currently not reentrant / doesn't support concurrent requests
  @ReactMethod
  public void launchImageLibrary(ReadableMap options, Callback callback) {
    if (options.hasKey("noData")) {
      noData = options.getBoolean("noData");
    }

    Intent libraryIntent = new Intent();
    libraryIntent.setType("image/");
    libraryIntent.setAction(Intent.ACTION_GET_CONTENT);
    mCallback = callback;
    mMainActivity.startActivityForResult(libraryIntent, REQUEST_LAUNCH_IMAGE_LIBRARY);
  }
  @ReactMethod
  public void showImagePicker(final ReadableMap options, final Callback callback) {
    List<String> mTitles = new ArrayList<String>();
    List<String> mActions = new ArrayList<String>();

    String cancelButtonTitle = "Cancel";

    if (options.hasKey("takePhotoButtonTitle")
        && !options.getString("takePhotoButtonTitle").isEmpty()) {
      mTitles.add(options.getString("takePhotoButtonTitle"));
      mActions.add("photo");
    }
    if (options.hasKey("chooseFromLibraryButtonTitle")
        && !options.getString("chooseFromLibraryButtonTitle").isEmpty()) {
      mTitles.add(options.getString("chooseFromLibraryButtonTitle"));
      mActions.add("library");
    }
    if (options.hasKey("cancelButtonTitle") && !options.getString("cancelButtonTitle").isEmpty()) {
      cancelButtonTitle = options.getString("cancelButtonTitle");
    }
    mTitles.add(cancelButtonTitle);
    mActions.add("cancel");

    String[] option = new String[mTitles.size()];
    option = mTitles.toArray(option);

    String[] action = new String[mActions.size()];
    action = mActions.toArray(action);
    final String[] act = action;

    ArrayAdapter<String> adapter =
        new ArrayAdapter<String>(mMainActivity, android.R.layout.select_dialog_item, option);
    AlertDialog.Builder builder = new AlertDialog.Builder(mMainActivity);
    if (options.hasKey("title") && !options.getString("title").isEmpty()) {
      builder.setTitle(options.getString("title"));
    }

    builder.setAdapter(
        adapter,
        new DialogInterface.OnClickListener() {
          public void onClick(DialogInterface dialog, int index) {
            if (act[index].equals("photo")) {
              launchCamera(options, callback);
            } else if (act[index].equals("library")) {
              launchImageLibrary(options, callback);
            } else {
              callback.invoke(true, Arguments.createMap());
            }
          }
        });

    final AlertDialog dialog = builder.create();
    /**
     * override onCancel method to callback cancel in case of a touch outside of the dialog or the
     * BACK key pressed
     */
    dialog.setOnCancelListener(
        new DialogInterface.OnCancelListener() {
          @Override
          public void onCancel(DialogInterface dialog) {
            dialog.dismiss();
            callback.invoke(true, Arguments.createMap());
          }
        });
    dialog.show();
  }
  // NOTE: Currently not reentrant / doesn't support concurrent requests
  @ReactMethod
  public void launchCamera(final ReadableMap options, final Callback callback) {
    response = Arguments.createMap();

    if (options.hasKey("noData")) {
      noData = options.getBoolean("noData");
    }
    if (options.hasKey("maxWidth")) {
      maxWidth = options.getInt("maxWidth");
    }
    if (options.hasKey("maxHeight")) {
      maxHeight = options.getInt("maxHeight");
    }
    if (options.hasKey("aspectX")) {
      aspectX = options.getInt("aspectX");
    }
    if (options.hasKey("aspectY")) {
      aspectY = options.getInt("aspectY");
    }
    if (options.hasKey("quality")) {
      quality = (int) (options.getDouble("quality") * 100);
    }
    tmpImage = true;
    if (options.hasKey("storageOptions")) {
      tmpImage = false;
    }
    if (options.hasKey("allowsEditing")) {
      allowEditing = options.getBoolean("allowsEditing");
    }
    forceAngle = false;
    if (options.hasKey("angle")) {
      forceAngle = true;
      angle = options.getInt("angle");
    }
    if (options.hasKey("assetProperties")) {
      assetProperties = options.getBoolean("assetProperties");
    }

    Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if (cameraIntent.resolveActivity(mMainActivity.getPackageManager()) == null) {
      response.putString("error", "Cannot launch camera");
      callback.invoke(response);
      return;
    }

    // we create a tmp file to save the result
    File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
    File imageFile;
    try {
      // Make sure the Pictures directory exists.
      path.mkdirs();
      imageFile = File.createTempFile("capture", ".jpg", path);
    } catch (IOException e) {
      e.printStackTrace();
      response.putString("error", e.getMessage());
      callback.invoke(response);
      return;
    }
    cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(imageFile));
    mCameraCaptureURI = Uri.fromFile(imageFile);
    mCallback = callback;

    try {
      mMainActivity.startActivityForResult(cameraIntent, REQUEST_LAUNCH_CAMERA);
    } catch (ActivityNotFoundException e) {
      e.printStackTrace();
    }
  }