6 package com.google.appinventor.components.runtime;
8 import android.app.Activity;
9 import android.util.Log;
20 import org.json.JSONArray;
21 import org.json.JSONException;
22 import org.json.JSONObject;
24 import java.io.BufferedReader;
25 import java.io.IOException;
26 import java.io.InputStreamReader;
27 import java.net.HttpURLConnection;
28 import java.net.MalformedURLException;
30 import java.net.URLConnection;
31 import java.util.ArrayList;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.ListIterator;
35 import java.util.concurrent.CopyOnWriteArrayList;
45 private static final int ERROR_CODE_MALFORMED_URL = -1;
46 private static final int ERROR_CODE_IO_EXCEPTION = -2;
47 private static final int ERROR_CODE_MALFORMED_GEOJSON = -3;
48 private static final int ERROR_CODE_UNKNOWN_TYPE = -4;
49 private static final String ERROR_MALFORMED_URL =
"The URL is malformed";
50 private static final String ERROR_IO_EXCEPTION =
"Unable to download content from URL";
51 private static final String ERROR_MALFORMED_GEOJSON =
"Malformed GeoJSON response. Expected FeatureCollection as root element.";
52 private static final String ERROR_UNKNOWN_TYPE =
"Unrecognized/invalid type in JSON object";
53 private static final String GEOJSON_TYPE =
"type";
54 private static final String GEOJSON_FEATURECOLLECTION =
"FeatureCollection";
55 private static final String GEOJSON_GEOMETRYCOLLECTION =
"GeometryCollection";
56 private static final String GEOJSON_FEATURES =
"features";
62 protected List<MapFeature>
features =
new CopyOnWriteArrayList<MapFeature>();
73 addFeature(lineString);
78 public Void visit(MapFactory.MapPolygon polygon, Object... arguments) {
84 public Void visit(MapFactory.MapCircle circle, Object... arguments) {
90 public Void visit(MapFactory.MapRectangle rectangle, Object... arguments) {
91 addFeature(rectangle);
96 @SuppressWarnings(
"WeakerAccess")
109 feature.removeFromMap();
111 this.features.clear();
112 ListIterator<?> it =
features.listIterator(1);
113 while (it.hasNext()) {
114 Object o = it.next();
130 description =
"The list of features placed on this %type%. This list also includes any " +
131 "features created by calls to FeatureFromDescription")
144 @
SimpleEvent(description =
"The user clicked on a map feature.")
160 @
SimpleEvent(description =
"The user long-pressed on a map feature.")
176 @
SimpleEvent(description =
"The user started dragging a map feature.")
192 @
SimpleEvent(description =
"The user dragged a map feature.")
208 @
SimpleEvent(description =
"The user stopped dragging a map feature.")
225 @
SimpleFunction(description =
"<p>Load a feature collection in " +
226 "<a href=\"https://en.wikipedia.org/wiki/GeoJSON\">GeoJSON</a> format from the given " +
227 "url. On success, the event GotFeatures will be raised with the given url and a list of " +
228 "the features parsed from the GeoJSON as a list of (key, value) pairs. On failure, the " +
229 "LoadError event will be raised with any applicable HTTP response code and error " +
263 return processGeoJSONFeature(TAG,
this, description);
264 }
catch(IllegalArgumentException e) {
266 ERROR_CODE_MALFORMED_GEOJSON, e.getMessage());
267 return e.getMessage();
280 @
SimpleEvent(description =
"A GeoJSON document was successfully read from url. The features " +
281 "specified in the document are provided as a list in features.")
287 while (it.hasNext()) {
299 @
SimpleEvent(description =
"An error was encountered while processing a GeoJSON document at " +
300 "the given url. The responseCode parameter will contain an HTTP status code and the " +
301 "errorMessage parameter will contain a detailed error message.")
302 public
void LoadError(String url,
int responseCode, String errorMessage) {
306 if (url.startsWith(
"file:")) {
328 throw new UnsupportedOperationException(
"Map.$add() called");
333 throw new UnsupportedOperationException(
"Map.setChildWidth called");
338 throw new UnsupportedOperationException(
"Map.setChildHeight called");
353 getMap().addFeature(marker);
356 void addFeature(MapFactory.MapLineString polyline) {
358 getMap().addFeature(polyline);
361 void addFeature(MapFactory.MapPolygon polygon) {
363 getMap().addFeature(polygon);
366 void addFeature(MapFactory.MapCircle circle) {
368 getMap().addFeature(circle);
371 void addFeature(MapFactory.MapRectangle rectangle) {
373 getMap().addFeature(rectangle);
378 feature.accept(featureAdder);
381 private void performGet(
final String url) {
383 String jsonContent = loadUrl(url);
384 if (jsonContent ==
null) {
388 }
catch(Exception e) {
389 Log.e(TAG,
"Exception retreiving GeoJSON", e);
395 private String loadUrl(
final String url) {
397 URLConnection connection =
new URL(url).openConnection();
398 connection.connect();
399 if (connection instanceof HttpURLConnection) {
400 HttpURLConnection conn = (HttpURLConnection) connection;
401 final int responseCode = conn.getResponseCode();
402 final String responseMessage = conn.getResponseMessage();
403 if (responseCode != 200) {
404 $form().runOnUiThread(
new Runnable() {
413 BufferedReader reader =
new BufferedReader(
new InputStreamReader(connection.getInputStream(),
415 StringBuilder content =
new StringBuilder();
417 while ((line = reader.readLine()) !=
null) {
418 content.append(line);
419 content.append(
"\n");
422 return content.toString();
423 }
catch(MalformedURLException e) {
424 $form().runOnUiThread(
new Runnable() {
427 ERROR_MALFORMED_URL);
430 }
catch (IOException e) {
431 $form().runOnUiThread(
new Runnable() {
441 @SuppressWarnings(
"WeakerAccess")
442 protected
void processGeoJSON(final String url, final String content) throws JSONException {
443 String type = getGeoJSONType(content, GEOJSON_TYPE);
444 if (!GEOJSON_FEATURECOLLECTION.equals(type) && !GEOJSON_GEOMETRYCOLLECTION.equals(type)) {
445 $form().runOnUiThread(
new Runnable() {
448 ERROR_MALFORMED_GEOJSON);
453 final List<YailList> yailFeatures = getGeoJSONFeatures(TAG, content);
454 $form().runOnUiThread(
new Runnable() {