Android Open Source - egotrip G P S Service






From Project

Back to project page egotrip.

License

The source code is released under:

Apache License

If you think the Android project egotrip listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package net.myegotrip.egotrip;
//from   w  w  w.  j  av  a  2s . com
import java.text.DateFormat;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import net.myegotrip.egotrip.map.MockLocationProvider;
import net.myegotrip.egotrip.net.Uploader;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceManager;

import android.text.format.DateUtils;
import android.util.Log;
import android.widget.EditText;
import android.widget.Toast;

public class GPSService extends Service implements
    OnSharedPreferenceChangeListener {

  private static final String TAG = "EGOTRIP-GPSService";

  // at least the emulator seems to generate broken timestamps
  // if this is set to true, we generate our own timestamps at insert time
  public static final boolean GENERATE_GPS_TIMESTAMPS = true;

  private DbTools db;
  private Uploader uploader;

  private Notification notification = null;
  private static final int NOTIFICATION_ID=1337;

  private String debug = "";

  /* gps */
  private Location lastLocation = null;
  private ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(
      5);
  // this should be the last one found in the ... db?
  private long lastprovidertimestamp = 0;
  private boolean gps_recorder_running = false;

  /* service */
  private final IBinder mBinder = new LocalBinder();

  /* mock locations... turned on by user via menu */
  MockLocationProvider mocker;

  private boolean service_running = false;
  
  private LocationManager myLocationManager=null;

  private Vector<MyLocationListener> activeLocationListeners=new Vector<GPSService.MyLocationListener>();
  
  /**
   * Class for clients to access. Because we know this service always runs in
   * the same process as its clients, we don't need to deal with IPC.
   */
  public class LocalBinder extends Binder {
    GPSService getService() {
      return GPSService.this;
    }
  }

  public Uploader getUploader() {
    return uploader;
  }

  public DbTools getDbTools() {
    return db;
  }

  @Override
  public void onCreate() {
    super.onCreate();
    p("onCreate");
    db = DbTools.getDbTools(this.getApplicationContext());
    debug = "";
    // get last provider timestamp from db!
    lastprovidertimestamp = db.getLatestLocationTimeStamp();
    p("Got latest location timestamp: " + lastprovidertimestamp);
    uploader = new Uploader(this.getApplicationContext(), db);
  }

  public String getDebug() {
    return debug;
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    p("onStartCommand");

    if (service_running) {
      p("service already running..not starting stuff again");
      return START_STICKY;
    }
    SharedPreferences prefs = PreferenceManager
        .getDefaultSharedPreferences(this);
    prefs.registerOnSharedPreferenceChangeListener(this);



    service_running = true;

    return START_STICKY;
  }

  @Override
  public void onDestroy() {
    stopRecording();
    uploader.stopUploading();
    p("onDestroy");
    service_running = false;
     Toast.makeText(this, "Egotrip recorder stopped",Toast.LENGTH_LONG).show();
  }

  public void startUploading() {
    p("startUploading");
    uploader.startUploading();
  }

  public void stopUploading() {
    p("stopUploading");
    uploader.stopUploading();
  }

  @Override
  public IBinder onBind(Intent intent) {
    return mBinder;
  }

  
  public LocationManager getLocationManager(){
    if(myLocationManager==null){
      myLocationManager=(LocationManager) getApplicationContext()
      .getSystemService(Context.LOCATION_SERVICE);
    }
    return myLocationManager;
  }
  
  public void unregisterAllListeners(){
    LocationManager manager=getLocationManager();
    for(MyLocationListener l:activeLocationListeners){
      manager.removeUpdates(l);
    }
    activeLocationListeners.clear();
  }
  
  public void startRecording() {
    
    // Set the icon, scrolling text and timestamp
    notification = new Notification(R.drawable.red_dot,
        "gps recorder starting....", System.currentTimeMillis());

    // The PendingIntent to launch our activity if the user selects this
    // notification
    PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
        new Intent(this, ControlWindow.class), 0);

    // Set the info for the views that show in the notification panel.
    notification.setLatestEventInfo(this, "gps/uploader status", "running",
        contentIntent);

    startForeground(NOTIFICATION_ID, notification);
    
    
    //kill old executor/listeners
    executor.shutdown();
    unregisterAllListeners();
    
    executor = new ScheduledThreadPoolExecutor(5);
    p("startRecording");
    long checkMinutes = getGPSCheckMinutesFromPrefs();
    long checkSeconds = checkMinutes * 60;
    long checkMilliSecs = checkSeconds * 1000;

    long minDistance = getMinDistanceFromPrefs();

    // receive updates
    LocationManager locationManager = getLocationManager();

    for (String provider : locationManager.getAllProviders()) {
      p("Found GPS provider: " + provider);
      MyLocationListener listener= new MyLocationListener(provider);
      locationManager.requestLocationUpdates(provider, checkMilliSecs,
          minDistance,listener);
      activeLocationListeners.add(listener);
    }
    gps_recorder_running = true;

    Runnable gps_recorder = new Runnable() {
      @Override
      public void run() {
        t_gpsloop();
      }
    };

    
    if (checkSeconds<=0){
      checkSeconds=1;
    }
    p("Starting gps loop with loop delay=" + checkSeconds + " sec");
    executor.scheduleWithFixedDelay(gps_recorder, 0L, checkSeconds,
        TimeUnit.SECONDS);
    
    
    

  }

  /** called from the activity - only if the user has enabled it */
  public Location getMockLocation() {
    if (Math.random() > 0.7) {
      p("generating mock location");
      if (mocker == null)
        mocker = new MockLocationProvider();
      return mocker.getRandomLocation();
    } else
      return null;

  }

  private void p(String msg) {
    Log.d(TAG, msg);
    if (debug.length() > 1000) {
      // delete start
      debug = debug.substring(1000);
    }
    debug += TAG + ":" + msg + "\n";
  }

  private class MyLocationListener implements LocationListener {

    private String provider;

    public MyLocationListener() {
      this(LocationManager.GPS_PROVIDER);
    }

    public MyLocationListener(String provider) {
      this.provider = provider;
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
      p(this.provider + " onStatusChanged : " + status);
    }

    @Override
    public void onProviderEnabled(String provider) {
      p(this.provider + " onProviderEnabled");
    }

    @Override
    public void onProviderDisabled(String provider) {
      p(this.provider + " onProviderDisabled");
    }

    @Override
    public void onLocationChanged(Location location) {
      
      if(!gps_recorder_running){
        p("location update, but gps recorder is not running.. looks like this listener wasn't de-registered...");
        return;
      }
      
      // if this is a gps location, we can use it
      p(this.provider + ": Location changed, reports provider "
          + location.getProvider());
      if (location.getProvider().equals(provider)) {
        if (location != null && GENERATE_GPS_TIMESTAMPS) {
          location.setTime(System.currentTimeMillis());
        }
        doLocationUpdate(location, true);
      }
    }
  }
  
  
  /**
   * Dummy listener that immediately deregisters itself 
   * after the first update
   * (for force update)
   * @author gryphius
   *
   */
  private class SingleUpdateLocationListener implements LocationListener {

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
    }


    @Override
    public void onLocationChanged(Location location) {
      LocationManager locationManager = getLocationManager();
      locationManager.removeUpdates(this);
      p("SingleHit :"
          + location.getProvider());
    }


    @Override
    public void onProviderDisabled(String provider) {
      // TODO Auto-generated method stub
      
    }


    @Override
    public void onProviderEnabled(String provider) {
      // TODO Auto-generated method stub
      
    }
  }
  
  

  public void stopRecording() {
    p("stopping gps recorder thread....");
    executor.shutdown();
    p("gps thread stopped");
    gps_recorder_running = false;
    
    stopForeground(true);
    unregisterAllListeners();  
  }

  private void t_gpsloop() {
    p("Loop tick - getting best location...");
    long start = System.currentTimeMillis();
    Location location = getBestLocation();
    long diff = System.currentTimeMillis() - start;
    if (location != null) {
      p("getBestLocation() finished after " + diff
          + " msecs. location ts=" + location.getTime()
          + " provider=" + location.getProvider());
    } else {
      p("getBestLocation() finished after " + diff
          + " msecs. location=null");
    }
    doLocationUpdate(location, false);
  }

  public boolean isProviderSupported(String in_Provider) {
    LocationManager locationManager = getLocationManager();
    /* locals */
    int lv_N;
    List lv_List;

    // isProviderEnabled should throw a IllegalArgumentException if
    // provider is not
    // supported
    // But in sdk 1.1 the exception is catched by isProviderEnabled itself.
    // Therefore check out the list of providers instead (which indeed does
    // not
    // report a provider it does not exist in the device) Undocumented is
    // that
    // this call can throw a SecurityException
    try {
      lv_List = locationManager.getAllProviders();
    } catch (Throwable e) {
      return false;
    }

    // scan the list for the specified provider
    for (lv_N = 0; lv_N < lv_List.size(); ++lv_N)
      if (in_Provider.equals((String) lv_List.get(lv_N)))
        return true;

    // not supported
    return false;
  }

  /**
   * get the last known location from a specific provider (network/gps
   */
  private Location getLocationByProvider(String provider) {
    Location location = null;
    if (!isProviderSupported(provider)) {
      return null;
    }
    LocationManager locationManager = getLocationManager();

    try {
      if (locationManager.isProviderEnabled(provider)) {

        location = locationManager.getLastKnownLocation(provider);

      }
    } catch (IllegalArgumentException e) {
      p("Cannot acces Provider " + provider);
    }
    return location;
  }

  public boolean isMockOn() {
    SharedPreferences prefs = PreferenceManager
        .getDefaultSharedPreferences(this);
    boolean mockOn = prefs.getBoolean("gps_mock_locations", false);
    return mockOn;
  }

  private long getGPSCheckMinutesFromPrefs() {
    SharedPreferences prefs = PreferenceManager
        .getDefaultSharedPreferences(this);
    int checkminutes = 15;
    try {
      checkminutes = Integer.parseInt(prefs.getString(
          "gps_check_interval", "15"));
    } catch (NumberFormatException e) {
    }

    return checkminutes;
  }

  private long getMinDistanceFromPrefs() {

    SharedPreferences prefs = PreferenceManager
        .getDefaultSharedPreferences(this);
    int minDist = 1000;
    try {
      minDist = Integer.parseInt(prefs.getString("gps_min_distance",
          "1000"));
    } catch (NumberFormatException e) {
    }
    return minDist;
  }

  public boolean checkIfGpsIsTurnedOn() {
    LocationManager locationManager = getLocationManager();
    return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
  }

  /**
   * try to get the 'best' location selected from all providers
   */
  private Location getBestLocation() {
    Location gpslocation = getLocationByProvider(LocationManager.GPS_PROVIDER);
    Location networkLocation = getLocationByProvider(LocationManager.NETWORK_PROVIDER);

    
    if (gpslocation == null && networkLocation == null) {
      p("No GPS or network location available");
      if (this.isMockOn())
        return getMockLocation();
    }
    // if we have only one location available, the choice is easy
    if (gpslocation == null) {
      p("No GPS Location available.");
      // doesn't work if
      // (!this.isProviderSupported(LocationManager.GPS_PROVIDER)) {
      return networkLocation;
    }
    if (networkLocation == null) {
      p("No Network Location available");
      return gpslocation;
    }

    // a locationupdate is considered 'old' if its older than the configured
    // update interval. this means, we didn't get a
    // update from this provider since the last check
    long old = System.currentTimeMillis() - getGPSCheckMinutesFromPrefs();
    boolean gpsIsOld = (gpslocation.getTime() < old);
    boolean networkIsOld = (networkLocation.getTime() < old);

    // gps is current and available, gps is better than network
    if (!gpsIsOld) {
      p("Returning current GPS Location");
      return gpslocation;
    }

    // gps is old, we can't trust it. use network location
    if (!networkIsOld) {
      p("GPS is old, Network is current, returning network");
      return networkLocation;
    }

    // both are old return the newer of those two
    if (gpslocation.getTime() > networkLocation.getTime()) {
      p("Both are old, returning gps(newer)");
      return gpslocation;
    } else {
      p("Both are old, returning network(newer)");
      return networkLocation;
    }
  }

  
  /**
   * try to get a fresh position from the provider by requesting
   * a permanent update and immediately removing the listener after the
   * first update again 
   * @param provider
   */
  private void forceSingleProviderUpdate(String provider){
    LocationManager locationManager = getLocationManager();
    if(locationManager.isProviderEnabled(provider)){
      p("ForceLocUpdate: "+provider);
      locationManager.requestLocationUpdates(provider, 0, 0, new SingleUpdateLocationListener());
    }
  }
  
  /**
   * try to get a fresh position from gps and network
   */
  public void forcelocationupdate() {
    Toast.makeText(this, "Updating current location....",
    Toast.LENGTH_SHORT).show();
    p("Force Location Update....");
    forceSingleProviderUpdate(LocationManager.GPS_PROVIDER);
    forceSingleProviderUpdate(LocationManager.NETWORK_PROVIDER);
    p("ForceLocUpdate: completed");
  }

  
  /**
   * called when any provider sends a update to a listener
   * inserts the new location into the db if it looks like it 
   * is newer  than the last known position
   * @param l
   * @param force
   */
  public void doLocationUpdate(Location l, boolean force) {

    long minDistance = getMinDistanceFromPrefs();

    p("update received:" + l);
    if (l == null) {
      p("Empty location");
      if (force) {
        try {
          p("Current location not available");
          Toast.makeText(this, "Current location not available",
              Toast.LENGTH_SHORT).show();
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
      return;
    }
    if (lastLocation != null) {
      float distance = l.distanceTo(lastLocation);
      p("Distance to last: " + distance);

      if (l.distanceTo(lastLocation) < minDistance && !force) {
        p("Position didn't change");
        return;
      }

      if (l.getAccuracy() >= lastLocation.getAccuracy()
          && l.distanceTo(lastLocation) < l.getAccuracy() && !force) {
        p("Accuracy got worse and we are still within the accuracy range.. Not updating");
        return;
      }

      if (l.getTime() <= lastprovidertimestamp && !force) {
        p("Timestamp not never than last");
        return;
      }

    }

    else
      p("Got no lastprovidertimestamp");

    final SharedPreferences prefs = PreferenceManager
        .getDefaultSharedPreferences(this);
    // should be the current trip name... as used in map activity
    String tripname = prefs.getString("custom_trip", "default");

    final LocationUpdate update = new LocationUpdate(l);
    if (tripname.trim().equals("")) {
      tripname = "default";
    }
    update.setTripname(tripname);

    p("pushing location update " + l);
    db.insertLocation(update);

    lastprovidertimestamp = l.getTime();
    lastLocation = l;
    
    DateFormat fm=DateFormat.getDateTimeInstance(DateFormat.SHORT,DateFormat.SHORT);
    String currentDateTimeString = ""+fm.format(new Date(l.getTime()));

    currentDateTimeString+=" "+l.getProvider();
    String ns = Context.NOTIFICATION_SERVICE;
    NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
    notification.setLatestEventInfo(this, "Last position change", currentDateTimeString, notification.contentIntent);
    mNotificationManager.notify(NOTIFICATION_ID, notification);
  }

  public Location getLastLocation() {
    return lastLocation;
  }

  public boolean isRecording() {
    return gps_recorder_running;
  }

  @Override
  public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
      String key) {

    p("settings change: " + key);
    if (key.equals("gps_min_distance") || key.equals("gps_check_interval")) {
      if (isRecording()) {
        p("gps settings changed -> restarting recorder");
        stopRecording();
        startRecording();
      }
    }

  }

  /** deleta last location */
  public void clearData() {
    this.lastLocation = null;
    lastprovidertimestamp = 0;
  }

}




Java Source Code List

net.myegotrip.egotrip.CommonGPSServiceFunctions.java
net.myegotrip.egotrip.ControlHandler.java
net.myegotrip.egotrip.ControlWindow.java
net.myegotrip.egotrip.DbListener.java
net.myegotrip.egotrip.DbTools.java
net.myegotrip.egotrip.DownloadProgressHandler.java
net.myegotrip.egotrip.FallbackDefaults.java
net.myegotrip.egotrip.GPSService.java
net.myegotrip.egotrip.Installation.java
net.myegotrip.egotrip.LocationUpdate.java
net.myegotrip.egotrip.MapViewActivity.java
net.myegotrip.egotrip.PrefActivity.java
net.myegotrip.egotrip.ReleaseConfig.java
net.myegotrip.egotrip.StartupActivity.java
net.myegotrip.egotrip.TaskDoneListener.java
net.myegotrip.egotrip.Tools.java
net.myegotrip.egotrip.TripManager.java
net.myegotrip.egotrip.help.HelpActivity.java
net.myegotrip.egotrip.help.TopicActivity.java
net.myegotrip.egotrip.image.ImageHandler.java
net.myegotrip.egotrip.map.MockLocationProvider.java
net.myegotrip.egotrip.map.PlacemarkOverlay.java
net.myegotrip.egotrip.map.Placemark.java
net.myegotrip.egotrip.map.RouteOverlay.java
net.myegotrip.egotrip.map.RoutePoint.java
net.myegotrip.egotrip.map.Trip.java
net.myegotrip.egotrip.metadata.EgotripMetadata.java
net.myegotrip.egotrip.metadata.GenericMetadata.java
net.myegotrip.egotrip.metadata.Icon.java
net.myegotrip.egotrip.metadata.Image.java
net.myegotrip.egotrip.metadata.MetadataManager.java
net.myegotrip.egotrip.metadata.Text.java
net.myegotrip.egotrip.net.BetaUpdateManager.java
net.myegotrip.egotrip.net.ProtocolConstants.java
net.myegotrip.egotrip.net.ServerReply.java
net.myegotrip.egotrip.net.Uploader.java
net.myegotrip.egotrip.profile.ProfileActivity.java
net.myegotrip.egotrip.profile.ProfilePrefActivity.java
net.myegotrip.egotrip.profile.ProfileView.java
net.myegotrip.egotrip.utils.DebugActivity.java
net.myegotrip.egotrip.utils.Debug.java
net.myegotrip.egotrip.utils.GuiUtils.java
net.myegotrip.egotrip.utils.IconItem.java
net.myegotrip.egotrip.utils.TwoDScrollView.java
net.myegotrip.egotrip.utils.XYScaleGestureDetector.java