Android Open Source - Android-SimpleLocation Simple Location






From Project

Back to project page Android-SimpleLocation.

License

The source code is released under:

Apache License

If you think the Android project Android-SimpleLocation 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 im.delight.android.location;
/* w ww. j  av a2 s  . c  o m*/
/**
 * Copyright 2014 www.delight.im <info@delight.im>
 *
 * 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.
 */

import android.os.Parcel;
import android.os.Parcelable;
import java.util.Random;
import android.provider.Settings;
import android.content.Intent;
import android.os.Bundle;
import android.location.LocationListener;
import android.location.Location;
import android.content.Context;
import android.location.LocationManager;

/** Utility class for easy access to the device location on Android */
public class SimpleLocation {

  /** Wrapper for two coordinates (latitude and longitude) */
  public static class Point implements Parcelable {

    /** The latitude of the point */
    public final double latitude;
    /** The longitude of the point */
    public final double longitude;

    /**
     * Constructs a new point from the given coordinates
     *
     * @param lat the latitude
     * @param lon the longitude
     */
    public Point(double lat, double lon) {
      latitude = lat;
      longitude = lon;
    }

    @Override
    public String toString() {
      return "("+latitude+", "+longitude+")";
    }

    public static final Parcelable.Creator<Point> CREATOR = new Parcelable.Creator<Point>() {

      @Override
      public Point createFromParcel(Parcel in) {
        return new Point(in);
      }

      @Override
      public Point[] newArray(int size) {
        return new Point[size];
      }

    };

    @Override
    public int describeContents() {
      return 0;
    }

    @Override
    public void writeToParcel(Parcel out, int flags) {
      out.writeDouble(latitude);
      out.writeDouble(longitude);
    }

    private Point(Parcel in) {
      latitude = in.readDouble();
      longitude = in.readDouble();
    }

  }

  /** The internal name of the provider for the coarse location */
  private static final String PROVIDER_COARSE = LocationManager.NETWORK_PROVIDER;
  /** The internal name of the provider for the fine location */
  private static final String PROVIDER_FINE = LocationManager.GPS_PROVIDER;
  /** The internal name of the provider for the fine location in passive mode */
  private static final String PROVIDER_FINE_PASSIVE = LocationManager.PASSIVE_PROVIDER;
  /** The default interval to receive new location updates after (in milliseconds) */
  private static final long INTERVAL_DEFAULT = 10 * 60 * 1000;
  /** The factor for conversion from kilometers to meters */
  private static final float KILOMETER_TO_METER = 1000.0f;
  /** The factor for conversion from latitude to kilometers */
  private static final float LATITUDE_TO_KILOMETER = 111.133f;
  /** The factor for conversion from longitude to kilometers at zero degree in latitude */
  private static final float LONGITUDE_TO_KILOMETER_AT_ZERO_LATITUDE = 111.320f;
  /** The PRNG that is used for location blurring */
  private static final Random mRandom = new Random();
  private static final double SQUARE_ROOT_TWO = Math.sqrt(2);
  /** The last location that was internally cached when creating new instances in the same process */
  private static Location mCachedPosition;
  /** The LocationManager instance used to query the device location */
  private final LocationManager mLocationManager;
  /** Whether a fine location should be required or coarse location can be used */
  private final boolean mRequireFine;
  /** Whether passive mode shall be used or not */
  private final boolean mPassive;
  /** The internal after which new location updates are requested (in milliseconds) where longer intervals save battery */
  private final long mInterval;
  /** The blur radius (in meters) that will be used to blur the location for privacy reasons */
  private int mBlurRadius;
  /** The LocationListener instance used internally to listen for location updates */
  private LocationListener mLocationListener;
  /** The current location with latitude, longitude, speed and altitude */
  private Location mPosition;

  /**
   * Constructs a new instance with default granularity, mode and interval
   *
   * @param context the Context reference to get the system service from
   */
  public SimpleLocation(final Context context) {
    this(context, false);
  }

  /**
   * Constructs a new instance with default mode and interval
   *
   * @param context the Context reference to get the system service from
   * @param requireFine whether to require fine location or use coarse location
   */
  public SimpleLocation(final Context context, final boolean requireFine) {
    this(context, requireFine, false);
  }

  /**
   * Constructs a new instance with default interval
   *
   * @param context the Context reference to get the system service from
   * @param requireFine whether to require fine location or use coarse location
   * @param passive whether to use passive mode (to save battery) or active mode
   */
  public SimpleLocation(final Context context, final boolean requireFine, final boolean passive) {
    this(context, requireFine, passive, INTERVAL_DEFAULT);
  }

  /**
   * Constructs a new instance
   *
   * @param context the Context reference to get the system service from
   * @param requireFine whether to require fine location or use coarse location
   * @param passive whether to use passive mode (to save battery) or active mode
   * @param interval the interval to request new location updates after (in milliseconds) where longer intervals save battery
   */
  public SimpleLocation(final Context context, final boolean requireFine, final boolean passive, final long interval) {
    mLocationManager = (LocationManager) context.getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
    mRequireFine = requireFine;
    mPassive = passive;
    mInterval = interval;

    mPosition = getCachedPosition();
    cachePosition();
  }

  /**
   * Whether the device has location access enabled in the settings
   *
   * @return whether location access is enabled or not
   */
  public boolean hasLocationEnabled() {
    if (mRequireFine) {
      return mLocationManager.isProviderEnabled(getProviderName());
    }
    else {
      if (mLocationManager.isProviderEnabled(getProviderName(false))) {
        return true;
      }
      else {
        try {
          return mLocationManager.isProviderEnabled(getProviderName(true));
        }
        catch (Exception e) {
          return false;
        }
      }
    }
  }

  /** Starts updating the location and requesting new updates after the defined interval */
  public void beginUpdates() {
    if (mLocationListener != null) {
      endUpdates();
    }

    mPosition = getCachedPosition();

    mLocationListener = createLocationListener();
    mLocationManager.requestLocationUpdates(getProviderName(), mInterval, 0, mLocationListener);
  }

  /** Stops the location updates when they aren't needed anymore so that battery can be saved */
  public void endUpdates() {
    if (mLocationListener != null) {
      mLocationManager.removeUpdates(mLocationListener);
      mLocationListener = null;
    }
  }

  /**
   * Blurs the specified location with the defined blur radius or returns an unchanged location if no blur radius is set
   *
   * @param originalLocation the original location received from the device
   * @return the blurred location
   */
  private Location blurWithRadius(final Location originalLocation) {
    if (mBlurRadius <= 0) {
      return originalLocation;
    }
    else {
      Location newLocation = new Location(originalLocation);

      double blurMeterLong = calculateRandomOffset(mBlurRadius) / SQUARE_ROOT_TWO;
      double blurMeterLat = calculateRandomOffset(mBlurRadius) / SQUARE_ROOT_TWO;

      newLocation.setLongitude(newLocation.getLongitude() + meterToLongitude(blurMeterLong, newLocation.getLatitude()));
      newLocation.setLatitude(newLocation.getLatitude() + meterToLatitude(blurMeterLat));

      return newLocation;
    }
  }

  /**
   * For any radius `n`, calculate a random offset in the range `[-n, n]`
   *
   * @param radius the radius
   * @return the random offset
   */
  private static int calculateRandomOffset(final int radius) {
    return mRandom.nextInt((radius + 1) * 2) - radius;
  }

  /**
   * Returns the current position as a Point instance
   *
   * @return the current location (if any) or `null`
   */
  public Point getPosition() {
    if (mPosition == null) {
      return null;
    }
    else {
      Location position = blurWithRadius(mPosition);
      return new Point(position.getLatitude(), position.getLongitude());
    }
  }

  /**
   * Returns the latitude of the current location
   *
   * @return the current latitude (if any) or `0`
   */
  public double getLatitude() {
    if (mPosition == null) {
      return 0.0f;
    }
    else {
      Location position = blurWithRadius(mPosition);
      return position.getLatitude();
    }
  }

  /**
   * Returns the longitude of the current location
   *
   * @return the current longitude (if any) or `0`
   */
  public double getLongitude() {
    if (mPosition == null) {
      return 0.0f;
    }
    else {
      Location position = blurWithRadius(mPosition);
      return position.getLongitude();
    }
  }

  /**
   * Returns the current speed
   *
   * @return the current speed (if detected) or `0`
   */
  public float getSpeed() {
    if (mPosition == null) {
      return 0.0f;
    }
    else {
      return mPosition.getSpeed();
    }
  }

  /**
   * Returns the current altitude
   *
   * @return the current altitude (if detected) or `0`
   */
  public double getAltitude() {
    if (mPosition == null) {
      return 0.0f;
    }
    else {
      return mPosition.getAltitude();
    }
  }

  /**
   * Sets the blur radius (in meters) to use for privacy reasons
   *
   * @param blurRadius the blur radius (in meters)
   */
  public void setBlurRadius(final int blurRadius) {
    mBlurRadius = blurRadius;
  }

  /**
   * Creates a new LocationListener instance used internally to listen for location updates
   *
   * @return the new LocationListener instance
   */
  private LocationListener createLocationListener() {
    return new LocationListener() {

      @Override
      public void onLocationChanged(Location location) {
        mPosition = location;
        cachePosition();
      }

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

      @Override
      public void onProviderEnabled(String provider) { }

      @Override
      public void onProviderDisabled(String provider) { }

    };
  }

  /**
   * Returns the name of the location provider that matches the specified settings
   *
   * @return the provider's name
   */
  private String getProviderName() {
    return getProviderName(mRequireFine);
  }

  /**
   * Returns the name of the location provider that matches the specified settings and depends on the given granularity
   *
   * @param whether to require fine location or use coarse location
   * @return the provider's name
   */
  private String getProviderName(final boolean requireFine) {
    if (requireFine) {
      if (mPassive) {
        return PROVIDER_FINE_PASSIVE;
      }
      else {
        return PROVIDER_FINE;
      }
    }
    else {
      if (mPassive) {
        throw new RuntimeException("There is no passive provider for the coarse location");
      }
      else {
        return PROVIDER_COARSE;
      }
    }
  }

  /**
   * Returns the last position from the cache
   *
   * @return the cached position
   */
  private Location getCachedPosition() {
    if (mCachedPosition != null) {
      return mCachedPosition;
    }
    else {
      return mLocationManager.getLastKnownLocation(getProviderName());
    }
  }

  /** Caches the current position */
  private void cachePosition() {
    if (mPosition != null) {
      mCachedPosition = mPosition;
    }
  }

  /**
   * Opens the device's settings screen where location access can be enabled
   *
   * @param context the Context reference to start the Intent from
   */
  public static void openSettings(final Context context) {
    context.startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
  }

  /**
   * Converts a difference in latitude to a difference in kilometers (rough estimation)
   *
   * @param latitude the latitude (difference)
   * @return the kilometers (difference)
   */
  public static double latitudeToKilometer(double latitude) {
    return latitude * LATITUDE_TO_KILOMETER;
  }

  /**
   * Converts a difference in kilometers to a difference in latitude (rough estimation)
   * @param kilometer the kilometers (difference)
   * @return the latitude (difference)
   */
  public static double kilometerToLatitude(double kilometer) {
    return kilometer / latitudeToKilometer(1.0f);
  }

  /**
   * Converts a difference in latitude to a difference in meters (rough estimation)
   *
   * @param latitude the latitude (difference)
   * @return the meters (difference)
   */
  public static double latitudeToMeter(double latitude) {
    return latitudeToKilometer(latitude) * KILOMETER_TO_METER;
  }

  /**
   * Converts a difference in meters to a difference in latitude (rough estimation)
   * @param meter the meters (difference)
   * @return the latitude (difference)
   */
  public static double meterToLatitude(double meter) {
    return meter / latitudeToMeter(1.0f);
  }

  /**
   * Converts a difference in longitude to a difference in kilometers (rough estimation)
   *
   * @param longitude the longitude (difference)
   * @param latitude the latitude (absolute)
   * @return the kilometers (difference)
   */
  public static double longitudeToKilometer(double longitude, double latitude) {
    return longitude * LONGITUDE_TO_KILOMETER_AT_ZERO_LATITUDE * Math.cos(Math.toRadians(latitude));
  }

  /**
   * Converts a difference in kilometers to a difference in longitude (rough estimation)
   * @param kilometer the kilometers (difference)
   * @param latitude the latitude (absolute)
   * @return the longitude (difference)
   */
  public static double kilometerToLongitude(double kilometer, double latitude) {
    return kilometer / longitudeToKilometer(1.0f, latitude);
  }

  /**
   * Converts a difference in longitude to a difference in meters (rough estimation)
   *
   * @param longitude the longitude (difference)
   * @param latitude the latitude (absolute)
   * @return the meters (difference)
   */
  public static double longitudeToMeter(double longitude, double latitude) {
    return longitudeToKilometer(longitude, latitude) * KILOMETER_TO_METER;
  }

  /**
   * Converts a difference in meters to a difference in longitude (rough estimation)
   * @param meter the meters (difference)
   * @param latitude the latitude (absolute)
   * @return the longitude (difference)
   */
  public static double meterToLongitude(double meter, double latitude) {
    return meter / longitudeToMeter(1.0f, latitude);
  }

  /**
   * Calculates the difference from the start position to the end position (in meters)
   *
   * @param start the start position
   * @param end the end position
   * @return the distance in meters
   */
  public static double calculateDistance(Point start, Point end) {
    return calculateDistance(start.latitude, start.longitude, end.latitude, end.longitude);
  }

  /**
   * Calculates the difference from the start position to the end position (in meters)
   *
   * @param startLatitude the latitude of the start position
   * @param startLongitude the longitude of the start position
   * @param endLatitude the latitude of the end position
   * @param endLongitude the longitude of the end position
   * @return the distance in meters
   */
  public static double calculateDistance(double startLatitude, double startLongitude, double endLatitude, double endLongitude) {
    float[] results = new float[3];
    Location.distanceBetween(startLatitude, startLongitude, endLatitude, endLongitude, results);
    return results[0];
  }

}




Java Source Code List

im.delight.android.location.SimpleLocation.java