diff --git a/CHANGELOG.md b/CHANGELOG.md index e44b00a..e987f0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# 3.3.0 (2020-03-25) + +- merge PR #54 "move Geocoding in an IntentService to not block the main thread" (closes #47, thank you @DavidWiesner) + +## ** BREAKING CHANGES ** +- remove dependency [Swift support plugin](https://github.com/akofman/cordova-plugin-add-swift-support); min Cordova iOS Version is now >5.0.0 + + # 3.2.2 (2019-04-14) - update cordova-plugin-add-swift-support to 2.0.2 (closes #45, thank you @DavidWiesner) diff --git a/README.md b/README.md index 8aa61fe..b77ee95 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ This plugin is also available for **[Ionic Native](https://ionicframework.com/do ``` cordova plugin add cordova-plugin-nativegeocoder ``` -The iOS part is written in Swift and the [Swift support plugin](https://github.com/akofman/cordova-plugin-add-swift-support) is configured as a dependency. +**For iOS Cordova iOS version >5.0.0 is required.** ## Configuration You can also configure the following variable to customize the iOS location plist entry diff --git a/package.json b/package.json index c2e09e4..61c3287 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cordova-plugin-nativegeocoder", - "version": "3.2.2", + "version": "3.3.0", "description": "Cordova plugin for native forward and reverse geocoding", "cordova": { "id": "cordova-plugin-nativegeocoder", diff --git a/plugin.xml b/plugin.xml index 77a26ae..3f0b045 100644 --- a/plugin.xml +++ b/plugin.xml @@ -1,5 +1,5 @@ - + NativeGeocoder Cordova plugin for native forward and reverse geocoding MIT @@ -22,7 +22,16 @@ - + + + + + + @@ -42,8 +51,5 @@ $LOCATION_WHEN_IN_USE_DESCRIPTION - - - diff --git a/src/android/GeocodingIntentService.java b/src/android/GeocodingIntentService.java new file mode 100644 index 0000000..5e2568f --- /dev/null +++ b/src/android/GeocodingIntentService.java @@ -0,0 +1,245 @@ +package cordova.plugin.nativegeocoder; + +import android.app.IntentService; +import android.content.Context; +import android.content.Intent; +import android.location.Address; +import android.location.Geocoder; +import android.location.Location; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Build; +import android.os.Bundle; +import android.os.ResultReceiver; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.util.List; +import java.util.Locale; + + +class NativeGeocoderOptions { + boolean useLocale = true; + String defaultLocale = null; + int maxResults = 1; +} + +public class GeocodingIntentService extends IntentService { + public static final String OPTIONS_DATA_EXTRA = "NATIVE_GEOCODER_OPTIONS_DATA_EXTRA"; + public static final String LOCATION_DATA_EXTRA = "NATIVE_GEOCODER_LOCATION_DATA_EXTRA"; + public static final String ADDRESS_STRING_DATA_EXTRA = "NATIVE_GEOCODER_ADDRESS_STRING_DATA_EXTRA"; + public static final String RECEIVER = "NATIVE_GEOCODER_RECEIVER"; + public static final int FAILURE_RESULT = 1; + public static final int SUCCESS_RESULT = 0; + public static final String RESULT_DATA_KEY = "NATIVE_GEOCODER_RECEIVER_RESULT_KEY"; + + public GeocodingIntentService() { + super("GeocodingIntentService"); + } + + @Override + protected void onHandleIntent(Intent intent) { + Location location = intent.getParcelableExtra(LOCATION_DATA_EXTRA); + String options = intent.getStringExtra(OPTIONS_DATA_EXTRA); + String addressString = intent.getStringExtra(ADDRESS_STRING_DATA_EXTRA); + ResultReceiver mReceiver = intent.getParcelableExtra(RECEIVER); + + NativeGeocoderOptions geocoderOptions = getNativeGeocoderOptions(options); + + try { + if (location != null) { + reverseGeocode(mReceiver, location, geocoderOptions); + } else { + forwardGeocode(mReceiver, addressString, geocoderOptions); + } + } catch (Exception e) { + String errorMsg = e.getMessage(); + if (e.getMessage().equals("grpc failed") && !isNetworkAvailable()) { + errorMsg = "No Internet Access"; + } + deliverResultToReceiver(mReceiver, FAILURE_RESULT, "Geocoder:getFromLocationName Error: " + errorMsg); + } + } + + /** + * Reverse geocode a given location to find location address + * @param mReceiver ResultReceiver + * @param location Location + * @param geocoderOptions NativeGeocoderOptions + */ + private void reverseGeocode(ResultReceiver mReceiver, Location location, NativeGeocoderOptions geocoderOptions) throws IOException { + Geocoder geocoder = createGeocoderWithOptions(geocoderOptions); + List
addresses = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), + geocoderOptions.maxResults); + if (addresses.size() > 0) { + JSONArray jsonAddresses = this.addressesToJSONArray(addresses, geocoderOptions.maxResults, false); + deliverResultToReceiver(mReceiver, SUCCESS_RESULT, jsonAddresses.toString()); + } else { + deliverResultToReceiver(mReceiver, FAILURE_RESULT, "Cannot get an address."); + } + } + + /** + * Forward geocode a given address to find coordinates + * @param mReceiver ResultReceiver + * @param addressString String + * @param geocoderOptions NativeGeocoderOptions + */ + private void forwardGeocode(ResultReceiver mReceiver, String addressString, NativeGeocoderOptions geocoderOptions) throws IOException { + Geocoder geocoder = createGeocoderWithOptions(geocoderOptions); + List
addresses = geocoder.getFromLocationName(addressString, geocoderOptions.maxResults); + if (addresses.size() > 0) { + JSONArray jsonAddresses = this.addressesToJSONArray(addresses, geocoderOptions.maxResults, true); + if (jsonAddresses.length() > 0) { + deliverResultToReceiver(mReceiver, SUCCESS_RESULT, jsonAddresses.toString()); + } else { + deliverResultToReceiver(mReceiver, FAILURE_RESULT, "Cannot get latitude and/or longitude."); + } + } else { + deliverResultToReceiver(mReceiver, FAILURE_RESULT, "Cannot find a location."); + } + } + + /** + * Send the decoding result back to the receiver + * @param mReceiver ResultReceiver + * @param resultCode int + * @param message String + */ + private void deliverResultToReceiver(ResultReceiver mReceiver, int resultCode, String message) { + Bundle bundle = new Bundle(); + bundle.putString(RESULT_DATA_KEY, message); + mReceiver.send(resultCode, bundle); + } + + /** + * Convert a list of addresses to a JSONArray + * @param addresses List
+ * @param maxResults int + * @param skipEmptyLocationResults boolean + * @return JSONArray + */ + private JSONArray addressesToJSONArray(List
addresses, int maxResults, boolean skipEmptyLocationResults) { + JSONArray resultArray = new JSONArray(); + int maxResultObjects = Math.min(addresses.size(), maxResults); + + for (int i = 0; i < maxResultObjects; i++) { + Address address = addresses.get(i); + + try { + String latitude = String.valueOf(address.getLatitude()); + String longitude = String.valueOf(address.getLongitude()); + + boolean hasLocation = !latitude.isEmpty() && !longitude.isEmpty(); + if (hasLocation || !skipEmptyLocationResults) { + // https://developer.android.com/reference/android/location/Address.html + JSONObject placemark = new JSONObject(); + placemark.put("latitude", latitude.isEmpty() ? "" : latitude); + placemark.put("longitude", longitude.isEmpty() ? "" : longitude); + placemark.put("countryCode", address.getCountryCode() != null ? address.getCountryCode() : ""); + placemark.put("countryName", address.getCountryName() != null ? address.getCountryName() : ""); + placemark.put("postalCode", address.getPostalCode() != null ? address.getPostalCode() : ""); + placemark.put("administrativeArea", address.getAdminArea() != null ? address.getAdminArea() : ""); + placemark.put("subAdministrativeArea", address.getSubAdminArea() != null ? address.getSubAdminArea() : ""); + placemark.put("locality", address.getLocality() != null ? address.getLocality() : ""); + placemark.put("subLocality", address.getSubLocality() != null ? address.getSubLocality() : ""); + placemark.put("thoroughfare", address.getThoroughfare() != null ? address.getThoroughfare() : ""); + placemark.put("subThoroughfare", address.getSubThoroughfare() != null ? address.getSubThoroughfare() : ""); + placemark.put("areasOfInterest", address.getFeatureName() != null ? new JSONArray(new String[]{address.getFeatureName()}) : new JSONArray()); + + resultArray.put(placemark); + } + } catch (JSONException | RuntimeException e) { + e.printStackTrace(); + } + } + return resultArray; + } + + /** + * Get a valid NativeGeocoderOptions object + * + * @param stringOptions String + * @return NativeGeocoderOptions + */ + private NativeGeocoderOptions getNativeGeocoderOptions(String stringOptions) { + NativeGeocoderOptions geocoderOptions = new NativeGeocoderOptions(); + + if (stringOptions != null) { + try { + JSONObject options = new JSONObject(stringOptions); + geocoderOptions.useLocale = !options.has("useLocale") || options.getBoolean("useLocale"); + if (options.has("defaultLocale")) { + geocoderOptions.defaultLocale = options.getString("defaultLocale"); + } else { + geocoderOptions.defaultLocale = null; + } + if (options.has("maxResults")) { + geocoderOptions.maxResults = options.getInt("maxResults"); + + if (geocoderOptions.maxResults > 0) { + int MAX_RESULTS_COUNT = 5; + geocoderOptions.maxResults = Math.min(geocoderOptions.maxResults, MAX_RESULTS_COUNT); + } else { + geocoderOptions.maxResults = 1; + } + + } else { + geocoderOptions.maxResults = 1; + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + + return geocoderOptions; + } + + /** + * Create a Geocoder with NativeGeocoderOptions + * + * @param geocoderOptions NativeGeocoderOptions + * @return Geocoder + */ + private Geocoder createGeocoderWithOptions(NativeGeocoderOptions geocoderOptions) { + if (geocoderOptions.defaultLocale != null && !geocoderOptions.defaultLocale.isEmpty()) { + Locale locale; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + locale = Locale.forLanguageTag(geocoderOptions.defaultLocale); + } else { + String[] parts = geocoderOptions.defaultLocale.split("[-_]", -1); + if (parts.length == 1) + locale = new Locale(parts[0]); + else if (parts.length == 2 || (parts.length == 3 && parts[2].startsWith("#"))) + locale = new Locale(parts[0], parts[1]); + else + locale = new Locale(parts[0], parts[1], parts[2]); + } + return new Geocoder(this, locale); + } else { + if (geocoderOptions.useLocale) { + return new Geocoder(this, Locale.getDefault()); + } else { + return new Geocoder(this, Locale.ENGLISH); + } + } + } + + /** + * Get network connection + * + * @return boolean + */ + private boolean isNetworkAvailable() { + ConnectivityManager connectivityManager = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo activeNetworkInfo = null; + if (connectivityManager != null) { + activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); + } + return activeNetworkInfo != null && activeNetworkInfo.isConnected(); + } + +} diff --git a/src/android/NativeGeocoder.java b/src/android/NativeGeocoder.java index aaffc66..53958b0 100644 --- a/src/android/NativeGeocoder.java +++ b/src/android/NativeGeocoder.java @@ -1,11 +1,12 @@ package cordova.plugin.nativegeocoder; -import android.content.Context; -import android.location.Address; +import android.content.Intent; import android.location.Geocoder; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.os.Build; +import android.location.Location; +import android.os.Bundle; +import android.os.Handler; +import android.os.ResultReceiver; + import org.apache.cordova.CallbackContext; import org.apache.cordova.CordovaInterface; import org.apache.cordova.CordovaPlugin; @@ -14,17 +15,9 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import java.util.List; -import java.util.Locale; -class NativeGeocoderOptions { - boolean useLocale = true; - String defaultLocale = null; - int maxResults = 1; -} public class NativeGeocoder extends CordovaPlugin { - private Geocoder geocoder; @Override public void initialize(CordovaInterface cordova, CordovaWebView webView) { @@ -41,9 +34,13 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo JSONObject options = null; try { options = args.getJSONObject(2); - } catch (JSONException e) { } + } catch (JSONException ignored) { } this.reverseGeocode(latitude, longitude, options, callbackContext); + + PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT); + r.setKeepCallback(true); + callbackContext.sendPluginResult(r); return true; } @@ -52,8 +49,12 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo JSONObject options = null; try { options = args.getJSONObject(1); - } catch (JSONException e) { } + } catch (JSONException ignored) { } this.forwardGeocode(addressString, options, callbackContext); + + PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT); + r.setKeepCallback(true); + callbackContext.sendPluginResult(r); return true; } @@ -67,7 +68,7 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo * @param options JSONObject * @param callbackContext CallbackContext */ - private void reverseGeocode(double latitude, double longitude, JSONObject options, CallbackContext callbackContext) throws JSONException{ + private void reverseGeocode(double latitude, double longitude, JSONObject options, CallbackContext callbackContext) { if (latitude == 0 || longitude == 0) { PluginResult r = new PluginResult(PluginResult.Status.ERROR, "Expected two non-empty double arguments."); @@ -80,51 +81,15 @@ private void reverseGeocode(double latitude, double longitude, JSONObject option callbackContext.sendPluginResult(r); return; } - - NativeGeocoderOptions geocoderOptions = getNativeGeocoderOptions(options); - geocoder = createGeocoderWithOptions(geocoderOptions); - - try { - List
geoResults = geocoder.getFromLocation(latitude, longitude, geocoderOptions.maxResults); - if (geoResults.size() > 0) { - int maxResultObjects = geoResults.size() >= geocoderOptions.maxResults ? geoResults.size() : geoResults.size(); - JSONArray resultObj = new JSONArray(); - - for (int i = 0; i < maxResultObjects; i++) { - Address address = geoResults.get(i); - - // https://developer.android.com/reference/android/location/Address.html - JSONObject placemark = new JSONObject(); - placemark.put("latitude", !String.valueOf(address.getLatitude()).isEmpty() ? address.getLatitude() : ""); - placemark.put("longitude", !String.valueOf(address.getLongitude()).isEmpty() ? address.getLongitude() : ""); - placemark.put("countryCode", address.getCountryCode() != null ? address.getCountryCode() : ""); - placemark.put("countryName", address.getCountryName() != null ? address.getCountryName() : ""); - placemark.put("postalCode", address.getPostalCode() != null ? address.getPostalCode() : ""); - placemark.put("administrativeArea", address.getAdminArea() != null ? address.getAdminArea() : ""); - placemark.put("subAdministrativeArea", address.getSubAdminArea() != null ? address.getSubAdminArea() : ""); - placemark.put("locality", address.getLocality() != null ? address.getLocality() : ""); - placemark.put("subLocality", address.getSubLocality() != null ? address.getSubLocality() : ""); - placemark.put("thoroughfare", address.getThoroughfare() != null ? address.getThoroughfare() : ""); - placemark.put("subThoroughfare", address.getSubThoroughfare() != null ? address.getSubThoroughfare() : ""); - placemark.put("areasOfInterest", address.getFeatureName() != null ? new JSONArray(new String[]{ address.getFeatureName()} ) : new JSONArray()); - - resultObj.put(placemark); - } - - callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, resultObj)); - } else { - PluginResult r = new PluginResult(PluginResult.Status.ERROR, "Cannot get an address."); - callbackContext.sendPluginResult(r); - } - } - catch (Exception e) { - String errorMsg = e.getMessage(); - if (e.getMessage().equals("grpc failed") && !isNetworkAvailable()) { - errorMsg = "No Internet Access"; - } - PluginResult r = new PluginResult(PluginResult.Status.ERROR, "Geocoder:getFromLocationName Error: " + errorMsg); - callbackContext.sendPluginResult(r); - } + Location location = new Location(""); + location.setLatitude(latitude); + location.setLongitude(longitude); + + Intent intent = new Intent(this.cordova.getActivity(), GeocodingIntentService.class); + intent.putExtra(GeocodingIntentService.RECEIVER, new AddressResultReceiver(callbackContext)); + intent.putExtra(GeocodingIntentService.LOCATION_DATA_EXTRA, location); + intent.putExtra(GeocodingIntentService.OPTIONS_DATA_EXTRA, options.toString()); + this.cordova.getActivity().startService(intent); } @@ -134,7 +99,7 @@ private void reverseGeocode(double latitude, double longitude, JSONObject option * @param options JSONObject * @param callbackContext CallbackContext */ - private void forwardGeocode(String addressString, JSONObject options, CallbackContext callbackContext) throws JSONException { + private void forwardGeocode(String addressString, JSONObject options, CallbackContext callbackContext) { if (addressString == null || addressString.length() == 0) { PluginResult r = new PluginResult(PluginResult.Status.ERROR, "Expected a non-empty string argument."); callbackContext.sendPluginResult(r); @@ -147,148 +112,37 @@ private void forwardGeocode(String addressString, JSONObject options, CallbackCo return; } - NativeGeocoderOptions geocoderOptions = getNativeGeocoderOptions(options); - geocoder = createGeocoderWithOptions(geocoderOptions); - - try { - List
geoResults = geocoder.getFromLocationName(addressString, geocoderOptions.maxResults); - - if (geoResults.size() > 0) { - int maxResultObjects = geoResults.size() >= geocoderOptions.maxResults ? geoResults.size() : geoResults.size(); - JSONArray resultObj = new JSONArray(); - - for (int i = 0; i < maxResultObjects; i++) { - Address address = geoResults.get(i); - - try { - String latitude = String.valueOf(address.getLatitude()); - String longitude = String.valueOf(address.getLongitude()); - - if (!latitude.isEmpty() && !longitude.isEmpty()) { - // https://developer.android.com/reference/android/location/Address.html - JSONObject placemark = new JSONObject(); - placemark.put("latitude", latitude); - placemark.put("longitude", longitude); - placemark.put("countryCode", address.getCountryCode() != null ? address.getCountryCode() : ""); - placemark.put("countryName", address.getCountryName() != null ? address.getCountryName() : ""); - placemark.put("postalCode", address.getPostalCode() != null ? address.getPostalCode() : ""); - placemark.put("administrativeArea", address.getAdminArea() != null ? address.getAdminArea() : ""); - placemark.put("subAdministrativeArea", address.getSubAdminArea() != null ? address.getSubAdminArea() : ""); - placemark.put("locality", address.getLocality() != null ? address.getLocality() : ""); - placemark.put("subLocality", address.getSubLocality() != null ? address.getSubLocality() : ""); - placemark.put("thoroughfare", address.getThoroughfare() != null ? address.getThoroughfare() : ""); - placemark.put("subThoroughfare", address.getSubThoroughfare() != null ? address.getSubThoroughfare() : ""); - placemark.put("areasOfInterest", address.getFeatureName() != null ? new JSONArray(new String[]{ address.getFeatureName() }) : new JSONArray()); - - resultObj.put(placemark); - } - } - catch (RuntimeException e) { - e.printStackTrace(); - } - } - - if (resultObj.length() == 0) { - PluginResult r = new PluginResult(PluginResult.Status.ERROR, "Cannot get latitude and/or longitude."); - callbackContext.sendPluginResult(r); - } else { - callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, resultObj)); - } - - } else { - PluginResult r = new PluginResult(PluginResult.Status.ERROR, "Cannot find a location."); - callbackContext.sendPluginResult(r); - } - } - catch (Exception e) { - String errorMsg = e.getMessage(); - if (e.getMessage().equals("grpc failed") && !isNetworkAvailable()) { - errorMsg = "No Internet Access"; - } - PluginResult r = new PluginResult(PluginResult.Status.ERROR, "Geocoder:getFromLocationName Error: " + errorMsg); - callbackContext.sendPluginResult(r); - } - } - - /** - * Get network connection - * @return boolean - */ - private boolean isNetworkAvailable() { - ConnectivityManager connectivityManager - = (ConnectivityManager) cordova.getActivity().getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo activeNetworkInfo = null; - if (connectivityManager != null) { - activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); - } - return activeNetworkInfo != null && activeNetworkInfo.isConnected(); + Intent intent = new Intent(this.cordova.getActivity(), GeocodingIntentService.class); + intent.putExtra(GeocodingIntentService.RECEIVER, new AddressResultReceiver(callbackContext)); + intent.putExtra(GeocodingIntentService.ADDRESS_STRING_DATA_EXTRA, addressString); + intent.putExtra(GeocodingIntentService.OPTIONS_DATA_EXTRA, options.toString()); + this.cordova.getActivity().startService(intent); } - /** - * Get a valid NativeGeocoderOptions object - * @param options JSONObject - * @return NativeGeocoderOptions - */ - private NativeGeocoderOptions getNativeGeocoderOptions(JSONObject options) throws JSONException { - NativeGeocoderOptions geocoderOptions = new NativeGeocoderOptions(); - - if (options != null) { - geocoderOptions.useLocale = !options.has("useLocale") || options.getBoolean("useLocale"); - if (options.has("defaultLocale")) { - geocoderOptions.defaultLocale = options.getString("defaultLocale"); - } else { - geocoderOptions.defaultLocale = null; - } - if (options.has("maxResults")) { - geocoderOptions.maxResults = options.getInt("maxResults"); + static class AddressResultReceiver extends ResultReceiver { - if (geocoderOptions.maxResults > 0) { - int MAX_RESULTS_COUNT = 5; - geocoderOptions.maxResults = geocoderOptions.maxResults > MAX_RESULTS_COUNT ? MAX_RESULTS_COUNT : geocoderOptions.maxResults; - } else { - geocoderOptions.maxResults = 1; - } + private final CallbackContext callbackContext; - } else { - geocoderOptions.maxResults = 1; - } - } else { - geocoderOptions.useLocale = true; - geocoderOptions.defaultLocale = null; - geocoderOptions.maxResults = 1; + AddressResultReceiver(CallbackContext callbackContext) { + super(new Handler()); + this.callbackContext = callbackContext; } - return geocoderOptions; - } - - /** - * Create a Geocoder with NativeGeocoderOptions - * @param geocoderOptions NativeGeocoderOptions - * @return Geocoder - */ - private Geocoder createGeocoderWithOptions(NativeGeocoderOptions geocoderOptions) { - if (geocoderOptions.defaultLocale != null && !geocoderOptions.defaultLocale.isEmpty()) { - Locale locale; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - locale = Locale.forLanguageTag(geocoderOptions.defaultLocale); + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + String result = resultData.getString(GeocodingIntentService.RESULT_DATA_KEY); + PluginResult pluginResult; + if (resultCode == GeocodingIntentService.FAILURE_RESULT) { + pluginResult = new PluginResult(PluginResult.Status.ERROR, result); } else { - String parts[] = geocoderOptions.defaultLocale.split("[-_]", -1); - if (parts.length == 1) - locale = new Locale(parts[0]); - else if (parts.length == 2 || (parts.length == 3 && parts[2].startsWith("#"))) - locale = new Locale(parts[0], parts[1]); - else - locale = new Locale(parts[0], parts[1], parts[2]); - } - geocoder = new Geocoder(cordova.getActivity().getApplicationContext(), locale); - } else { - if (geocoderOptions.useLocale) { - geocoder = new Geocoder(cordova.getActivity().getApplicationContext(), Locale.getDefault()); - } else { - geocoder = new Geocoder(cordova.getActivity().getApplicationContext(), Locale.ENGLISH); + try { + JSONArray json = new JSONArray(result); + pluginResult = new PluginResult(PluginResult.Status.OK, json); + } catch (JSONException e) { + pluginResult = new PluginResult(PluginResult.Status.ERROR, "can not parse result"); + } } + this.callbackContext.sendPluginResult(pluginResult); } - return geocoder; } - }