teaching machines

CS 436 Lecture 23 – Maps

November 18, 2014 by . Filed under cs436, fall 2014, lectures.

Code

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:context=".MainActivity">

  <TextView
    android:text="@string/hello_world"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

  <fragment
    android:id="@+id/map"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:name="com.google.android.gms.maps.MapFragment"/>

  <ProgressBar
    style="?android:attr/progressBarStyleLarge"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/progressBar"
    android:layout_centerVertical="true"
    android:layout_centerHorizontal="true"
    android:visibility="gone"/>

</RelativeLayout>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="org.twodee.donde">

  <uses-permission android:name="android.permission.INTERNET"/>
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

  <uses-feature
    android:glEsVersion="0x00020000"
    android:required="true"/>

  <application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme">
    <activity
      android:name="org.twodee.donde.MainActivity"
      android:label="@string/app_name">
      <intent-filter>
        <action android:name="android.intent.action.MAIN"/>

        <category android:name="android.intent.category.LAUNCHER"/>
      </intent-filter>
    </activity>

    <meta-data
      android:name="com.google.android.gms.version"
      android:value="@integer/google_play_services_version"/>

    <meta-data
      android:name="com.google.android.maps.v2.API_KEY"
      android:value="YOUR-API-KEY"/>
  </application>

</manifest>

Utilities.java

package org.twodee.donde;

import org.json.JSONException;

import java.io.IOException;
import java.io.InputStream;

public class Utilities {
  public static String slurp(InputStream is) throws IOException, JSONException {
    StringBuilder sb = new StringBuilder();
    byte[] bytes = new byte[1024];

    int nBytes;
    while ((nBytes = is.read(bytes)) > 0) {
      sb.append(new String(bytes, 0, nBytes));
    }

    return sb.toString();
  }
}

Placemark.java

package org.twodee.donde;

import com.google.android.gms.maps.model.LatLng;

import java.util.ArrayList;

public class Placemark {
  private ArrayList<String> names;
  private String placeName;
  private LatLng location;

  public Placemark(String placeName) {
    this.names = new ArrayList<String>();
    this.placeName = placeName;
  }

  public ArrayList<String> getNames() {
    return names;
  }

  public void addName(String name) {
    names.add(name);
  }

  public String getPlaceName() {
    return placeName;
  }

  public LatLng getLocation() {
    return location;
  }

  public void setLocation(LatLng location) {
    this.location = location;
  }

  public String toString() {
    return String.format("%s|%s|%s", names.toString(), placeName, location);
  }
}

MainActivity.java

package org.twodee.donde;

import android.app.Activity;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.ProgressBar;

import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;


public class MainActivity extends Activity {
  private GoogleMap map;
  private ProgressBar progressBar;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    progressBar = (ProgressBar) findViewById(R.id.progressBar);

    MapFragment mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map);
    map = mapFragment.getMap();

    map.setMapType(GoogleMap.MAP_TYPE_HYBRID);

    new PlacemarkLoader().execute();
  }

  class PlacemarkLoader extends AsyncTask<Void, Placemark, ArrayList<Placemark>> {
    @Override
    protected ArrayList<Placemark> doInBackground(Void... params) {

      try {
        HashMap<String, Placemark> placeToPlacemarks = new HashMap<String, Placemark>();
        File csv = new File(Environment.getExternalStorageDirectory(), "donde.csv");
        loadPlacemarks(csv, placeToPlacemarks);

        ArrayList<Placemark> placemarks = new ArrayList<Placemark>(placeToPlacemarks.values());
        locatePlacemarks(placemarks);

        return placemarks;
      } catch (Exception e) {
        Log.e("FOO", e.getMessage());
      }

      return null;
    }

    @Override
    protected void onPreExecute() {
      super.onPreExecute();
      progressBar.setVisibility(View.VISIBLE);
    }

    @Override
    protected void onPostExecute(ArrayList<Placemark> placemarks) {
      super.onPostExecute(placemarks);
      progressBar.setVisibility(View.GONE);
    }

    @Override
    protected void onProgressUpdate(Placemark... values) {
      super.onProgressUpdate(values);

      Placemark placemark = values[0];
      Log.d("FOO", placemark.toString());
      if (placemark.getLocation() != null) {
        MarkerOptions marker = new MarkerOptions();
        marker.position(placemark.getLocation());
        marker.title(placemark.getPlaceName());
        marker.snippet(placemark.getNames().toString());
        map.addMarker(marker);
      }
    }

    private void loadPlacemarks(File csv,
                                HashMap<String, Placemark> placeToPlacemarks) throws FileNotFoundException {
      Scanner in = new Scanner(csv);

      while (in.hasNextLine()) {
        String[] fields = in.nextLine().split("\\|");
        String name = fields[0];
        String place = fields[1];

        Placemark placemark = placeToPlacemarks.get(place);
        if (placemark == null) {
          placemark = new Placemark(place);
          placeToPlacemarks.put(place, placemark);
        }

        placemark.addName(name);
      }

      in.close();

      Log.d("FOO", "LOAD: " + placeToPlacemarks.toString());

    }

    private void locatePlacemarks(ArrayList<Placemark> placemarks) throws IOException, JSONException, InterruptedException {
      Log.d("FOO", "LOCATE: " + placemarks.toString());
      for (Placemark placemark : placemarks) {
        Uri.Builder builder = new Uri.Builder();
        builder.scheme("https");
        builder.authority("maps.googleapis.com");
        builder.appendEncodedPath("maps/api/geocode/json");
        builder.appendQueryParameter("address", placemark.getPlaceName());
        String urlString = builder.build().toString();
        URL url = new URL(urlString);

        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");

        InputStream is = connection.getInputStream();
        String body = Utilities.slurp(is);
        JSONObject json = new JSONObject(body);
        JSONArray results = json.getJSONArray("results");
        JSONObject result = results.getJSONObject(0);
        JSONObject geometry = result.getJSONObject("geometry");
        JSONObject location = geometry.getJSONObject("location");

        double latitude = location.getDouble("lat");
        double longitude = location.getDouble("lng");

        LatLng ll = new LatLng(latitude, longitude);
        placemark.setLocation(ll);

        publishProgress(placemark);

        Thread.sleep(300);
      }
    }
  }
}