TrackRecorderService.java :  » Map » swp-dv-ws2010-osm-2 » de » fuberlin » osm2 » trackrecorder » Android Open Source

Android Open Source » Map » swp dv ws2010 osm 2 
swp dv ws2010 osm 2 » de » fuberlin » osm2 » trackrecorder » TrackRecorderService.java
package de.fuberlin.osm2.trackrecorder;

import java.util.LinkedList;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
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.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.util.Log;
import de.fuberlin.osm2.R;
import de.fuberlin.osm2.data.DataBaseConnector;
import de.fuberlin.osm2.data.DataBaseConnectorImpl;
import de.fuberlin.osm2.gui.activity.ViewActivity;
import de.fuberlin.osm2.gui.view.ServiceLocationListener;
import de.fuberlin.osm2.log.Constants;
import de.fuberlin.osm2.settings.Settings;

/**
 * TrackRecorderService is a component between GUI and database. It implements
 * LocationListener to obtain new GPS fixes.
 * 
 * @author micha & simon
 */
public class TrackRecorderService extends Service implements LocationListener {
  /**
   * Bundle Wrapper stores pointId of a point and its attributes in a bundle.
   * 
   * @author micha & simon
   * 
   */
  private static class BundleWrapper {
    protected long pointId;
    protected Bundle bundle;

    /**
     * 
     * @param pId pointId of the point
     * @param bndl attributes of the point
     */
    protected BundleWrapper(long pId, Bundle bndl) {
      pointId = pId;
      bundle = bndl;
    }
  }

  // static variables
  private static boolean serviceIsRunning;

  // reference to the singleton TrackRecorderService
  private static TrackRecorderService service;
  private static Settings settings;

  private static SharedPreferences sharedPreferences;

  private static final int NOTIFICATION_ID = 1;
  private static final int MILLIS_TO_SEC = 1000;

  /**
   * Starts TrackRecorderService if necessary and returns the reference to the
   * singleton. NOTE: reference is null, if TrackRecorderService is not yet
   * running.
   * 
   * @param context parent context
   * @return reference to the singleton
   */
  public static TrackRecorderService getService(Context context) {
    if (!serviceIsRunning) {
      Log.d(Constants.TAG, "TrackRecorderService getService: service is null");
      startService(context);
    }
    return service;
  }

  /**
   * Starts TrackRecorderService if necessary.
   * 
   * @param context parent context
   */

  public static void startService(Context context) {
    if (settings == null) {
      settings = new Settings(context);
    }
    if (sharedPreferences == null) {
      sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
    }

    if (!serviceIsRunning) {
      context.startService(new Intent(context, TrackRecorderService.class));
    }
  }

  /**
   * Stops TrackRecorderService.
   * 
   * @param context context of caller
   */
  public static void stopService(Context context) {

    if (service != null) {
      Log.d(Constants.TAG, "stopService");
      context.stopService(new Intent(context, TrackRecorderService.class));
      service = null;
    }
  }

  private OnSharedPreferenceChangeListener settingsListener;
  private String ns = Context.NOTIFICATION_SERVICE;

  private NotificationManager notificationManager;
  private ServiceLocationListener locationListener;

  private boolean notifyListener;
  private LocationManager locationManager;

  /** for database access. */
  DataBaseConnector db;
  private float minDistance = 0.5F; // in meters

  private boolean gpsEnabled;
  private boolean isTracking;
  private boolean isPaused;

  private Location currentLocation;
  private long currentLocationId;
  private long trackId;
  private boolean trackingWay;
  private long wayId;
  private boolean trackingArea;
  private long areaId;

  // it shall be possible to add POIs right at the beginning,
  // when no location is available yet.

  private String currentTrackName;

  private LinkedList<Bundle> poiQueue = new LinkedList<Bundle>();

  /**
   * Stops the current tracked area.
   * 
   * @param tags identifies a area, if we allow to track more then one area at
   *            one time (not yet used)
   * 
   */
  public void closeArea(Bundle tags) {
    if (trackingArea) {
      Log.d(Constants.TAG, "TRC: closeArea");
      if (notifyListener)
        locationListener.onStopArea();
      trackingArea = false;
    }
  }

  /**
   * Gives the name of the current track.
   * 
   * @return name of the current track
   */
  public String getCurrentTrackName() {
    return currentTrackName;
  }

  /**
   * returns the id of the current track.
   * 
   * @return trackId
   */
  public long getCurrentTrackId() {
    return trackId;
  }

  /**
   * returns the id of the current point.
   * 
   * @return pointId
   */
  public long getCurrentPointId() {
    return currentLocationId;
  }

  /**
   * checks whether the gps provider is enabled.
   * 
   * @return true if gps provider is enabled
   */
  public boolean isGpsEnabled() {
    gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
    return gpsEnabled;
  }

  /**
   * We don't use the Android binder mechanism, so return null.
   */
  @Override
  public IBinder onBind(Intent intent) {
    return null;
  }

  private static void setService(TrackRecorderService service) {
    TrackRecorderService.service = service;
  }

  private static void setServiceAsRunning() {
    TrackRecorderService.serviceIsRunning = true;
  }

  private static void setServiceAsStopped() {
    TrackRecorderService.serviceIsRunning = false;
  }

  /**
   * Registers SettingsListener and LocationUpdates.
   */
  @Override
  public void onCreate() {
    super.onCreate();
    setService(this);
    setServiceAsRunning();
    // get gps LocationManager
    locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
    isGpsEnabled();
    db = new DataBaseConnectorImpl(this);
    registerSettingsListener();
  }

  /**
   * Unregisters SettingsListener and LocationUpdates.
   */
  @Override
  public void onDestroy() {
    setServiceAsStopped();
    setService(null);
    unregisterSettingsListener();
    db.close();
    // if (serviceDemand) {
    // Service is crashed
    // }

    Log.d(Constants.TAG, "Service: onDestroyed");
    if (!isPaused) {
      locationManager.removeUpdates(this);
      notificationManager.cancelAll();
    }
  }

  /**
   * Receives a new gps-fix and delegates it to the db-wrapper. Adds the
   * gps-fix to ways or areas when they are tracked actually.
   */
  @Override
  public void onLocationChanged(Location location) {
    Log.d(Constants.TAG,
        "new gps fix lat->" + location.getLatitude() + " lng->"
            + location.getLongitude());
    isTracking = true;
    if (!isPaused) {
      currentLocation = location;
      currentLocationId = db.addPoint(location.getLongitude(), location.getLatitude(),
          System.currentTimeMillis(), trackId);
      if (notifyListener) {
        locationListener.onLocationUpdate(currentLocation.getLongitude(),
            currentLocation.getLatitude());
      }
      if (trackingWay) {
        final AsyncTask<Long, Integer, Long> asyncTask = new AsyncTask<Long, Integer, Long>() {
          @Override
          protected Long doInBackground(Long... ids) {
            db.addPointToWay(ids[0].longValue(), ids[1].longValue());
            Log.d(Constants.TAG, "TRC: added point to way");
            return null;
          }
        };
        asyncTask.execute(Long.valueOf(currentLocationId), Long.valueOf(wayId));
      }
      if (trackingArea) {
        final AsyncTask<Long, Integer, Long> asyncTask = new AsyncTask<Long, Integer, Long>() {
          @Override
          protected Long doInBackground(final Long... ids) {
            db.addPointToWay(ids[0].longValue(), ids[1].longValue());
            Log.d(Constants.TAG, "TRC: added point to area");
            return null;
          }
        };
        asyncTask.execute(Long.valueOf(currentLocationId), Long.valueOf(areaId));
      }

      if (!poiQueue.isEmpty()) {
        Log.d(Constants.TAG, "TRC: Added Poi from Queue");
        for (Bundle b : poiQueue) {
          onPOI(b);
        }
        poiQueue.clear();
      }
    }
  }

  /**
   * Adds a new POI with the given attributes.
   * 
   * @param tags contains the attributes of the POI
   * 
   */
  public void onPOI(Bundle tags) {

    if (null != currentLocation) {
      final AsyncTask<BundleWrapper, Integer, Long> asyncTask = new AsyncTask<BundleWrapper, Integer, Long>() {
        @Override
        protected Long doInBackground(BundleWrapper... bundleWrp) {
          Log.d(Constants.TAG, "TRC: onPoi currentLocationId->"
              + bundleWrp[0].pointId + " tags ->" + bundleWrp[0].bundle);

          db.addPoi(bundleWrp[0].pointId, bundleWrp[0].bundle);

          return null;
        }
      };
      asyncTask.execute(new BundleWrapper(currentLocationId, tags));

      // TODO: tag name
      String tag = tags.containsKey("KEY") ? tags.getString("KEY") : "";
      if (notifyListener) {
        locationListener.onPOI(currentLocation.getLongitude(),
            currentLocation.getLatitude(), tag);
      }
    }

    else {
      Log.d(Constants.TAG, "TRC: Adding Poi to Queue");
      poiQueue.add(tags);
    }
  }

  /**
   * Is called when the user disables the gps provider.
   */
  @Override
  public void onProviderDisabled(String provider) {
    gpsEnabled = false;
    Log.d(Constants.TAG, "gps provider disabled");
  }

  /**
   * Is called when the user enables the gps provider.
   */
  @Override
  public void onProviderEnabled(String provider) {
    gpsEnabled = true;
    Log.d(Constants.TAG, "gps provider enabled");

  }

  /**
   * Starts the service sticky, so it is running until it is explicitly
   * stopped.
   */
  // @Override
  // public int onStartCommand(Intent intent, int flags, int startId) {
  // Log.d(Constants.TAG, "Received start id " + startId + ": " + intent);
  // // We want this service to continue running until it is explicitly
  // // stopped, so return sticky.
  // return START_STICKY;
  // }

  /**
   * Start the service. Called by the system.
   */
  @Override
  public void onStart(Intent intent, int startId) {
    Log.d(Constants.TAG, "Received start id " + startId + ": " + intent);
  }

  /**
   * Pauses the current track. The LocationManager is still running to avoid a
   * gps-fix delay.
   */
  public void pauseTrack() {
    if (!isPaused) {
      isTracking = false;
      unregisterLocationListener();
      showNotificationPaused();
      isPaused = true;
    }
  }

  /**
   * Registers gps LocationLister to obtain gps-fixes.
   */
  private void registerLocationListener() {

    // DEBUG
    // locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
    // settings.gpsInterval() * MILLIS_TO_SEC, minDistance, this);

    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
        settings.gpsInterval() * MILLIS_TO_SEC, minDistance, this);

  }

  /**
   * Enables notifications for the locationListener. The locationListener will
   * be informed if the location changes or new points are added.
   * 
   * @param locListener which wants to be informed about location changes
   */
  public void registerLocationUpdates(ServiceLocationListener locListener) {
    Log.d(Constants.TAG, "TRS: registerLocationUpdates ");
    this.locationListener = locListener;
    notifyListener = true;
  }

  /**
   * Registers SettingsListener to obtain setting changes i.e gps interval.
   */
  private void registerSettingsListener() {
    sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
    settingsListener = new OnSharedPreferenceChangeListener() {
      @Override
      public void onSharedPreferenceChanged(SharedPreferences pref, String arg) {
        Log.d(Constants.TAG, "setting changed");
        if ((TrackRecorderService.this).getResources()
            .getString(R.string.settings_key_gps_interval).equals(arg)) {
          Log.d(Constants.TAG, "gps interval changed");
          // pause and resume Track to change gps interval of the
          // location locationListener
          TrackRecorderService.this.restartTracking();
        } else if ((TrackRecorderService.this).getResources()
            .getString(R.string.settings_key_osm_layer).equals(arg)) {
          Log.d(Constants.TAG, "showOSMlayer changed");
        }
      }
    };
    sharedPreferences.registerOnSharedPreferenceChangeListener(settingsListener);
  }

  /**
   * Pauses and resumes tracking to update preferences of the LocationListener
   * i.e. gps interval
   */
  void restartTracking() {
    if (!isPaused) {
      pauseTrack();
      resumeTrack();
    }
  }

  /**
   * Resumes the paused track.
   */

  public void resumeTrack() {
    if (isPaused) {
      registerLocationListener();
      showNotificationRunning();
      isPaused = false;
    }
  }

  /**
   * Shows pause notification icon in statusbar.
   */
  private void showNotificationPaused() {
    // TODO: modify notification paused
    // Instantiate the Notification:
    int icon = R.drawable.ic_stat_notify_paused;
    CharSequence tickerText = this.getString(R.string.service_notification_paused);
    long when = System.currentTimeMillis();

    Notification notification = new Notification(icon, tickerText, when);

    // Define the Notification's expanded message and Intent:
    Context context = getApplicationContext();
    CharSequence contentTitle = this.getString(R.string.app_name);
    CharSequence contentText = this.getString(R.string.service_notification_paused);

    Intent notificationIntent = new Intent(this, ViewActivity.class);
    PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

    notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);

    // Pass the Notification to the NotificationManager:

    notificationManager.notify(NOTIFICATION_ID, notification);

  }

  /**
   * Shows running-notification icon in statusbar.
   */
  private void showNotificationRunning() {
    // Instantiate the Notification:
    int icon = R.drawable.ic_stat_notify_running;
    CharSequence tickerText = this.getString(R.string.service_notification_running);
    long when = System.currentTimeMillis();

    Notification notification = new Notification(icon, tickerText, when);

    // Define the Notification's expanded message and Intent:
    Context context = getApplicationContext();
    CharSequence contentTitle = this.getString(R.string.app_name);
    CharSequence contentText = this.getString(R.string.service_notification_running);

    Intent notificationIntent = new Intent(this, ViewActivity.class);
    PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

    notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);

    // Pass the Notification to the NotificationManager:

    notificationManager.notify(NOTIFICATION_ID, notification);
  }

  /**
   * Starts a new area with the given attributes.
   * 
   * @param tags contains the attributes of the area
   * 
   */
  public void startArea(Bundle tags) {
    if (!trackingArea) {
      Log.d(Constants.TAG, "TRC: startArea");
      areaId = db.startWay(tags, true);
      if (notifyListener) {
        locationListener.onStartArea();
      }
      trackingArea = true;
    }
  }

  /**
   * Starts a new track. The LocationManger is started immediately to obtain
   * gps fixes.
   * 
   * @param bundle contains the name of the new track ( key:"TRACK_NAME")
   */
  public void startTrack(Bundle bundle) {

    Log.d(Constants.TAG, "TRC: startTrack -> " + bundle);

    registerLocationListener();

    Log.d(Constants.TAG, "TRS: gpsEnabled->" + gpsEnabled);

    currentTrackName = bundle.getString("TRACK_NAME");
    trackId = db.addTrack(currentTrackName, System.currentTimeMillis());
    // Get a reference to the NotificationManager:
    notificationManager = (NotificationManager) getSystemService(ns);
    showNotificationRunning();

  }

  /**
   * Starts a new way with the given attributes.
   * 
   * @param tags contains the attributes of the way
   * 
   */
  public void startWay(Bundle tags) {
    if (!trackingWay) {
      Log.d(Constants.TAG, "TRC: startWay");
      wayId = db.startWay(tags, false);
      if (notifyListener) {
        locationListener.onStartWay();
      }
      trackingWay = true;
    }
  }

  /**
   * Stops current track and the LocationManager.
   */
  public void stopTrack() {
    unregisterLocationListener();
    isTracking = false;
    notificationManager.cancelAll();
  }

  /**
   * Stops the current tracked way.
   * 
   * @param tags identifies a way, if we allow to track more then one way at
   *            one time (not yet used)
   * 
   */
  public void stopWay(Bundle tags) {
    if (trackingWay) {
      Log.d(Constants.TAG, "TRC: stopWay");
      if (notifyListener) {
        locationListener.onStopWay();
      }
      trackingWay = false;
    }
  }

  /**
   * Unregisters gps LocationListener, stops obtaining gps-fixes.
   */
  private void unregisterLocationListener() {
    locationManager.removeUpdates(this);
  }

  /**
   * Disables ServiceLocationListener's notifications.
   */
  public void unregisterLocationUpdates() {
    notifyListener = false;
    this.locationListener = null;
  }

  /**
   * Unregisters SettingsListener, stops obtaining setting changes.
   */
  private void unregisterSettingsListener() {
    sharedPreferences.unregisterOnSharedPreferenceChangeListener(settingsListener);
  }

  /**
   * informs about the the state of tracking.
   * 
   * @return true if the service has a actual gps fix
   */
  public boolean isTracking() {
    return isTracking;
  }

  @Override
  public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
    // TODO Auto-generated method stub

  }

}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.