/* * Copyright (C) 2011 Google Inc. * * 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 tgnourse.balloontracker; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import java.util.Map; import tgnourse.balloontracker.AprsReader.AprsException; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.graphics.Color; import android.location.GpsStatus; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.location.LocationProvider; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.SystemClock; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TableLayout; import android.widget.TextView; import android.widget.Toast; /** * @author tgnourse@google.com (Thomas Nourse) */ public class BalloonTrackerActivity extends Activity { /** * We need to keep track of all of these listeners so we can de-register them later. */ private GpsStatus.Listener gpsStatusListener; private GpsStatus.NmeaListener nmeaListener; private LocationListener locationListener; private LocationManager locationManager; /** * Information about the current location. */ private CurrentLocation currentLocation; private List<Target> targets; /** * Set up the UI and grab the LocationManager. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); // Create the current location object. currentLocation = new CurrentLocation(); targets = new ArrayList<Target>(); // Set up the UI. setContentView(R.layout.main); // Set up the various location listeners so we get GPS updates. locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); gpsStatusListener = new MyGpsStatusListener(); nmeaListener = new MyNmeaListener(); locationListener = new MyLocationListener(); } /** * Android calls this when the user taps the menu button. */ public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.options_menu, menu); return true; } /** * Android calls this when a user taps an option in the options menu. */ public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.edit_locations: showDialog(DIALOG_EDIT_LOCATIONS); break; case R.id.refresh_locations: updateLocations(); break; case R.id.edit_callsigns: showDialog(DIALOG_EDIT_CALLSIGNS); break; } return true; } private void updateLocations() { issueShortToast("Refreshing locations ..."); final List<String> stationNames = getStationNames(); new AsyncTask<Void, Void, Map<String, TargetLocation>>() { protected Map<String, TargetLocation> doInBackground(Void... unused) { try { return new AprsReader().getLocation(stationNames); } catch (AprsException e) { Util.log(e.toString()); return null; } } protected void onPostExecute(Map<String, TargetLocation> locations) { if (locations == null) { issueShortToast("Failed to refresh locations"); return; } int count = 0; for (Target target : targets) { String callsign = target.getCallsign(); if (locations.containsKey(callsign)) { target.setLocation(locations.get(callsign)); count++; Util.log("Updated location for station " + callsign); } } issueShortToast(count + " New Locations Received"); updateUI(); } }.execute(); } private List<String> getStationNames() { final List<String> stationNames = new ArrayList<String>(); for (Target target : targets) { stationNames.add(target.getCallsign()); } return stationNames; } static final int DIALOG_EDIT_LOCATIONS = 0; static final int DIALOG_EDIT_CALLSIGNS = 1; static final int DIALOG_EDIT_LOCATION = 2; static final String DIALOG_EDIT_LOCATION_CALLSIGN = "callsign"; protected Dialog onCreateDialog(int id, Bundle args) { Util.log("onCreateDialog(id,args)"); final Dialog dialog; switch(id) { case DIALOG_EDIT_CALLSIGNS: Util.log("Create callsigns dialog"); dialog = createEditCallsignsDialog(); break; case DIALOG_EDIT_LOCATIONS: Util.log("Create locations dialog"); dialog = createEditLocationsDialog(); break; case DIALOG_EDIT_LOCATION: Util.log("Create location dialog"); dialog = createEditLocationDialog(args.getString(DIALOG_EDIT_LOCATION_CALLSIGN)); break; default: dialog = null; } return dialog; } protected void onPrepareDialog(int id, Dialog dialog, Bundle args) { Util.log("onPrepareDialog(id, dialog, args)"); switch(id) { case DIALOG_EDIT_CALLSIGNS: Util.log("Edit callsigns dialog"); updateEditCallsignsDialog(dialog); break; case DIALOG_EDIT_LOCATIONS: Util.log("Edit locations dialog"); updateEditLocationsDialog(dialog); break; case DIALOG_EDIT_LOCATION: Util.log("Edit location dialog"); updateEditLocationDialog(dialog, args.getString(DIALOG_EDIT_LOCATION_CALLSIGN)); break; } } private void updateEditLocationsDialog(Dialog dialog) { Util.log("updateEditLocationsDialog"); final Button callsign1 = (Button) dialog.findViewById(R.id.callsign1_button); callsign1.setText(targets.size() >= 1 ? targets.get(0).getCallsign() : ""); final Button callsign2 = (Button) dialog.findViewById(R.id.callsign2_button); callsign2.setText(targets.size() >= 2 ? targets.get(1).getCallsign() : ""); final Button callsign3 = (Button) dialog.findViewById(R.id.callsign3_button); callsign3.setText(targets.size() >= 3 ? targets.get(2).getCallsign() : ""); final TextView warning = (TextView) dialog.findViewById(R.id.warning); Util.log("There are " + targets.size() + " targets"); if (targets.size() == 0) { Util.log("0"); warning.setVisibility(View.VISIBLE); callsign1.setVisibility(View.GONE); callsign2.setVisibility(View.GONE); callsign3.setVisibility(View.GONE); } else if (targets.size() == 1) { Util.log("1"); warning.setVisibility(View.GONE); callsign1.setVisibility(View.VISIBLE); callsign2.setVisibility(View.GONE); callsign3.setVisibility(View.GONE); } else if (targets.size() == 2) { Util.log("2"); warning.setVisibility(View.GONE); callsign1.setVisibility(View.VISIBLE); callsign2.setVisibility(View.VISIBLE); callsign3.setVisibility(View.GONE); } else if (targets.size() >= 3) { Util.log("3"); warning.setVisibility(View.GONE); callsign1.setVisibility(View.VISIBLE); callsign2.setVisibility(View.VISIBLE); callsign3.setVisibility(View.VISIBLE); } } private Dialog createEditLocationsDialog() { Context mContext = getApplicationContext(); LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER_SERVICE); View layout = inflater.inflate(R.layout.locations_dialog, (ViewGroup) findViewById(R.id.layout_root)); AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Edit callsign locations"); builder.setView(layout) .setCancelable(true) .setPositiveButton("Ok", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { Util.log("OKAY!"); dialog.dismiss(); updateUI(); } }); final Dialog dialog = builder.create(); final Button callsign1 = (Button) layout.findViewById(R.id.callsign1_button); callsign1.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { Bundle args = new Bundle(); args.putString(DIALOG_EDIT_LOCATION_CALLSIGN, getTextViewValue(dialog, R.id.callsign1_button)); showDialog(DIALOG_EDIT_LOCATION, args); } }); final Button callsign2 = (Button) layout.findViewById(R.id.callsign2_button); callsign2.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { Bundle args = new Bundle(); args.putString(DIALOG_EDIT_LOCATION_CALLSIGN, getTextViewValue(dialog, R.id.callsign2_button)); showDialog(DIALOG_EDIT_LOCATION, args); } }); final Button callsign3 = (Button) layout.findViewById(R.id.callsign3_button); callsign3.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { Bundle args = new Bundle(); args.putString(DIALOG_EDIT_LOCATION_CALLSIGN, getTextViewValue(dialog, R.id.callsign3_button)); showDialog(DIALOG_EDIT_LOCATION, args); } }); return dialog; } private String getTextViewValue(Dialog layout, int id) { return ((TextView) layout.findViewById(id)).getText().toString(); } private void updateEditCallsignsDialog(Dialog dialog) { Util.log("updateEditCallsignsDialog"); final TextView callsign1 = (TextView) dialog.findViewById(R.id.edit_callsign1); callsign1.setText(targets.size() >= 1 ? targets.get(0).getCallsign() : ""); final TextView callsign2 = (TextView) dialog.findViewById(R.id.edit_callsign2); callsign2.setText(targets.size() >= 2 ? targets.get(1).getCallsign() : ""); final TextView callsign3 = (TextView) dialog.findViewById(R.id.edit_callsign3); callsign3.setText(targets.size() >= 3 ? targets.get(2).getCallsign() : ""); } private Dialog createEditCallsignsDialog() { Context mContext = getApplicationContext(); LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER_SERVICE); final View layout = inflater.inflate(R.layout.callsign_dialog, (ViewGroup) findViewById(R.id.layout_root)); AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Edit callsigns"); builder.setView(layout) .setCancelable(false) .setPositiveButton("Okay", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { Util.log("OKAY!"); String one, two, three; one = getTextViewValue((Dialog) dialog, R.id.edit_callsign1).toUpperCase().trim(); two = getTextViewValue((Dialog) dialog, R.id.edit_callsign2).toUpperCase().trim(); three = getTextViewValue((Dialog) dialog, R.id.edit_callsign3).toUpperCase().trim(); Util.log("Done!"); setTargetLocations("".equals(one) ? null : one, "".equals(two) ? null : two, "".equals(three) ? null : three); dialog.dismiss(); updateUI(); } }) .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { Util.log("Cancel, not changing any callsigns!"); dialog.cancel(); } }); final Dialog dialog = builder.create(); return dialog; } private void updateEditLocationDialog(Dialog dialog, String callsign) { Util.log("updateEditLocationsDialog"); TextView callsignview = (TextView) dialog.findViewById(R.id.callsign); callsignview.setText("Update location for " + callsign); TargetLocation location = null; for (Target target : targets) { Util.log(target.getCallsign()); if (target.getCallsign().equals(callsign)) { location = target.getLocation(); } } if (location != null) { TextView latitude = (TextView) dialog.findViewById(R.id.edit_latitude); latitude.setText(String.valueOf(location.getLatitude())); TextView longitude = (TextView) dialog.findViewById(R.id.edit_longitude); longitude.setText(String.valueOf(location.getLongitude())); TextView altitude = (TextView) dialog.findViewById(R.id.edit_altitude); altitude.setText(String.valueOf(location.getAltitude())); } else { TextView latitude = (TextView) dialog.findViewById(R.id.edit_latitude); latitude.setText(""); TextView longitude = (TextView) dialog.findViewById(R.id.edit_longitude); longitude.setText(""); TextView altitude = (TextView) dialog.findViewById(R.id.edit_altitude); altitude.setText(""); } } private Dialog createEditLocationDialog(final String callsign) { Context mContext = getApplicationContext(); LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER_SERVICE); View layout = inflater.inflate(R.layout.location_dialog, (ViewGroup) findViewById(R.id.layout_root)); AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Set a location for " + callsign); builder.setView(layout) .setCancelable(false) .setPositiveButton("Okay", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { Util.log("OKAY! Setting new location for " + callsign + "!"); try { double latitude = Double.parseDouble(getTextViewValue((Dialog) dialog, R.id.edit_latitude)); double longitude = Double.parseDouble(getTextViewValue((Dialog) dialog, R.id.edit_longitude)); double altitude = Double.parseDouble(getTextViewValue((Dialog) dialog, R.id.edit_altitude)); for (Target target : targets) { if (callsign.equals(target.getCallsign())) { target.setLocation(new TargetLocation(latitude, longitude, 0, altitude)); } } issueShortToast("Updated location for " + callsign); dialog.dismiss(); updateUI(); } catch (NumberFormatException e) { issueShortToast("Numbers are not formatted correctly. Please try again."); } } }) .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { Util.log("Cancel, not changing any callsigns!"); dialog.cancel(); } }); final Dialog dialog = builder.create(); return dialog; } private void setTargetLocations(String one, String two, String three) { targets.clear(); if (one != null) targets.add(new Target(one, Color.rgb(255, 0, 255))); if (two != null) targets.add(new Target(two, Color.rgb(0, 0, 255))); if (three != null) targets.add(new Target(three, Color.rgb(255, 255, 0))); Util.log("1.'" + one + "' 2.'" + two + "' 3.'" + three + "'"); updateUI(targets); } private void updateStatus() { if (targets.size() > 0) { if (currentLocation.hasLocation()) { updateStatus("Your location is " + Util.getHumanReadableDuration(currentLocation.getAge()) + Util.getUnitForDuration(currentLocation.getAge()) + " old at " + Math.round(currentLocation.getDeclination()) + "� declination"); } else { updateStatus("Waiting for your location ..."); } } else { updateStatus("Please set some callsigns..."); } } private void updateStatus(String message) { TextView status = (TextView) findViewById(R.id.status); status.setText(message); } private void updateUI() { updateUI(targets); } private void updateAgeSpeedElevation(View layout, long ageValue, float speedValue, double elevationValue) { TextView age = (TextView) findViewByIdAndReleaseId(layout, R.id.age); TextView speed = (TextView) findViewByIdAndReleaseId(layout, R.id.speed); TextView elevation = (TextView) findViewByIdAndReleaseId(layout, R.id.elevation); // age.setText(Util.getHumanReadableDuration(ageValue) + " " + Util.getUnitForDuration(ageValue)); // Age wasn't being calculated right so switch this to time of last fix String time = new java.text.SimpleDateFormat("M/d HH:mm").format(new java.util.Date(ageValue)); age.setText(time); speed.setText(Util.formatNumber(speedValue * Util.MPH_INA_MPS, 0) + " mph"); elevation.setText(Util.formatNumber(elevationValue * Util.FEET_INA_METER, 0) + " ft"); } private void updateUI(List<Target> targets) { Util.log("Updating the UI."); updateStatus(); LayoutInflater inflater = getLayoutInflater(); TableLayout mainTable = (TableLayout) findViewById(R.id.main_table); // HACK: assumes there's only 1 permanent row in the table mainTable.removeViews(1, mainTable.getChildCount() - 1); for (Target target : targets) { TableLayout layout = (TableLayout) inflater.inflate( R.layout.target_table, (ViewGroup) findViewById(R.id.main_table), true); // HACK: Since we are merging new rows in multiple times, we would have ID // collisions. To avoid this, we blow away the ID of each View as we access it. // That way it won't cause conflicts when we merge in another set of rows. TextView callsign = (TextView) findViewByIdAndReleaseId(layout, R.id.callsign); TextView altitude = (TextView) findViewByIdAndReleaseId(layout, R.id.altitude); TextView azimuth = (TextView) findViewByIdAndReleaseId(layout, R.id.azimuth); TextView distance = (TextView) findViewByIdAndReleaseId(layout, R.id.distance); callsign.setText(target.getCallsign()); TargetLocation targetLocation = target.getLocation(); if (targetLocation == null) { callsign.setTextColor(Color.rgb(255, 0, 0)); } else { callsign.setTextColor(Color.rgb(0, 255, 0)); } if (!currentLocation.hasLocation() && targetLocation != null) { Util.log("Waiting for GPS signal ..."); altitude.setText("-"); azimuth.setText("-"); distance.setText("-"); updateAgeSpeedElevation(layout, targetLocation.getAge(), targetLocation.getSpeed(), targetLocation.getAltitude()); } else if (!currentLocation.hasLocation() || targetLocation == null) { altitude.setText("-"); azimuth.setText("-"); distance.setText("-"); TextView age = (TextView) findViewByIdAndReleaseId(layout, R.id.age); TextView speed = (TextView) findViewByIdAndReleaseId(layout, R.id.speed); TextView elevation = (TextView) findViewByIdAndReleaseId(layout, R.id.elevation); age.setText("-"); speed.setText("-"); elevation.setText("-"); } else { Difference difference = currentLocation.getDifference(targetLocation); Util.log(difference.toString()); altitude.setText(Util.formatNumber(difference.getAltitude(), 1) + "�"); azimuth.setText(Util.formatNumber(difference.getAzimuth(), 1) + "� " + Util.getDirectionFromHeading(Math.round(difference.getAzimuth()))); distance.setText(Util.getHumanReadableDistance(difference.getDistance()) + " " + Util.getUnitForDistance(difference.getDistance())); long age; // TODO(tgnourse): Get actual time working. /*if (targetLocation.hasTime()) { age = difference.getTargetAge(); } else {*/ age = targetLocation.getAge(); // } updateAgeSpeedElevation(layout, age, targetLocation.getSpeed(), targetLocation.getAltitude()); } } } /** * calls findViewById() and then changes the view's ID to -1. */ private View findViewByIdAndReleaseId(View view, int id) { View out = view.findViewById(id); out.setId(-1); return out; } public static final String PREFS_NAME = "BalloonTrackerPrefsFile"; public static final String PREF_TARGET_1 = "target1"; public static final String PREF_TARGET_2 = "target2"; public static final String PREF_TARGET_3 = "target3"; public static final String PREF_HAS_LOCATION_PREFIX = "has_location_"; public static final String PREF_LATITUDE_PREFIX = "latitude_"; public static final String PREF_LONGITUDE_PREFIX = "longitude_"; public static final String PREF_SPEED_PREFIX = "speed_"; public static final String PREF_ALTITUDE_PREFIX = "altitude_"; public static final String PREF_TIME_PREFIX = "time_"; private double getPreferencesDouble(SharedPreferences preferences, String key) { String str = preferences.getString(key, ""); try { double num = Double.parseDouble(str); return num; } catch (NumberFormatException e) { return (double) -1; } } private void loadTargetLocation(SharedPreferences settings, String callsign) { double latitude = getPreferencesDouble(settings, PREF_LATITUDE_PREFIX + callsign); double longitude = getPreferencesDouble(settings, PREF_LONGITUDE_PREFIX + callsign); double altitude = getPreferencesDouble(settings, PREF_ALTITUDE_PREFIX + callsign); float speed = settings.getFloat(PREF_SPEED_PREFIX + callsign, (float) -1); long time = settings.getLong(PREF_TIME_PREFIX + callsign, (long) -1); boolean hasLocation = settings.getBoolean(PREF_HAS_LOCATION_PREFIX + callsign, false); if (hasLocation) { for (Target target : targets) { if (callsign.equals(target.getCallsign())) { target.setLocation(new TargetLocation(latitude, longitude, speed, altitude, time)); } } } } private void loadPreferences() { SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); String one = settings.getString(PREF_TARGET_1, null); String two = settings.getString(PREF_TARGET_2, null); String three = settings.getString(PREF_TARGET_3, null); setTargetLocations(one, two, three); loadTargetLocation(settings, one); loadTargetLocation(settings, two); loadTargetLocation(settings, three); } private void putPreferencesDouble(SharedPreferences.Editor editor, String key, double num) { editor.putString(key, String.valueOf(num)); } private void saveTargetLocation(SharedPreferences.Editor editor, Target target) { TargetLocation location = target.getLocation(); if (location != null) { String callsign = target.getCallsign(); putPreferencesDouble(editor, PREF_LATITUDE_PREFIX + callsign, location.getLatitude()); putPreferencesDouble(editor, PREF_LONGITUDE_PREFIX + callsign, location.getLongitude()); putPreferencesDouble(editor, PREF_ALTITUDE_PREFIX + callsign, location.getAltitude()); editor.putFloat(PREF_SPEED_PREFIX + callsign, location.getSpeed()); editor.putLong(PREF_TIME_PREFIX + callsign, location.getTime()); editor.putBoolean(PREF_HAS_LOCATION_PREFIX + callsign, true); } } private void savePreferences() { SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); SharedPreferences.Editor editor = settings.edit(); editor.remove(PREF_TARGET_1); editor.remove(PREF_TARGET_2); editor.remove(PREF_TARGET_3); if (targets.size() >= 1) { editor.putString(PREF_TARGET_1, targets.get(0).getCallsign()); saveTargetLocation(editor, targets.get(0)); } if (targets.size() >= 2) { editor.putString(PREF_TARGET_2, targets.get(1).getCallsign()); saveTargetLocation(editor, targets.get(1)); } if (targets.size() >= 3) { editor.putString(PREF_TARGET_3, targets.get(2).getCallsign()); saveTargetLocation(editor, targets.get(2)); } editor.commit(); } /** * Start the location tracking. */ @Override protected void onResume() { super.onResume(); Util.log("onResume()"); // Re-register all of the listeners. if (!locationManager.addGpsStatusListener(gpsStatusListener)) { Util.error("Couldn't add Gps Status Listener!"); } if (!locationManager.addNmeaListener(nmeaListener)) { Util.error("Couldn't add Nmea Listener!"); } locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener); loadPreferences(); // If we have saved values, we should update the UI. updateUI(); startTimer(); } private Handler handler = new Handler(); long startTime = 0L; private Runnable updateTimeTask = new Runnable() { public void run() { long seconds = (SystemClock.uptimeMillis() - startTime) / 1000; long minutes = seconds / 60; seconds = seconds % 60; updateUI(); handler.postAtTime(this, startTime + (((minutes * 60) + seconds + 1) * 1000)); } }; private void startTimer() { Util.log("startTimer()"); startTime = System.currentTimeMillis(); handler.removeCallbacks(updateTimeTask); handler.postDelayed(updateTimeTask, 100); } public void stopTimer() { Util.log("stopTimer()"); handler.removeCallbacks(updateTimeTask); } /** * Stop the location tracking. */ @Override protected void onPause() { super.onPause(); Util.log("onPause()"); stopTimer(); // Remover the listeners. locationManager.removeGpsStatusListener(gpsStatusListener); locationManager.removeNmeaListener(nmeaListener); locationManager.removeUpdates(locationListener); savePreferences(); } private class MyLocationListener implements LocationListener { public void onLocationChanged(Location location) { // Util.log("New location: " + location); currentLocation.locationChanged(location); updateUI(); String line = "GPS," + System.currentTimeMillis() + "," + location.getAccuracy() + "," + location.getAltitude() + "," + location.getBearing() + "," + location.getLatitude() + "," + location.getLongitude() + "," + location.getSpeed() + "," + location.getTime(); // Util.log(line); } public void onProviderDisabled(String provider) { Util.log("Provider disabled: " + provider); } public void onProviderEnabled(String provider) { Util.log("Provider enabled: " + provider); } public void onStatusChanged(String provider, int status, Bundle extras) { Util.log("Provider status changed: " + provider); switch (status) { case LocationProvider.AVAILABLE: Util.log(provider + " is available."); case LocationProvider.TEMPORARILY_UNAVAILABLE: Util.log(provider + " is temporarily unavailable."); case LocationProvider.OUT_OF_SERVICE: Util.log(provider + " is out of service."); } } } private class MyGpsStatusListener implements GpsStatus.Listener { public void onGpsStatusChanged(int event) { LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); switch (event) { case GpsStatus.GPS_EVENT_FIRST_FIX: //Util.log("First fix"); break; case GpsStatus.GPS_EVENT_SATELLITE_STATUS: //Util.log("Satellite status"); break; case GpsStatus.GPS_EVENT_STARTED: //Util.log("Started"); break; case GpsStatus.GPS_EVENT_STOPPED: //Util.log("Stopped"); break; } // Request a new GpsStatus object instead of having one filled in. GpsStatus status = locationManager.getGpsStatus(null); //Util.log("Max Satellites: " + status.getMaxSatellites()); //Util.log("Time to First Fix: " + status.getTimeToFirstFix()); } } private class MyNmeaListener implements GpsStatus.NmeaListener { public void onNmeaReceived(long timestamp, String nmea) { Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(timestamp); // Util.log(calendar.getTime().toString() + "] " + nmea); } } private void issueShortToast(String message) { Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); } }