// test that after a page load the cached callback id and the live callback id match
  // this is to prevent a regression
  // the issue was that CordovaWebViewImpl's cached instance of CoreAndroid would become stale on
  // page load
  // this is because the cached instance was not being cleared when the pluginManager was reset on
  // page load
  // the plugin manager would get a new instance which would be updated with a new callback id
  // the cached instance's message channel callback id would become stale
  // effectively this caused message channel events to not be delivered
  public void testThatCachedCallbackIdIsValid() throws Throwable {
    Class cordovaWebViewImpl = CordovaWebViewImpl.class;
    // send a test event - this initializes cordovaWebViewImpl.appPlugin (the cached instance of
    // CoreAndroid)
    Method method = cordovaWebViewImpl.getDeclaredMethod("sendJavascriptEvent", String.class);
    method.setAccessible(true);
    method.invoke(cordovaWebView, "testEvent");
    sleep(1000);

    // load a page - this resets the plugin manager and nulls cordovaWebViewImpl.appPlugin
    // (previously this resets plugin manager but did not null cordovaWebViewImpl.appPlugin, leading
    // to the issue)
    runTestOnUiThread(
        new Runnable() {
          public void run() {
            cordovaWebView.loadUrl(START_URL);
          }
        });
    assertEquals(START_URL, testActivity.onPageFinishedUrl.take());

    // send a test event - this initializes cordovaWebViewImpl.appPlugin (the cached instance of
    // CoreAndroid)
    method.invoke(cordovaWebView, "testEvent");
    sleep(1000);

    // get reference to package protected class CoreAndroid
    Class coreAndroid = Class.forName("org.apache.cordova.CoreAndroid");

    // get cached CoreAndroid
    Field appPluginField = cordovaWebViewImpl.getDeclaredField("appPlugin");
    appPluginField.setAccessible(true);
    Object cachedAppPlugin = appPluginField.get(cordovaWebView);
    // get cached CallbackContext
    Field messageChannelField = coreAndroid.getDeclaredField("messageChannel");
    messageChannelField.setAccessible(true);
    CallbackContext cachedCallbackContext =
        (CallbackContext) messageChannelField.get(cachedAppPlugin);

    // get live CoreAndroid
    PluginManager pluginManager =
        MessageChannelMultiPageTest.this.cordovaWebView.getPluginManager();
    Field coreAndroidPluginNameField = coreAndroid.getField("PLUGIN_NAME");
    String coreAndroidPluginName = (String) coreAndroidPluginNameField.get(null);
    Object liveAppPlugin = pluginManager.getPlugin(coreAndroidPluginName);
    // get live CallbackContext
    CallbackContext liveCallbackContext = (CallbackContext) messageChannelField.get(liveAppPlugin);

    // get callback id from live callbackcontext
    String liveCallbackId =
        (liveCallbackContext != null) ? liveCallbackContext.getCallbackId() : null;
    // get callback id from cached callbackcontext
    String cachedCallbackId =
        (cachedCallbackContext != null) ? cachedCallbackContext.getCallbackId() : null;

    // verify that the live message channel has been initialized
    assertNotNull(liveCallbackId);
    // verify that the cached message channel and the live message channel have the same id
    assertEquals(liveCallbackId, cachedCallbackId);
  }
  /**
   * Executes the request and returns PluginResult.
   *
   * @param action The action to execute
   * @param args JSONArray of arguments for the plugin.
   * @param callbackContext The callback id used when calling back into JavaScript
   * @return True if the action was valid, otherwise false
   */
  @Override
  public boolean execute(String action, JSONArray args, CallbackContext callbackContext)
      throws JSONException {
    Log.d(EstimoteBeacons.class.toString(), "action -> " + action);

    try {
      if (action.equalsIgnoreCase(START_MONITORING_BEACONS_IN_REGION)) {
        startMonitoringBeaconsInRegion(callbackContext);
        return true;
      }

      if (action.equalsIgnoreCase(STOP_MONITORING_BEACONS_IN_REGION)) {
        stopMonitoringBeaconsInRegion();
        callbackContext.success(callbackContext.getCallbackId());
        return true;
      }

      if (action.equalsIgnoreCase(START_RANGING_BEACONS_IN_REGION)) {
        startRangingBeaconsInRegion();
        callbackContext.success(callbackContext.getCallbackId());
        return true;
      }

      if (action.equalsIgnoreCase(STOP_RANGING_BEACONS_IN_REGION)) {
        stopRangingBeaconsInRegion();
        callbackContext.success(callbackContext.getCallbackId());
        return true;
      }

      if (action.equalsIgnoreCase(GET_BEACONS)) {
        callbackContext.sendPluginResult(
            new PluginResult(PluginResult.Status.OK, listToJSONArray(beacons)));
        return true;
      }

      if (action.equalsIgnoreCase(IS_BLE_SUPPORTED)) {
        isBleSupported(callbackContext);
        return true;
      }

      if (action.equalsIgnoreCase(IS_BLUETOOTH_ENABLED)) {
        isBluetoothEnabled(callbackContext);
        return true;
      }
    } catch (Exception e) {
      System.out.println(e.getMessage());
      callbackContext.error(e.getMessage());
      return false;
    }
    return false;
  }
  public void setPushReceiveCallbackChannel(JSONArray data, CallbackContext callbackContext) {
    Log.i(TAG, "setPushReceiveCallbackChannel:" + callbackContext.getCallbackId());

    mJPushReceiveCallback = callbackContext;
    PluginResult dataResult = new PluginResult(PluginResult.Status.OK, "js call init ok");
    dataResult.setKeepCallback(true); // 必要
    mJPushReceiveCallback.sendPluginResult(dataResult);
  }
  public boolean execute(String action, JSONArray data, final CallbackContext callbackContext) {
    Boolean result = false;

    if (ACTION_START.equalsIgnoreCase(action)) {
      if (geotrigger.isEnabled()) {
        callbackContext.error("Service has already been started");
      } else if (!geotrigger.isConfigured()) {
        callbackContext.error("Call configure before calling start");
      } else {

        this.geotrigger.start();
        result = true;
        callbackContext.success("start succeed");
      }
    } else if (ACTION_STOP.equalsIgnoreCase(action)) {
      if (!geotrigger.isEnabled()) {
        callbackContext.error("The service hasn't started yet");
      } else {
        this.geotrigger.stop();
        result = true;
        callbackContext.success("stop succeed");
      }
    } else if (ACTION_CONFIGURE.equalsIgnoreCase(action)) {
      if (geotrigger.isEnabled()) {
        Log.v(Config.TAG, "has enabled, then disable all the previous geofences");
        geotrigger.stop();
      }

      TripPlan tripPlanToConfigure = null;
      try {
        TripPlanParser parser = new TripPlanParser(data.toString());
        tripPlanToConfigure = parser.getTripplan();

      } catch (Exception e) {
        e.printStackTrace();
        callbackContext.error("Errors occur when parsing tripplan data");
      }

      if (tripPlanToConfigure != null) {
        this.geotrigger.configure(tripPlanToConfigure);
        result = true;
        callbackContext.success("configure succeed");
      }
    } else if (ACTION_RECONFIGURE.equalsIgnoreCase(action)) {

      TripPlan tripPlanToConfigure = null;
      try {
        TripPlanParser parser = new TripPlanParser(data.toString());
        tripPlanToConfigure = parser.getTripplan();

      } catch (Exception e) {
        e.printStackTrace();
        callbackContext.error("Errors occur when parsing tripplan data");
      }

      if (tripPlanToConfigure != null) {
        this.geotrigger.reconfigure(tripPlanToConfigure);
        result = true;
        callbackContext.success("configure succeed");
      }
    } else if (ACTION_ADDPLACE.equalsIgnoreCase(action)) {
      if (!this.geotrigger.isConfigured()) {
        callbackContext.error("The service is not configured yet");
      } else {
        Place place = null;
        try {
          PlaceParser parser = new PlaceParser(data.toString());
          place = parser.getPlace();
        } catch (Exception e) {
          e.printStackTrace();
        }

        if (place == null) {
          callbackContext.error("Errors occur when parsing tripplan data");
        } else {
          boolean isAdded = this.geotrigger.addPlace(place);
          if (isAdded) {
            result = true;
            callbackContext.success("adding place succeed");
          } else {
            callbackContext.error("failed to add place");
          }
        }
      }

    } else if (ACTION_DELETEPLACE.equalsIgnoreCase(action)) {
      if (!this.geotrigger.isConfigured()) {
        callbackContext.error("The service is not configured yet");
      } else {
        String placeUuid = null;
        try {
          PlaceUuidParser parser = new PlaceUuidParser(data.toString());
          placeUuid = parser.getPlaceUuid();
        } catch (Exception e) {
          e.printStackTrace();
        }

        if (placeUuid == null) {
          callbackContext.error("Errors occur when parsing place uuid");
        } else {
          boolean isDeleted = this.geotrigger.deletePlace(placeUuid);
          if (isDeleted) {
            result = true;
            callbackContext.success("deleting place succeed");
          } else {
            callbackContext.error("failed to delete place");
          }
        }
      }
    } else if (ACTION_ENABLEPLACE.equalsIgnoreCase(action)) {
      if (!this.geotrigger.isConfigured()) {
        callbackContext.error("The service is not configured yet");
      } else {
        String placeUuid = null;
        try {
          PlaceUuidParser parser = new PlaceUuidParser(data.toString());
          placeUuid = parser.getPlaceUuid();
        } catch (Exception e) {
          e.printStackTrace();
        }

        if (placeUuid == null) {
          callbackContext.error("Errors occur when parsing place uuid");
        } else {
          boolean isEnabled = this.geotrigger.enablePlace(placeUuid);
          if (isEnabled) {
            result = true;
            callbackContext.success("enable place succeed");
          } else {
            callbackContext.error("failed to enable place");
          }
        }
      }
    } else if (ACTION_DISABLEPLACE.equalsIgnoreCase(action)) {
      if (!this.geotrigger.isConfigured()) {
        callbackContext.error("The service is not configured yet");
      } else {
        String placeUuid = null;
        try {
          PlaceUuidParser parser = new PlaceUuidParser(data.toString());
          placeUuid = parser.getPlaceUuid();
        } catch (Exception e) {
          e.printStackTrace();
        }

        if (placeUuid == null) {
          callbackContext.error("Errors occur when parsing place uuid");
        } else {
          boolean isEnabled = this.geotrigger.disablePlace(placeUuid);
          if (isEnabled) {
            result = true;
            callbackContext.success("disable place succeed");
          } else {
            callbackContext.error("failed to disable place");
          }
        }
      }
    } else if (ACTION_GETCURRENTLOCATION.equalsIgnoreCase(action)) {
      final LocationManager locationManager =
          (LocationManager) this.cordova.getActivity().getSystemService(Context.LOCATION_SERVICE);
      Criteria criteria = new Criteria();
      criteria.setAltitudeRequired(false);
      criteria.setBearingRequired(false);
      criteria.setSpeedRequired(true);
      criteria.setCostAllowed(true);
      criteria.setAccuracy(Criteria.ACCURACY_FINE);
      criteria.setHorizontalAccuracy(Criteria.ACCURACY_HIGH);
      criteria.setPowerRequirement(Criteria.POWER_HIGH);

      String bestProvider = locationManager.getBestProvider(criteria, true);
      if (bestProvider != LocationManager.PASSIVE_PROVIDER) {
        locationManager.requestLocationUpdates(
            bestProvider,
            0,
            0,
            new LocationListener() {

              @Override
              public void onLocationChanged(Location location) {
                JSONObject object = new JSONObject();
                try {
                  object.put("lat", location.getLatitude());
                  object.put("lng", location.getLongitude());
                } catch (JSONException e) {
                  e.printStackTrace();
                }
                callbackContext.success(object);
                locationManager.removeUpdates(this);
              }

              @Override
              public void onProviderDisabled(String arg0) {}

              @Override
              public void onProviderEnabled(String arg0) {}

              @Override
              public void onStatusChanged(String arg0, int arg1, Bundle arg2) {}
            });
      }
    } else if (ACTION_SETONNOTIFICATIONCLICKEDCALLBACK.equalsIgnoreCase(action)) {
      String callbackId = callbackContext.getCallbackId();
      this.callbackIds.put(ACTION_SETONNOTIFICATIONCLICKEDCALLBACK, callbackId);
      Log.d(Config.TAG, "notificaton callback is set");
      return true;
    } else if (ACTION_MOCK_START.equalsIgnoreCase(action)) {
      if (this.geoFaker != null && this.geoFaker.isStarted()) {
        callbackContext.error("geofaker has started");
      } else {
        this.geoFaker = new Geofaker(this.cordova.getActivity());
        this.geoFaker.start();
        result = true;
        callbackContext.success("mocking started");
      }
    } else if (ACTION_MOCK_STOP.equalsIgnoreCase(action)) {
      if (this.geoFaker != null && this.geoFaker.isStarted()) {
        this.geoFaker.stop();
        result = true;
        callbackContext.success("mocking stopped");
      } else {
        callbackContext.error("geofaker has already stopped");
      }
    } else if (ACTION_MOCK.equalsIgnoreCase(action)) {
      Intent intent = new Intent();
      intent.setAction(Geofaker.INTENT_MOCK_GPS_PROVIDER);
      intent.putExtra(Geofaker.MOCKED_JSON_COORDINATES, data.toString());
      activity.sendBroadcast(intent);
      result = true;
      callbackContext.success("mocked position: " + data.toString());
    }

    return result;
  }
Example #5
0
  /**
   * Executes the request and returns PluginResult.
   *
   * @param action The action to execute.
   * @param args JSONArry of arguments for the plugin.
   * @param callbackId The callback id used when calling back into JavaScript.
   * @return A PluginResult object with a status and message.
   */
  public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext)
      throws JSONException {
    if (action.equals("open")) {
      this.callbackContext = callbackContext;
      final String url = args.getString(0);
      String t = args.optString(1);
      if (t == null || t.equals("") || t.equals(NULL)) {
        t = SELF;
      }
      final String target = t;
      final HashMap<String, Boolean> features = parseFeature(args.optString(2));

      Log.d(LOG_TAG, "target = " + target);

      this.cordova
          .getActivity()
          .runOnUiThread(
              new Runnable() {
                @Override
                public void run() {
                  String result = "";
                  // SELF
                  if (SELF.equals(target)) {
                    Log.d(LOG_TAG, "in self");
                    // load in webview
                    if (url.startsWith("file://")
                        || url.startsWith("javascript:")
                        || Config.isUrlWhiteListed(url)) {
                      webView.loadUrl(url);
                    }
                    // Load the dialer
                    else if (url.startsWith(AmazonWebView.SCHEME_TEL)) {
                      try {
                        Intent intent = new Intent(Intent.ACTION_DIAL);
                        intent.setData(Uri.parse(url));
                        cordova.getActivity().startActivity(intent);
                      } catch (android.content.ActivityNotFoundException e) {
                        LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
                      }
                    }
                    // load in InAppBrowser
                    else {
                      result = showWebPage(url, features);
                    }
                  }
                  // SYSTEM
                  else if (SYSTEM.equals(target)) {
                    Log.d(LOG_TAG, "in system");
                    result = openExternal(url);
                  }
                  // BLANK - or anything else
                  else {
                    Log.d(LOG_TAG, "in blank");
                    result = showWebPage(url, features);
                  }

                  PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, result);
                  pluginResult.setKeepCallback(true);
                  callbackContext.sendPluginResult(pluginResult);
                }
              });
    } else if (action.equals("close")) {
      closeDialog();
    } else if (action.equals("injectScriptCode")) {
      String jsWrapper = null;
      if (args.getBoolean(1)) {
        jsWrapper =
            String.format(
                "prompt(JSON.stringify([eval(%%s)]), 'gap-iab://%s')",
                callbackContext.getCallbackId());
      }
      injectDeferredObject(args.getString(0), jsWrapper);
    } else if (action.equals("injectScriptFile")) {
      String jsWrapper;
      if (args.getBoolean(1)) {
        jsWrapper =
            String.format(
                "(function(d) { var c = d.createElement('script'); c.src = %%s; c.onload = function() { prompt('', 'gap-iab://%s'); }; d.body.appendChild(c); })(document)",
                callbackContext.getCallbackId());
      } else {
        jsWrapper =
            "(function(d) { var c = d.createElement('script'); c.src = %s; d.body.appendChild(c); })(document)";
      }
      injectDeferredObject(args.getString(0), jsWrapper);
    } else if (action.equals("injectStyleCode")) {
      String jsWrapper;
      if (args.getBoolean(1)) {
        jsWrapper =
            String.format(
                "(function(d) { var c = d.createElement('style'); c.innerHTML = %%s; d.body.appendChild(c); prompt('', 'gap-iab://%s');})(document)",
                callbackContext.getCallbackId());
      } else {
        jsWrapper =
            "(function(d) { var c = d.createElement('style'); c.innerHTML = %s; d.body.appendChild(c); })(document)";
      }
      injectDeferredObject(args.getString(0), jsWrapper);
    } else if (action.equals("injectStyleFile")) {
      String jsWrapper;
      if (args.getBoolean(1)) {
        jsWrapper =
            String.format(
                "(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%s; d.head.appendChild(c); prompt('', 'gap-iab://%s');})(document)",
                callbackContext.getCallbackId());
      } else {
        jsWrapper =
            "(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %s; d.head.appendChild(c); })(document)";
      }
      injectDeferredObject(args.getString(0), jsWrapper);
    } else if (action.equals("show")) {
      this.cordova
          .getActivity()
          .runOnUiThread(
              new Runnable() {
                @Override
                public void run() {
                  dialog.show();
                }
              });
      PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
      pluginResult.setKeepCallback(true);
      this.callbackContext.sendPluginResult(pluginResult);
    } else {
      return false;
    }
    return true;
  }