Java tutorial
/* * Copyright [2012] [Dina Zuko, Simon Fransson] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package com.chalmers.schmaps; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.app.Dialog; import android.content.Context; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.location.Criteria; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import com.google.android.maps.GeoPoint; import com.google.android.maps.MapActivity; import com.google.android.maps.MapController; import com.google.android.maps.MapView; import com.google.android.maps.Overlay; import com.google.android.maps.OverlayItem; /***************************************************** * Class displays a google maps activity with a textfield and search button where user can search for classrooms. * Displays users position, rooms position if found and get directions from google directions api if user wants directions. *********************************************************/ public class GoogleMapSearchLocation extends MapActivity implements View.OnClickListener { private static final double CONVERTTOGEOPOINTVALUE = 1E6; private static final int OVERVIEWZOOMVALUE = 18; private static final long UPDATEFREQUENCYINMS = 1000; private static final float UPDATEAAREA = 10; private static final long SLEEPTIMEINMS = 500; private EditText lectureEdit; private GeoPoint ourLocation, roomLocation; private LocationManager locationManager; private LocationListener locationListener; private List<Overlay> mapOverlays; private MapItemizedOverlay mapItemizedRoom, mapItemizedStudent; private MapView mapView; private SearchSQL search; private Location location; private int longitude; private int latitude; private JSONObject jsonObject; private OverlayItem overlayitemStudent, overlayItemRoom; private MapController mapcon; private PathOverlay pathOverlay; private boolean roomSearched; private Dialog dialog; private List<GeoPoint> geoList; private boolean running; private String roomToFind; /** * onCreate method for determining what the activity does on creation. * Sets the right view for the user and assigns fields used by the activity. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //initiate the variables used in this class assignInstances(); //if there is an provider that provides an location ->continue if (location != null) { //get the latitude latitude = (int) (location.getLatitude() * CONVERTTOGEOPOINTVALUE); //get the longitude longitude = (int) (location.getLongitude() * CONVERTTOGEOPOINTVALUE); //greates an geopoint with our location ourLocation = new GeoPoint(latitude, longitude); mapcon = mapView.getController(); mapcon.animateTo(ourLocation); //zoom level mapcon.setZoom(OVERVIEWZOOMVALUE); //creates a MapItemizedOverlay-object and adds it to the list mapOverlays overlayitemStudent = new OverlayItem(ourLocation, "Hey amigo", "This is your position!"); mapItemizedStudent.addOverlay(overlayitemStudent); mapOverlays.add(mapItemizedStudent); } locationListener = new LocationListener() { /** * method is called when location is changed */ public void onLocationChanged(Location loc) { //get the latitude latitude = (int) (location.getLatitude() * CONVERTTOGEOPOINTVALUE); //get the longitude longitude = (int) (location.getLongitude() * CONVERTTOGEOPOINTVALUE); //greates an geopoint with our location ourLocation = new GeoPoint(latitude, longitude); //creates a MapItemizedOverlay-object and adds it to the list mapOverlays overlayitemStudent = new OverlayItem(ourLocation, "Hey amigo", "This is your position!"); mapItemizedStudent.addOverlay(overlayitemStudent); mapOverlays.add(mapItemizedStudent); } public void onProviderDisabled(String arg0) { } public void onProviderEnabled(String provider) { } public void onStatusChanged(String provider, int status, Bundle extras) { } }; //creates a SQLLite object search = new SearchSQL(GoogleMapSearchLocation.this); //creates an database search.createDatabase(); } /** * A simple check to see if a route is currently displayed * @return - boolean says if route displayed or not */ @Override protected boolean isRouteDisplayed() { return false; } /** * Method to define what the activity does on pause. Removes updates from the * location manager */ @Override protected void onPause() { super.onPause(); locationManager.removeUpdates(locationListener); } /** * Method to define what the activity does on resume. * Updates the coordinates of the current position. */ @Override protected void onResume() { super.onResume(); try { locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, UPDATEFREQUENCYINMS, UPDATEAAREA, locationListener); } catch (Exception e) { } } /** * method is called from onCreate() and it initiates the variables * used in GoogleMapSearchLocation */ private void assignInstances() { setContentView(R.layout.activity_map); //Fields used only once. Button editButton, directionsButton; Criteria criteria; String bestProvider; Drawable room, student; mapView = (MapView) findViewById(R.id.mapview); mapView.setBuiltInZoomControls(true); mapOverlays = mapView.getOverlays(); room = this.getResources().getDrawable(R.drawable.dot); student = this.getResources().getDrawable(R.drawable.chalmersandroid); mapItemizedRoom = new MapItemizedOverlay(room, this); mapItemizedStudent = new MapItemizedOverlay(student, this); editButton = (Button) findViewById(R.id.edittextbutton); directionsButton = (Button) findViewById(R.id.directionbutton); lectureEdit = (EditText) findViewById(R.id.edittextlecture); editButton.setOnClickListener(this); directionsButton.setOnClickListener(this); locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); //deafult criteria criteria = new Criteria(); //best reception bestProvider = locationManager.getBestProvider(criteria, false); //gets last known location from chosen provider location = locationManager.getLastKnownLocation(bestProvider); roomSearched = false; running = false; } /** * If the enter button is clicked a room search is done * If the get directions button is pressed you get the path drawn on map * but you have to search for a room first */ public void onClick(View v) { switch (v.getId()) { case R.id.edittextbutton: //Removes the key when finish typing InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(lectureEdit.getWindowToken(), 0); //removes the path drawn if there is one mapOverlays.remove(pathOverlay); //removes the dot that point to a previous room found mapOverlays.remove(mapItemizedRoom); roomToFind = lectureEdit.getText().toString(); //removes white signs and converts to lower case roomToFind.toLowerCase().trim(); //Removes illegal characters to prevent sql injection roomToFind = roomToFind.replaceAll("[^[a-z][A-Z][0-9]]", ""); //Set the field variable so it can be tested. setRoomToFind(roomToFind); //open database in read mode search.openRead(); //if we find room show room on map, if not show dialog if (search.exists(roomToFind)) { //create a geopoint roomLocation = new GeoPoint(search.getLat(roomToFind), search.getLong(roomToFind)); mapcon = mapView.getController(); mapcon.animateTo(roomLocation); //zoom level mapcon.setZoom(OVERVIEWZOOMVALUE); //address and level is shown in the dialog overlayItemRoom = new OverlayItem(roomLocation, search.getAddress(roomToFind), search.getLevel(roomToFind)); mapItemizedRoom.removeOverlay(); mapItemizedRoom.addOverlay(overlayItemRoom); mapOverlays.add(mapItemizedRoom); mapView.postInvalidate(); //now someone has searched for a room, set the boolean to true roomSearched = true; } else { //dilaog pops up if room not found dialog = new Dialog(GoogleMapSearchLocation.this); dialog.setTitle("Sorry, can not find the room :("); dialog.setCanceledOnTouchOutside(true); dialog.show(); } //close database search.close(); break; case R.id.directionbutton: Log.e("roomsearched", "in"); //if there there is roomLocation then search for a path //if not a roomLocation then the user has not searched for a room, do not give directions if (gotInternetConnection()) { Log.e("roomsearched", "inin"); if (roomSearched) { walkningDirections(); roomSearched = false; } else { Context context = getApplicationContext(); Toast.makeText(context, "Search for a room first to get directions", Toast.LENGTH_LONG).show(); } } else { Context context = getApplicationContext(); Toast.makeText(context, "Internet connection needed for this option", Toast.LENGTH_LONG).show(); } break; } } /** * @return the size of geoList with geopoints used to draw path */ public int returnNrOfGeopoints() { return geoList.size(); } /** * Returns the latest query from the user. * @return - String containing the user's query. */ public String getRoomToFind() { return roomToFind; } /** * Setting a field variable containing the latest query from the user. * @param roomToFind - String with the user's query. */ public void setRoomToFind(String roomToFind) { this.roomToFind = roomToFind; } /*********************************************** * creates a new thread (from where we get the directions) and calls it * waits for the new thread to return a json object * when json object returned parse it and extract directions in parseJson() ********************************************/ public void walkningDirections() { jsonObject = null; GetDirections directions = new GetDirections(); //the method doInBackground() in GetDirections is executed directions.execute(); //if json object not returned, sleep for 0,5 sec while (jsonObject == null) { try { Thread.sleep(SLEEPTIMEINMS); } catch (InterruptedException e1) { } } running = true; parseJson(jsonObject); } /** * Parses json response from google directions api * @param returnedJson */ public void parseJson(JSONObject returnedJson) { JSONObject step, startLocation, endLocation; int srcLat, srcLng, destLat, destLng; GeoPoint geo; geoList = new ArrayList<GeoPoint>(); try { JSONArray routes = returnedJson.getJSONArray("routes"); JSONObject route = routes.getJSONObject(0); // Take all legs from the route JSONArray legs = route.getJSONArray("legs"); // Grab first leg JSONObject leg = legs.getJSONObject(0); //Grab all the steps from the led JSONArray steps = leg.getJSONArray("steps"); for (int count = 0; count < steps.length(); count++) { Log.e("Json", "b"); //the json returns start and end for each step, we only want one geopoint of each position //that is why we only get the start once and then get the end // we add the geopoint to an array of geopoints if (count == 0) { step = steps.getJSONObject(0); startLocation = step.getJSONObject("start_location"); srcLat = (int) (startLocation.getDouble("lat") * CONVERTTOGEOPOINTVALUE); srcLng = (int) (startLocation.getDouble("lng") * CONVERTTOGEOPOINTVALUE); geo = new GeoPoint(srcLat, srcLng); geoList.add(0, geo); } step = steps.getJSONObject(count); endLocation = step.getJSONObject("end_location"); destLat = (int) (endLocation.getDouble("lat") * CONVERTTOGEOPOINTVALUE); destLng = (int) (endLocation.getDouble("lng") * CONVERTTOGEOPOINTVALUE); geo = new GeoPoint(destLat, destLng); geoList.add(count + 1, geo); } //creata an overlay and canvas so we can draw the path pathOverlay = new PathOverlay(geoList); Canvas canvas = new Canvas(); //adds the overay to the list of overlays and calls the draw-method to dra it mapOverlays.add(pathOverlay); pathOverlay.draw(canvas, mapView, true); mapView.postInvalidate(); } catch (JSONException e) { } } /** * @return true if the doinbackground() in asynktask has executed */ public boolean getIsAsyncTaskRunning() { return running; } /** this innerclass creates a new thread from where we can make a request * to google directions api - to get the directions * inspired by * http://www.vogella.com/articles/AndroidPerformance/article.html */ private class GetDirections extends AsyncTask<Void, Void, JSONObject> { private static final double CONVERTTOJSONVALUE = 1.0E6; /** when called makes a request to google directions api (json format) * gets the response back * convertes the response to a jsonobject */ @Override protected JSONObject doInBackground(Void... params) { StringBuilder urlString = new StringBuilder(); StringBuilder response = new StringBuilder(); InputStream is = null; URL url = null; HttpURLConnection urlConnection = null; String line = null; String jsonResponse = ""; //Create a string with the right start and end position urlString.append("http://maps.googleapis.com/maps/api/directions/json?origin="); //from, your position, latitude urlString.append(Double.toString((double) ourLocation.getLatitudeE6() / CONVERTTOJSONVALUE)); urlString.append(","); //longitude urlString.append(Double.toString((double) ourLocation.getLongitudeE6() / CONVERTTOJSONVALUE)); // to, where you are going urlString.append("&destination="); //latitude urlString.append(Double.toString((double) roomLocation.getLatitudeE6() / CONVERTTOJSONVALUE)); urlString.append(","); //longitude urlString.append(Double.toString((double) roomLocation.getLongitudeE6() / CONVERTTOJSONVALUE)); //we want the walking directions urlString.append("&sensor=false&avoid=highways&mode=walking"); //establish a connection with google directions api try { url = new URL(urlString.toString()); urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setRequestMethod("GET"); urlConnection.setDoOutput(true); urlConnection.setDoInput(true); is = urlConnection.getInputStream(); urlConnection.connect(); } catch (MalformedURLException e) { } catch (IOException e) { } //read from the buffer line by line and save in response (a stringbuider) try { InputStreamReader inputStream = new InputStreamReader(is); BufferedReader reader = new BufferedReader(inputStream); while ((line = reader.readLine()) != null) { response.append(line); } //Close the reader, stream & connection reader.close(); inputStream.close(); urlConnection.disconnect(); } catch (Exception e) { Log.e("Buffer Error", "Error converting result " + e.toString()); } jsonResponse = response.toString(); //convert string to jsonobject and return the object try { jsonObject = new JSONObject(jsonResponse); } catch (JSONException e) { } return jsonObject; } } /** * Check if the device is connected to internet. * Need three if-statements because getActiveNetworkInfo() may return null * and end up with a force close. So thats the last thing to check. * @return true if there is an internet connection */ public boolean gotInternetConnection() { ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo wifiNetwork = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI); if (wifiNetwork != null && wifiNetwork.isConnected()) { return true; } NetworkInfo mobileNetwork = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE); if (mobileNetwork != null && mobileNetwork.isConnected()) { return true; } NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); if (activeNetwork != null && activeNetwork.isConnected()) { return true; } return false; } }