/* Android IMSI-Catcher Detector | (c) AIMSICD Privacy Project * ----------------------------------------------------------- * LICENSE: http://git.io/vki47 | TERMS: http://git.io/vki4o * ----------------------------------------------------------- */ package com.secupwn.aimsicd.service; import android.annotation.TargetApi; import android.content.Context; import android.content.SharedPreferences; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Build; import android.os.Bundle; import com.secupwn.aimsicd.R; import com.secupwn.aimsicd.data.model.GpsLocation; import com.secupwn.aimsicd.utils.Cell; import com.secupwn.aimsicd.utils.GeoLocation; import com.secupwn.aimsicd.utils.RealmHelper; import com.secupwn.aimsicd.utils.TruncatedLocation; import io.freefair.android.util.logging.AndroidLogger; import io.freefair.android.util.logging.Logger; import io.realm.Realm; import lombok.Cleanup; /** * Class to handle GPS location tracking */ public final class LocationTracker { private final Logger log = AndroidLogger.forClass(LocationTracker.class); // how long with no movement detected, before we assume we are not moving public static final long MOVEMENT_THRESHOLD_MS = 20 * 1000; private AimsicdService context; private SharedPreferences prefs; private static LocationManager lm; private LocationListener mLocationListener; private LocationListener extLocationListener; private long lastLocationTime = 0; private Location lastLocation; private static final long GPS_MIN_UPDATE_TIME = 10000; private static final float GPS_MIN_UPDATE_DISTANCE = 10; private RealmHelper mDbHelper; public LocationTracker(AimsicdService service, LocationListener extLocationListener) { this.context = service; this.extLocationListener = extLocationListener; lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); mLocationListener = new MyLocationListener(); prefs = context.getSharedPreferences( AimsicdService.SHARED_PREFERENCES_BASENAME, 0); mDbHelper = new RealmHelper(context); } public void start() { lastKnownLocation(); try { lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, GPS_MIN_UPDATE_TIME, GPS_MIN_UPDATE_DISTANCE, mLocationListener); } catch (IllegalArgumentException e) { log.debug("GPS location provider doesnt exist"); } try { lm.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, GPS_MIN_UPDATE_TIME, GPS_MIN_UPDATE_DISTANCE, mLocationListener); } catch (IllegalArgumentException e) { log.debug("Passive location provider doesnt exist"); } try { lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, GPS_MIN_UPDATE_TIME, GPS_MIN_UPDATE_DISTANCE, mLocationListener); } catch (IllegalArgumentException e) { log.debug("Network location provider doesnt exist"); } } public void stop() { lm.removeUpdates(mLocationListener); } public boolean isGPSOn() { return lm.isProviderEnabled(LocationManager.GPS_PROVIDER); } /** * Check if we are moving, using last known GPS locations * * @return true if user has not moved in a while */ public boolean notMovedInAWhile() { // first-lock, assume no movement if (lastLocationTime <= 0) { return true; } // haven't received a GPS update in a while, assume no movement return System.currentTimeMillis() - lastLocationTime > MOVEMENT_THRESHOLD_MS; } public GeoLocation lastKnownLocation() { GeoLocation loc = null; Location location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER); if (location != null && (Double.doubleToLongBits(location.getLatitude()) != 0 && Double.doubleToLongBits(location.getLongitude()) != 0)) { TruncatedLocation TruncatedLocation = new TruncatedLocation(location); loc = GeoLocation.fromDegrees(TruncatedLocation.getLatitude(), TruncatedLocation.getLongitude()); } else { location = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); if (location != null && (Double.doubleToLongBits(location.getLatitude()) != 0 && Double.doubleToLongBits(location.getLongitude()) != 0)) { TruncatedLocation TruncatedLocation = new TruncatedLocation(location); loc = GeoLocation.fromDegrees(TruncatedLocation.getLatitude(), TruncatedLocation.getLongitude()); } else { String coords = prefs.getString(context.getString(R.string.data_last_lat_lon), null); if (coords != null) { String[] coord = coords.split(":"); loc = GeoLocation.fromDegrees(Double.valueOf(coord[0]), Double.valueOf(coord[1])); } else { // get location from MCC try { Cell cell = context.getCell(); if (cell != null) { log.debug("Looking up MCC " + cell.getMobileCountryCode()); @Cleanup Realm realm = Realm.getDefaultInstance(); GpsLocation defLoc = mDbHelper.getDefaultLocation(realm, cell.getMobileCountryCode()); loc = GeoLocation.fromDegrees(defLoc.getLatitude(), defLoc.getLongitude()); } } catch (Exception e) { log.error("Unable to get location from MCC", e); } } } } if (loc != null) { log.info("Last known location " + loc.toString()); } return loc; } /** * Our location listener, so that we can update our internal status before passing on the events * to the caller */ private final class MyLocationListener implements LocationListener { @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) @Override public void onLocationChanged(Location loc) { if (lastLocation != null && lastLocation.getLongitude() == loc.getLongitude() && lastLocation.getLatitude() == loc.getLatitude()) { // same location as before, so ignore return; } lastLocation = loc; lastLocationTime = System.currentTimeMillis(); extLocationListener.onLocationChanged(loc); } @Override public void onProviderDisabled(String provider) { extLocationListener.onProviderDisabled(provider); } @Override public void onProviderEnabled(String provider) { extLocationListener.onProviderEnabled(provider); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { extLocationListener.onStatusChanged(provider, status, extras); } } }