Java tutorial
/** * Copyright 2014 Google Inc. All Rights Reserved. * * 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 ro.tudorluca.gpstracks.android; import android.location.Location; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.JsonObjectRequest; import com.android.volley.toolbox.Volley; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks; import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener; import com.google.android.gms.location.LocationListener; import com.google.android.gms.location.LocationRequest; import com.google.android.gms.location.LocationServices; import org.json.JSONObject; import java.text.DateFormat; import java.util.Date; /** * Getting Location Updates. * <p/> * Demonstrates how to use the Fused Location Provider API to get updates about a device's * location. The Fused Location Provider is part of the Google Play services location APIs. */ public class MainActivity extends ActionBarActivity implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener { protected static final String TAG = "location-updates-sample"; /** * The desired interval for location updates. Inexact. Updates may be more or less frequent. */ public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000; /** * The fastest rate for active location updates. Exact. Updates will never be more frequent * than this value. */ public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = UPDATE_INTERVAL_IN_MILLISECONDS / 2; // Keys for storing activity state in the Bundle. protected final static String REQUESTING_LOCATION_UPDATES_KEY = "requesting-location-updates-key"; protected final static String LOCATION_KEY = "location-key"; protected final static String LAST_UPDATED_TIME_STRING_KEY = "last-updated-time-string-key"; /** * Provides the entry point to Google Play services. */ protected GoogleApiClient mGoogleApiClient; /** * Stores parameters for requests to the FusedLocationProviderApi. */ protected LocationRequest mLocationRequest; /** * Represents a geographical location. */ protected Location mCurrentLocation; /** * URL of the web api. */ private static final String API_URL = "http://192.168.2.6:8080"; private static final boolean DEBUG_MODE = true; private RequestQueue mRequestQueue; private ObjectMapper mMapper; // UI Widgets. protected Button mStartUpdatesButton; protected Button mStopUpdatesButton; protected TextView mLastUpdateTimeTextView; protected TextView mLatitudeTextView; protected TextView mLongitudeTextView; protected EditText mUserIdEditText; /** * Tracks the status of the location updates request. Value changes when the user presses the * Start Updates and Stop Updates buttons. */ protected Boolean mRequestingLocationUpdates; /** * Time when the location was updated represented as a String. */ protected String mLastUpdateTime; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Locate the UI widgets. mStartUpdatesButton = (Button) findViewById(R.id.start_updates_button); mStopUpdatesButton = (Button) findViewById(R.id.stop_updates_button); mLatitudeTextView = (TextView) findViewById(R.id.latitude_text); mLongitudeTextView = (TextView) findViewById(R.id.longitude_text); mLastUpdateTimeTextView = (TextView) findViewById(R.id.last_update_time_text); mUserIdEditText = (EditText) findViewById(R.id.user_id_text); mRequestingLocationUpdates = false; mLastUpdateTime = ""; // Update values using data stored in the Bundle. updateValuesFromBundle(savedInstanceState); mRequestQueue = Volley.newRequestQueue(this); // Kick off the process of building a GoogleApiClient and requesting the LocationServices // API. buildGoogleApiClient(); } /** * Updates fields based on data stored in the bundle. * * @param savedInstanceState The activity state saved in the Bundle. */ private void updateValuesFromBundle(Bundle savedInstanceState) { Log.i(TAG, "Updating values from bundle"); if (savedInstanceState != null) { // Update the value of mRequestingLocationUpdates from the Bundle, and make sure that // the Start Updates and Stop Updates buttons are correctly enabled or disabled. if (savedInstanceState.keySet().contains(REQUESTING_LOCATION_UPDATES_KEY)) { mRequestingLocationUpdates = savedInstanceState.getBoolean(REQUESTING_LOCATION_UPDATES_KEY); setButtonsEnabledState(); } // Update the value of mCurrentLocation from the Bundle and update the UI to show the // correct latitude and longitude. if (savedInstanceState.keySet().contains(LOCATION_KEY)) { // Since LOCATION_KEY was found in the Bundle, we can be sure that mCurrentLocation // is not null. mCurrentLocation = savedInstanceState.getParcelable(LOCATION_KEY); } // Update the value of mLastUpdateTime from the Bundle and update the UI. if (savedInstanceState.keySet().contains(LAST_UPDATED_TIME_STRING_KEY)) { mLastUpdateTime = savedInstanceState.getString(LAST_UPDATED_TIME_STRING_KEY); } updateUI(); } } /** * Builds a GoogleApiClient. Uses the {@code #addApi} method to request the * LocationServices API. */ protected synchronized void buildGoogleApiClient() { Log.i(TAG, "Building GoogleApiClient"); mGoogleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(this) .addOnConnectionFailedListener(this).addApi(LocationServices.API).build(); createLocationRequest(); } /** * Sets up the location request. Android has two location request settings: * {@code ACCESS_COARSE_LOCATION} and {@code ACCESS_FINE_LOCATION}. These settings control * the accuracy of the current location. This sample uses ACCESS_FINE_LOCATION, as defined in * the AndroidManifest.xml. * <p/> * When the ACCESS_FINE_LOCATION setting is specified, combined with a fast update * interval (5 seconds), the Fused Location Provider API returns location updates that are * accurate to within a few feet. * <p/> * These settings are appropriate for mapping applications that show real-time location * updates. */ protected void createLocationRequest() { mLocationRequest = new LocationRequest(); // Sets the desired interval for active location updates. This interval is // inexact. You may not receive updates at all if no location sources are available, or // you may receive them slower than requested. You may also receive updates faster than // requested if other applications are requesting location at a faster interval. mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS); // Sets the fastest rate for active location updates. This interval is exact, and your // application will never receive updates faster than this value. mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); } /** * Handles the Start Updates button and requests start of location updates. Does nothing if * updates have already been requested. */ public void startUpdatesButtonHandler(View view) { if (!mRequestingLocationUpdates) { mRequestingLocationUpdates = true; setButtonsEnabledState(); startLocationUpdates(); } } /** * Handles the Stop Updates button, and requests removal of location updates. Does nothing if * updates were not previously requested. */ public void stopUpdatesButtonHandler(View view) { if (mRequestingLocationUpdates) { mRequestingLocationUpdates = false; setButtonsEnabledState(); stopLocationUpdates(); } } public void locateNowButtonHandler(View view) { Location lastKnownLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); if (lastKnownLocation == null) { Toast.makeText(MainActivity.this, getString(R.string.location_unavailable), Toast.LENGTH_SHORT).show(); return; } sendLocationToWebApi(lastKnownLocation); } /** * Requests location updates from the FusedLocationApi. */ protected void startLocationUpdates() { LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this); } /** * Ensures that only one button is enabled at any time. The Start Updates button is enabled * if the user is not requesting location updates. The Stop Updates button is enabled if the * user is requesting location updates. */ private void setButtonsEnabledState() { if (mRequestingLocationUpdates) { mStartUpdatesButton.setEnabled(false); mStopUpdatesButton.setEnabled(true); } else { mStartUpdatesButton.setEnabled(true); mStopUpdatesButton.setEnabled(false); } } /** * Updates the latitude, the longitude, and the last location time in the UI. */ private void updateUI() { if (mCurrentLocation == null) { return; } mLatitudeTextView.setText(String.valueOf(mCurrentLocation.getLatitude())); mLongitudeTextView.setText(String.valueOf(mCurrentLocation.getLongitude())); mLastUpdateTimeTextView.setText(mLastUpdateTime); } private void sendLocationToWebApi(Location location) { Long userId = Long.valueOf(mUserIdEditText.getText().toString()); Position position = new Position(); position.setUserId(userId); position.setLatitude(String.valueOf(location.getLatitude())); position.setLongitude(String.valueOf(location.getLongitude())); position.setDate(new Date()); if (mMapper == null) { mMapper = new ObjectMapper(); mMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true); } try { JSONObject positionJSON = new JSONObject(mMapper.writeValueAsString(position)); JsonObjectRequest postRequest = new JsonObjectRequest(Request.Method.POST, API_URL + "/position", positionJSON, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { Toast.makeText(MainActivity.this, getString(R.string.location_sent_message), Toast.LENGTH_SHORT).show(); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Toast.makeText(MainActivity.this, getString(R.string.location_send_error), Toast.LENGTH_SHORT).show(); error.getCause().printStackTrace(); } }); mRequestQueue.add(postRequest); } catch (Exception ignored) { } } /** * Removes location updates from the FusedLocationApi. */ protected void stopLocationUpdates() { // It is a good practice to remove location requests when the activity is in a paused or // stopped state. Doing so helps battery performance and is especially // recommended in applications that request frequent location updates. LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this); } @Override protected void onStart() { super.onStart(); mGoogleApiClient.connect(); } @Override public void onResume() { super.onResume(); // Within {@code onPause()}, we pause location updates, but leave the // connection to GoogleApiClient intact. Here, we resume receiving // location updates if the user has requested them. if (mGoogleApiClient.isConnected() && mRequestingLocationUpdates) { startLocationUpdates(); } } @Override protected void onPause() { super.onPause(); // Stop location updates to save battery, but don't disconnect the GoogleApiClient object. stopLocationUpdates(); } @Override protected void onStop() { super.onStop(); if (mGoogleApiClient.isConnected()) { mGoogleApiClient.disconnect(); } } /** * Runs when a GoogleApiClient object successfully connects. */ @Override public void onConnected(Bundle connectionHint) { Log.i(TAG, "Connected to GoogleApiClient"); // if (DEBUG_MODE) { // LocationServices.FusedLocationApi.setMockMode(mGoogleApiClient, true); // } // If the initial location was never previously requested, we use // FusedLocationApi.getLastLocation() to get it. If it was previously requested, we store // its value in the Bundle and check for it in onCreate(). We // do not request it again unless the user specifically requests location updates by pressing // the Start Updates button. // // Because we cache the value of the initial location in the Bundle, it means that if the // user launches the activity, // moves to a new location, and then changes the device orientation, the original location // is displayed as the activity is re-created. if (mCurrentLocation == null) { mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); mLastUpdateTime = DateFormat.getTimeInstance().format(new Date()); updateUI(); } // If the user presses the Start Updates button before GoogleApiClient connects, we set // mRequestingLocationUpdates to true (see startUpdatesButtonHandler()). Here, we check // the value of mRequestingLocationUpdates and if it is true, we start location updates. if (mRequestingLocationUpdates) { startLocationUpdates(); } } /** * Callback that fires when the location changes. */ @Override public void onLocationChanged(Location location) { mCurrentLocation = location; mLastUpdateTime = DateFormat.getTimeInstance().format(new Date()); updateUI(); Toast.makeText(this, getResources().getString(R.string.location_updated_message), Toast.LENGTH_SHORT) .show(); sendLocationToWebApi(location); } @Override public void onConnectionSuspended(int cause) { // The connection to Google Play services was lost for some reason. We call connect() to // attempt to re-establish the connection. Log.i(TAG, "Connection suspended"); mGoogleApiClient.connect(); } @Override public void onConnectionFailed(ConnectionResult result) { // Refer to the javadoc for ConnectionResult to see what error codes might be returned in // onConnectionFailed. Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode()); } /** * Called by Google Play services if the connection to GoogleApiClient drops because of an * error. */ public void onDisconnected() { Log.i(TAG, "Disconnected"); } /** * Stores activity data in the Bundle. */ public void onSaveInstanceState(Bundle savedInstanceState) { savedInstanceState.putBoolean(REQUESTING_LOCATION_UPDATES_KEY, mRequestingLocationUpdates); savedInstanceState.putParcelable(LOCATION_KEY, mCurrentLocation); savedInstanceState.putString(LAST_UPDATED_TIME_STRING_KEY, mLastUpdateTime); super.onSaveInstanceState(savedInstanceState); } }