Java tutorial
/******************************************************************************* LocGenie An open source Android application that suggests users places of their preferred activity within their preferred distance in Map View along with their address. Copyright (C) 2014 Srividya Sundaram This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. Following is the link for the repository: https://github.com/Srividya2212/LocationFinder Please, see the file license in this distribution for license terms. Link is https://github.com/Srividya2212/LocationFinder/blob/master/LICENSE.md References: https://developers.google.com/maps/documentation/android/start#getting_the_google_maps_android_api_v2 https://developers.google.com/maps/documentation/android/ https://developers.google.com/places/documentation/ https://developers.google.com/places/documentation/search http://stackoverflow.com/questions/9605913/how-to-parse-json-in-android Author - Srividya Sundaram email: srividya@pdx.edu ******************************************************************************************/ package com.gmail.srivi.sundaram.locgenie; import com.gmail.srivi.sundaram.locgenie.R; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesClient; import com.google.android.gms.common.GooglePlayServicesUtil; import com.google.android.gms.location.LocationClient; import com.google.android.gms.location.LocationListener; import com.google.android.gms.location.LocationRequest; //import com.google.android.gms.maps.model.MarkerOptions; import android.content.Intent; import android.content.IntentSender; import android.location.Address; import android.location.Geocoder; import android.location.Location; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.drawable.AnimationDrawable; import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentActivity; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.EditText; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.TextView; import android.widget.Toast; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.List; import java.util.Locale; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.ResponseHandler; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.util.Log; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import android.os.AsyncTask; /** * This the app's main Activity. It provides buttons for requesting the various * features of the app, displays the current location, the current address, and * the status of the location client and updating services. hi * {@link #getLocation} gets the current location using the Location Services * getLastLocation() function. {@link #getAddress} calls geocoding to get a * street address for the current location. {@link #startUpdates} sends a * request to Location Services to send periodic location updates to the * Activity. {@link #stopUpdates} cancels previous periodic update requests. * * The update interval is hard-coded to be 5 seconds. */ public class MainActivity extends FragmentActivity implements LocationListener, GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener { // private int userIcon; public final static String EXTRA_MESSAGE = "com.android.location.suggestion.MESSAGE"; public final static String RADIUS = "com.android.location.suggestion.RADIUS"; public final static String ACTIVITY = "com.android.location.suggestion.ACTIVITY"; // A request to connect to Location Services private LocationRequest mLocationRequest; private LocationClient mLocationClient; // Handles to UI widgets private TextView mLatLng; private TextView mAddress; private ProgressBar mActivityIndicator; private TextView mConnectionState; private TextView mConnectionStatus; // Handle to SharedPreferences for this app SharedPreferences mPrefs; // Handle to a SharedPreferences editor SharedPreferences.Editor mEditor; boolean mUpdatesRequested = false; AnimationDrawable frameAnimation; ImageView view; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mLocationRequest = LocationRequest.create(); mLocationRequest.setInterval(LocationUtils.UPDATE_INTERVAL_IN_MILLISECONDS); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); mLocationRequest.setFastestInterval(LocationUtils.FAST_INTERVAL_CEILING_IN_MILLISECONDS); mUpdatesRequested = false; mPrefs = getSharedPreferences(LocationUtils.SHARED_PREFERENCES, Context.MODE_PRIVATE); mEditor = mPrefs.edit(); mLocationClient = new LocationClient(this, this, this); } /* @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { // Starting the animation when in Focus frameAnimation.start(); } else { frameAnimation.stop(); } }*/ /* * Called when the Activity is no longer visible at all. Stop updates and * disconnect. */ @Override public void onStop() { if (mLocationClient.isConnected()) { stopPeriodicUpdates(); } mLocationClient.disconnect(); super.onStop(); } /* * Called when the Activity is going into the background. Parts of the UI * may be visible, but the Activity is inactive. */ @Override public void onPause() { Log.d(" -->", "In onPause"); // Save the current setting for updates mEditor.putBoolean(LocationUtils.KEY_UPDATES_REQUESTED, mUpdatesRequested); mEditor.commit(); super.onPause(); } /* * Called when the Activity is restarted, even before it becomes visible. */ @Override public void onStart() { Log.d("2", "In onStart"); // Toast.makeText(this, "Inside Onstart()", Toast.LENGTH_SHORT).show(); super.onStart(); /* * Connect the client. Don't re-start any requests here; instead, wait * for onResume() */ mLocationClient.connect(); } /* * Called when the system detects that this Activity is now visible. */ @Override public void onResume() { super.onResume(); // If the app already has a setting for getting location updates, get it if (mPrefs.contains(LocationUtils.KEY_UPDATES_REQUESTED)) { mUpdatesRequested = mPrefs.getBoolean(LocationUtils.KEY_UPDATES_REQUESTED, false); // Otherwise, turn off location updates until requested } else { mEditor.putBoolean(LocationUtils.KEY_UPDATES_REQUESTED, false); mEditor.commit(); } } /* * Handle results returned to this Activity by other Activities started with * startActivityForResult(). In particular, the method onConnectionFailed() * in LocationUpdateRemover and LocationUpdateRequester may call * startResolutionForResult() to start an Activity that handles Google Play * services problems. The result of this call returns here, to * onActivityResult. */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { // Choose what to do based on the request code switch (requestCode) { // If the request code matches the code sent in onConnectionFailed case LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST: switch (resultCode) { // If Google Play services resolved the problem case Activity.RESULT_OK: // Log the result Log.d(LocationUtils.APPTAG, getString(R.string.resolved)); // Display the result // mConnectionState.setText(R.string.connected); // mConnectionStatus.setText(R.string.resolved); break; // If any other result was returned by Google Play services default: // Log the result Log.d(LocationUtils.APPTAG, getString(R.string.no_resolution)); // Display the result // mConnectionState.setText(R.string.disconnected); // mConnectionStatus.setText(R.string.no_resolution); break; } // If any other request code was received default: // Report that this Activity received an unknown requestCode Log.d(LocationUtils.APPTAG, getString(R.string.unknown_activity_request_code, requestCode)); break; } } /** * Verify that Google Play services is available before making a request. * * @return true if Google Play services is available, otherwise false */ private boolean servicesConnected() { // Check that Google Play services is available int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); // If Google Play services is available if (ConnectionResult.SUCCESS == resultCode) { // In debug mode, log the status Log.d(LocationUtils.APPTAG, getString(R.string.play_services_available)); // Continue return true; // Google Play services was not available for some reason } else { // Display an error dialog Dialog dialog = GooglePlayServicesUtil.getErrorDialog(resultCode, this, 0); if (dialog != null) { ErrorDialogFragment errorFragment = new ErrorDialogFragment(); errorFragment.setDialog(dialog); errorFragment.show(getSupportFragmentManager(), LocationUtils.APPTAG); } return false; } } /** * Invoked by the "Get Location" button. * * Calls getLastLocation() to get the current location * * @param v * The view object associated with this method, in this case a * Button. */ public void getLocation(View v) { // If Google Play Services is available if (servicesConnected()) { Log.d(" ", "In getLocation method"); // Toast.makeText(this, "Inside method getLocation()", // Toast.LENGTH_SHORT) // .show(); // Get the current location Location currentLocation = mLocationClient.getLastLocation(); // Display the current location in the UI mLatLng.setText(LocationUtils.getLatLng(this, currentLocation)); // Toast.makeText(this, LocationUtils.getLatLng(this, // currentLocation), Toast.LENGTH_SHORT).show(); } } // Invoked by Suggestions button public void getSuggestion(View v) { if (servicesConnected()) { Log.d(" ", "In getSuggestions_new"); EditText radius = (EditText) findViewById(R.id.editText1); String radiusCheck = radius.getText().toString(); // Getting the Selected Activity RadioGroup rg = (RadioGroup) findViewById(R.id.radioGroup1); RadioButton selected = (RadioButton) findViewById(rg.getCheckedRadioButtonId()); String activity = (String) selected.getText(); if (radiusCheck.isEmpty()) { Toast.makeText(this, "Please Enter Radius", Toast.LENGTH_SHORT).show(); } else { float miles = Float.valueOf(radius.getText().toString()); float meters = (float) (miles * 1609.344); String radiusInMeters = Float.toString(meters); Location currentLocation = mLocationClient.getLastLocation(); Intent intent = new Intent(getBaseContext(), DisplayPlacesActivity.class); intent.putExtra(EXTRA_MESSAGE, currentLocation); intent.putExtra(RADIUS, radiusInMeters); intent.putExtra(ACTIVITY, activity); startActivity(intent); } } } /** * Invoked by the "Get Address" button. Get the address of the current * location, using reverse geocoding. This only works if a geocoding service * is available. * * @param v * The view object associated with this method, in this case a * Button. */ // For Eclipse with ADT, suppress warnings about Geocoder.isPresent() @SuppressLint("NewApi") public void getAddress(View v) { // In Gingerbread and later, use Geocoder.isPresent() to see if a // geocoder is available. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD && !Geocoder.isPresent()) { // No geocoder is present. Issue an error message Toast.makeText(this, R.string.no_geocoder_available, Toast.LENGTH_LONG).show(); return; } if (servicesConnected()) { // Get the current location Location currentLocation = mLocationClient.getLastLocation(); // Turn the indefinite activity indicator on // mActivityIndicator.setVisibility(View.VISIBLE); // Start the background task (new MainActivity.GetAddressTask(this)).execute(currentLocation); } } /** * Invoked by the "Start Updates" button Sends a request to start location * updates * * @param v * The view object associated with this method, in this case a * Button. */ public void startUpdates(View v) { mUpdatesRequested = true; if (servicesConnected()) { startPeriodicUpdates(); } } /** * Invoked by the "Stop Updates" button Sends a request to remove location * updates request them. * * @param v * The view object associated with this method, in this case a * Button. */ public void stopUpdates(View v) { mUpdatesRequested = false; if (servicesConnected()) { stopPeriodicUpdates(); } } /* * Called by Location Services when the request to connect the client * finishes successfully. At this point, you can request the current * location or start periodic updates */ @Override public void onConnected(Bundle bundle) { Log.d(" ", "In onConnected"); // mConnectionStatus.setText(R.string.connected); // Toast.makeText(this, "Inside Onconnected()", // Toast.LENGTH_SHORT).show(); if (mUpdatesRequested) { startPeriodicUpdates(); } } /* * Called by Location Services if the connection to the location client * drops because of an error. */ @Override public void onDisconnected() { // mConnectionStatus.setText(R.string.disconnected); } /* * Called by Location Services if the attempt to Location Services fails. */ @Override public void onConnectionFailed(ConnectionResult connectionResult) { /* * Google Play services can resolve some errors it detects. If the error * has a resolution, try sending an Intent to start a Google Play * services activity that can resolve error. */ if (connectionResult.hasResolution()) { try { // Start an Activity that tries to resolve the error connectionResult.startResolutionForResult(this, LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST); /* * Thrown if Google Play services canceled the original * PendingIntent */ } catch (IntentSender.SendIntentException e) { // Log the error e.printStackTrace(); } } else { // If no resolution is available, display a dialog to the user with // the error. showErrorDialog(connectionResult.getErrorCode()); } } /** * Report location updates to the UI. * * @param location * The updated location. */ @Override public void onLocationChanged(Location location) { // Report to the UI that the location was updated // mConnectionStatus.setText(R.string.location_updated); // In the UI, set the latitude and longitude to the value received mLatLng.setText(LocationUtils.getLatLng(this, location)); } /** * In response to a request to start updates, send a request to Location * Services */ private void startPeriodicUpdates() { mLocationClient.requestLocationUpdates(mLocationRequest, this); // mConnectionState.setText(R.string.location_requested); } /** * In response to a request to stop updates, send a request to Location * Services */ private void stopPeriodicUpdates() { mLocationClient.removeLocationUpdates(this); // mConnectionState.setText(R.string.location_updates_stopped); } /** * An AsyncTask that calls getFromLocation() in the background. The class * uses the following generic types: Location - A * {@link android.location.Location} object containing the current location, * passed as the input parameter to doInBackground() Void - indicates that * progress units are not used by this subclass String - An address passed * to onPostExecute() */ protected class GetAddressTask extends AsyncTask<Location, Void, String> { // Store the context passed to the AsyncTask when the system // instantiates it. Context localContext; // Constructor called by the system to instantiate the task public GetAddressTask(Context context) { // Required by the semantics of AsyncTask super(); // Set a Context for the background task localContext = context; } /** * Get a geocoding service instance, pass latitude and longitude to it, * format the returned address, and return the address to the UI thread. */ @Override protected String doInBackground(Location... params) { /* * Get a new geocoding service instance, set for localized * addresses. This example uses android.location.Geocoder, but other * geocoders that conform to address standards can also be used. */ Geocoder geocoder = new Geocoder(localContext, Locale.getDefault()); // Get the current location from the input parameter list Location location = params[0]; // Create a list to contain the result address List<Address> addresses = null; // Try to get an address for the current location. Catch IO or // network problems. try { /* * Call the synchronous getFromLocation() method with the * latitude and longitude of the current location. Return at * most 1 address. */ addresses = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1); // Catch network or other I/O problems. } catch (IOException exception1) { // Log an error and return an error message Log.e(LocationUtils.APPTAG, getString(R.string.IO_Exception_getFromLocation)); // print the stack trace exception1.printStackTrace(); // Return an error message return (getString(R.string.IO_Exception_getFromLocation)); // Catch incorrect latitude or longitude values } catch (IllegalArgumentException exception2) { // Construct a message containing the invalid arguments String errorString = getString(R.string.illegal_argument_exception, location.getLatitude(), location.getLongitude()); // Log the error and print the stack trace Log.e(LocationUtils.APPTAG, errorString); exception2.printStackTrace(); // return errorString; } // If the reverse geocode returned an address if (addresses != null && addresses.size() > 0) { // Get the first address Address address = addresses.get(0); // Format the first line of address String addressText = getString(R.string.address_output_string, // If there's a street address, add it address.getMaxAddressLineIndex() > 0 ? address.getAddressLine(0) : "", // Locality is usually a city address.getLocality(), // The country of the address address.getCountryName()); // Return the text return addressText; // If there aren't any addresses, post a message } else { return getString(R.string.no_address_found); } } /** * A method that's called once doInBackground() completes. Set the text * of the UI element that displays the address. This method runs on the * UI thread. */ @Override protected void onPostExecute(String address) { // Turn off the progress bar // mActivityIndicator.setVisibility(View.GONE); // Set the address in the UI // mAddress.setText(address); } } /** * Show a dialog returned by Google Play services for the connection error * code * * @param errorCode * An error code returned from onConnectionFailed */ private void showErrorDialog(int errorCode) { // Get the error dialog from Google Play services Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(errorCode, this, LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST); // If Google Play services can provide an error dialog if (errorDialog != null) { // Create a new DialogFragment in which to show the error dialog ErrorDialogFragment errorFragment = new ErrorDialogFragment(); // Set the dialog in the DialogFragment errorFragment.setDialog(errorDialog); // Show the error dialog in the DialogFragment errorFragment.show(getSupportFragmentManager(), LocationUtils.APPTAG); } } /** * Define a DialogFragment to display the error dialog generated in * showErrorDialog. */ public static class ErrorDialogFragment extends DialogFragment { // Global field to contain the error dialog private Dialog mDialog; /** * Default constructor. Sets the dialog field to null */ public ErrorDialogFragment() { super(); mDialog = null; } /** * Set the dialog to display * * @param dialog * An error dialog */ public void setDialog(Dialog dialog) { mDialog = dialog; } /* * This method must return a Dialog to the DialogFragment. */ @Override public Dialog onCreateDialog(Bundle savedInstanceState) { return mDialog; } } }