forked from organicmaps/organicmaps
[android] add: Background GPS tracker.
refactor: Tuned GPS providers.
This commit is contained in:
parent
a4e6c5ccd8
commit
2b1547666c
14 changed files with 377 additions and 172 deletions
|
@ -252,6 +252,15 @@
|
|||
android:name="com.mapswithme.maps.background.WorkerService"
|
||||
android:exported="false"/>
|
||||
|
||||
<receiver android:name="com.mapswithme.maps.location.TrackRecorderWakeReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="com.mapswithme.maps.TRACK_RECORDER_ALARM"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service android:name="com.mapswithme.maps.location.TrackRecorderWakeService"
|
||||
android:exported="false"/>
|
||||
|
||||
<!-- our custom receiver, that will call Aloha & other handlers -->
|
||||
<receiver
|
||||
android:name="com.mapswithme.util.MultipleTrackerReferrerReceiver"
|
||||
|
@ -311,7 +320,5 @@
|
|||
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -15,10 +15,15 @@ import android.widget.ProgressBar;
|
|||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import com.mapswithme.country.StorageOptions;
|
||||
import com.mapswithme.maps.MapStorage.Index;
|
||||
import com.mapswithme.maps.MwmActivity.MapTask;
|
||||
import com.mapswithme.maps.MwmActivity.OpenUrlTask;
|
||||
import com.mapswithme.maps.MapStorage.Index;
|
||||
import com.mapswithme.maps.api.Const;
|
||||
import com.mapswithme.maps.api.ParsedMwmRequest;
|
||||
import com.mapswithme.maps.base.BaseMwmFragmentActivity;
|
||||
|
@ -33,11 +38,6 @@ import com.mapswithme.util.Yota;
|
|||
import com.mapswithme.util.concurrency.ThreadPool;
|
||||
import com.mapswithme.util.statistics.Statistics;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
@SuppressLint("StringFormatMatches")
|
||||
public class DownloadResourcesActivity extends BaseMwmFragmentActivity
|
||||
implements LocationHelper.LocationListener, MapStorage.Listener
|
||||
|
@ -115,7 +115,7 @@ public class DownloadResourcesActivity extends BaseMwmFragmentActivity
|
|||
{
|
||||
super.onResume();
|
||||
|
||||
LocationHelper.INSTANCE.addLocationListener(this);
|
||||
LocationHelper.INSTANCE.addLocationListener(this, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -624,7 +624,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||
@Override
|
||||
public void onLocationError(int errorCode)
|
||||
{
|
||||
MapFragment.nativeOnLocationError(errorCode);
|
||||
LocationHelper.nativeOnLocationError(errorCode);
|
||||
|
||||
if (errorCode == LocationHelper.ERROR_DENIED)
|
||||
{
|
||||
|
@ -665,13 +665,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||
if (!location.getProvider().equals(LocationHelper.LOCATION_PREDICTOR_PROVIDER))
|
||||
mLocationPredictor.reset(location);
|
||||
|
||||
MapFragment.nativeLocationUpdated(location.getTime(),
|
||||
location.getLatitude(),
|
||||
location.getLongitude(),
|
||||
location.getAccuracy(),
|
||||
location.getAltitude(),
|
||||
location.getSpeed(),
|
||||
location.getBearing());
|
||||
LocationHelper.onLocationUpdated(location);
|
||||
|
||||
if (mPlacePage.getState() != State.HIDDEN)
|
||||
mPlacePage.refreshLocation(location);
|
||||
|
@ -816,7 +810,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||
|
||||
private void resumeLocation()
|
||||
{
|
||||
LocationHelper.INSTANCE.addLocationListener(this);
|
||||
LocationHelper.INSTANCE.addLocationListener(this, true);
|
||||
// Do not turn off the screen while displaying position
|
||||
Utils.keepScreenOn(true, getWindow());
|
||||
mLocationPredictor.resume();
|
||||
|
|
|
@ -17,6 +17,7 @@ import com.mapswithme.country.CountryItem;
|
|||
import com.mapswithme.maps.background.AppBackgroundTracker;
|
||||
import com.mapswithme.maps.background.Notifier;
|
||||
import com.mapswithme.maps.bookmarks.data.BookmarkManager;
|
||||
import com.mapswithme.maps.location.TrackRecorder;
|
||||
import com.mapswithme.maps.sound.TtsPlayer;
|
||||
import com.mapswithme.util.Config;
|
||||
import com.mapswithme.util.Constants;
|
||||
|
@ -114,6 +115,7 @@ public class MwmApplication extends Application
|
|||
initParse();
|
||||
mPrefs = getSharedPreferences(getString(R.string.pref_file_name), MODE_PRIVATE);
|
||||
mBackgroundTracker = new AppBackgroundTracker();
|
||||
TrackRecorder.init();
|
||||
}
|
||||
|
||||
public void initNativeCore()
|
||||
|
@ -263,6 +265,7 @@ public class MwmApplication extends Application
|
|||
Config.resetAppSessionCounters();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void runNativeFunctorOnUiThread(final long functorPointer)
|
||||
{
|
||||
Message m = Message.obtain(mMainLoopHandler, new Runnable()
|
||||
|
|
|
@ -9,6 +9,10 @@ import android.view.ViewGroup;
|
|||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.mapswithme.maps.R;
|
||||
import com.mapswithme.maps.bookmarks.data.Bookmark;
|
||||
import com.mapswithme.maps.bookmarks.data.BookmarkCategory;
|
||||
|
@ -17,9 +21,6 @@ import com.mapswithme.maps.bookmarks.data.Track;
|
|||
import com.mapswithme.maps.location.LocationHelper;
|
||||
import com.mapswithme.util.Graphics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class BookmarkListAdapter extends BaseAdapter
|
||||
implements LocationHelper.LocationListener
|
||||
|
@ -43,7 +44,7 @@ public class BookmarkListAdapter extends BaseAdapter
|
|||
|
||||
public void startLocationUpdate()
|
||||
{
|
||||
LocationHelper.INSTANCE.addLocationListener(this);
|
||||
LocationHelper.INSTANCE.addLocationListener(this, true);
|
||||
}
|
||||
|
||||
public void stopLocationUpdate()
|
||||
|
|
|
@ -4,17 +4,16 @@ package com.mapswithme.maps.location;
|
|||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.mapswithme.maps.MwmApplication;
|
||||
import com.mapswithme.util.LocationUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class AndroidNativeProvider extends BaseLocationProvider implements android.location.LocationListener
|
||||
import com.mapswithme.maps.MwmApplication;
|
||||
import com.mapswithme.util.LocationUtils;
|
||||
|
||||
public class AndroidNativeProvider extends BaseLocationProvider
|
||||
{
|
||||
private LocationManager mLocationManager;
|
||||
private final LocationManager mLocationManager;
|
||||
private boolean mIsActive;
|
||||
|
||||
public AndroidNativeProvider()
|
||||
|
@ -36,7 +35,7 @@ public class AndroidNativeProvider extends BaseLocationProvider implements andro
|
|||
{
|
||||
mIsActive = true;
|
||||
for (final String provider : providers)
|
||||
mLocationManager.requestLocationUpdates(provider, LOCATION_UPDATE_INTERVAL, 0, this);
|
||||
mLocationManager.requestLocationUpdates(provider, LocationHelper.INSTANCE.getUpdateInterval(), 0, this);
|
||||
|
||||
LocationHelper.INSTANCE.registerSensorListeners();
|
||||
|
||||
|
@ -97,36 +96,4 @@ public class AndroidNativeProvider extends BaseLocationProvider implements andro
|
|||
|
||||
return acceptedProviders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(Location l)
|
||||
{
|
||||
// Completely ignore locations without lat and lon
|
||||
if (l.getAccuracy() <= 0.0)
|
||||
return;
|
||||
|
||||
if (isLocationBetterThanLast(l))
|
||||
{
|
||||
LocationHelper.INSTANCE.initMagneticField(l);
|
||||
LocationHelper.INSTANCE.setLastLocation(l);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderDisabled(String provider)
|
||||
{
|
||||
mLogger.d("Disabled location provider: ", provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderEnabled(String provider)
|
||||
{
|
||||
mLogger.d("Enabled location provider: ", provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras)
|
||||
{
|
||||
mLogger.d("Status changed for location provider: ", provider, status);
|
||||
}
|
||||
}
|
|
@ -2,33 +2,68 @@ package com.mapswithme.maps.location;
|
|||
|
||||
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.mapswithme.util.LocationUtils;
|
||||
import com.mapswithme.util.log.Logger;
|
||||
import com.mapswithme.util.log.SimpleLogger;
|
||||
|
||||
public abstract class BaseLocationProvider
|
||||
abstract class BaseLocationProvider implements LocationListener
|
||||
{
|
||||
protected static final long LOCATION_UPDATE_INTERVAL = 500;
|
||||
public static final double DEFAULT_SPEED_MPS = 5;
|
||||
public static final float DISTANCE_TO_RECREATE_MAGNETIC_FIELD_M = 1000;
|
||||
private static final double DEFAULT_SPEED_MPS = 5;
|
||||
|
||||
protected static final Logger mLogger = SimpleLogger.get(BaseLocationProvider.class.getName());
|
||||
protected static final Logger sLogger = SimpleLogger.get(BaseLocationProvider.class.getName());
|
||||
|
||||
protected abstract void startUpdates();
|
||||
|
||||
protected abstract void stopUpdates();
|
||||
|
||||
protected boolean isLocationBetterThanLast(Location newLocation)
|
||||
protected boolean isLocationBetterThanLast(Location newLocation, Location lastLocation)
|
||||
{
|
||||
double speed = Math.max(DEFAULT_SPEED_MPS, (newLocation.getSpeed() + lastLocation.getSpeed()) / 2.0);
|
||||
double lastAccuracy = (lastLocation.getAccuracy() + speed * LocationUtils.getDiffWithLastLocation(lastLocation, newLocation));
|
||||
return (newLocation.getAccuracy() < lastAccuracy);
|
||||
}
|
||||
|
||||
protected final boolean isLocationBetterThanLast(Location newLocation)
|
||||
{
|
||||
if (newLocation == null)
|
||||
return false;
|
||||
|
||||
final Location lastLocation = LocationHelper.INSTANCE.getLastLocation();
|
||||
if (lastLocation == null)
|
||||
return true;
|
||||
return (lastLocation == null || isLocationBetterThanLast(newLocation, lastLocation));
|
||||
}
|
||||
|
||||
final double s = Math.max(DEFAULT_SPEED_MPS, (newLocation.getSpeed() + lastLocation.getSpeed()) / 2.0);
|
||||
return (newLocation.getAccuracy() < (lastLocation.getAccuracy() + s * LocationUtils.getDiffWithLastLocation(lastLocation, newLocation)));
|
||||
@Override
|
||||
public void onLocationChanged(Location location)
|
||||
{
|
||||
// Completely ignore locations without lat and lon
|
||||
if (location.getAccuracy() <= 0.0)
|
||||
return;
|
||||
|
||||
if (isLocationBetterThanLast(location))
|
||||
{
|
||||
LocationHelper.INSTANCE.initMagneticField(location);
|
||||
LocationHelper.INSTANCE.setLastLocation(location);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderDisabled(String provider)
|
||||
{
|
||||
sLogger.d("Disabled location provider: ", provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderEnabled(String provider)
|
||||
{
|
||||
sLogger.d("Enabled location provider: ", provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras)
|
||||
{
|
||||
sLogger.d("Status changed for location provider: ", provider, status);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,34 +11,36 @@ import com.google.android.gms.location.LocationServices;
|
|||
import com.mapswithme.maps.MwmApplication;
|
||||
|
||||
public class GoogleFusedLocationProvider extends BaseLocationProvider
|
||||
implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener
|
||||
implements GoogleApiClient.ConnectionCallbacks,
|
||||
GoogleApiClient.OnConnectionFailedListener,
|
||||
LocationListener
|
||||
{
|
||||
private static final String GS_LOCATION_PROVIDER = "fused";
|
||||
|
||||
private final GoogleApiClient mGoogleApiClient;
|
||||
private LocationRequest mLocationRequest;
|
||||
private GoogleApiClient mGoogleApiClient;
|
||||
|
||||
private boolean mIsResolvingError;
|
||||
|
||||
public GoogleFusedLocationProvider()
|
||||
{
|
||||
mGoogleApiClient = new GoogleApiClient.Builder(MwmApplication.get())
|
||||
.addApi(LocationServices.API)
|
||||
.addConnectionCallbacks(this)
|
||||
.addOnConnectionFailedListener(this)
|
||||
.build();
|
||||
|
||||
mLocationRequest = LocationRequest.create();
|
||||
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
|
||||
mLocationRequest.setInterval(LOCATION_UPDATE_INTERVAL);
|
||||
mLocationRequest.setFastestInterval(LOCATION_UPDATE_INTERVAL / 2);
|
||||
.addApi(LocationServices.API)
|
||||
.addConnectionCallbacks(this)
|
||||
.addOnConnectionFailedListener(this)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startUpdates()
|
||||
{
|
||||
if (mGoogleApiClient != null && !mGoogleApiClient.isConnected() && !mGoogleApiClient.isConnecting())
|
||||
{
|
||||
mLocationRequest = LocationRequest.create();
|
||||
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
|
||||
mLocationRequest.setInterval(LocationHelper.INSTANCE.getUpdateInterval());
|
||||
mLocationRequest.setFastestInterval(LocationHelper.INSTANCE.getUpdateInterval() / 2);
|
||||
|
||||
mGoogleApiClient.connect();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -53,25 +55,18 @@ public class GoogleFusedLocationProvider extends BaseLocationProvider
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean isLocationBetterThanLast(Location newLocation)
|
||||
protected boolean isLocationBetterThanLast(Location newLocation, Location lastLocation)
|
||||
{
|
||||
if (newLocation == null)
|
||||
return false;
|
||||
|
||||
Location lastLocation = LocationHelper.INSTANCE.getLastLocation();
|
||||
if (lastLocation == null)
|
||||
return true;
|
||||
|
||||
// We believe that google service always returns good locations.
|
||||
return GS_LOCATION_PROVIDER.equalsIgnoreCase(newLocation.getProvider()) ||
|
||||
!GS_LOCATION_PROVIDER.equalsIgnoreCase(lastLocation.getProvider()) && super.isLocationBetterThanLast(newLocation);
|
||||
!GS_LOCATION_PROVIDER.equalsIgnoreCase(lastLocation.getProvider()) && super.isLocationBetterThanLast(newLocation, lastLocation);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnected(Bundle bundle)
|
||||
{
|
||||
mLogger.d("Fused onConnected. Bundle " + bundle);
|
||||
sLogger.d("Fused onConnected. Bundle " + bundle);
|
||||
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
|
||||
LocationHelper.INSTANCE.registerSensorListeners();
|
||||
final Location l = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
|
||||
|
@ -82,28 +77,14 @@ public class GoogleFusedLocationProvider extends BaseLocationProvider
|
|||
@Override
|
||||
public void onConnectionSuspended(int i)
|
||||
{
|
||||
mLogger.d("Fused onConnectionSuspended. Code " + i);
|
||||
sLogger.d("Fused onConnectionSuspended. Code " + i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionFailed(ConnectionResult connectionResult)
|
||||
{
|
||||
mLogger.d("Fused onConnectionFailed. Fall back to native provider. ConnResult " + connectionResult);
|
||||
sLogger.d("Fused onConnectionFailed. Fall back to native provider. ConnResult " + connectionResult);
|
||||
// TODO handle error in a smarter way
|
||||
LocationHelper.INSTANCE.initLocationProvider(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(Location location)
|
||||
{
|
||||
// Completely ignore locations without lat and lon
|
||||
if (location.getAccuracy() <= 0.0)
|
||||
return;
|
||||
|
||||
if (isLocationBetterThanLast(location))
|
||||
{
|
||||
LocationHelper.INSTANCE.initMagneticField(location);
|
||||
LocationHelper.INSTANCE.setLastLocation(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,17 +15,14 @@ import android.support.annotation.NonNull;
|
|||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.GoogleApiAvailability;
|
||||
import com.mapswithme.maps.LocationState;
|
||||
import com.mapswithme.maps.MwmApplication;
|
||||
import com.mapswithme.maps.R;
|
||||
import com.mapswithme.maps.background.AppBackgroundTracker;
|
||||
import com.mapswithme.maps.bookmarks.data.MapObject;
|
||||
import com.mapswithme.util.Listeners;
|
||||
import com.mapswithme.util.LocationUtils;
|
||||
import com.mapswithme.util.concurrency.UiThread;
|
||||
import com.mapswithme.util.log.Logger;
|
||||
|
@ -43,6 +40,9 @@ public enum LocationHelper implements SensorEventListener
|
|||
public static final int ERROR_GPS_OFF = 3;
|
||||
|
||||
public static final String LOCATION_PREDICTOR_PROVIDER = "LocationPredictorProvider";
|
||||
private static final float DISTANCE_TO_RECREATE_MAGNETIC_FIELD_M = 1000;
|
||||
private static final long UPDATE_INTERVAL_FOREGROUND = 500;
|
||||
private static final long UPDATE_INTERVAL_BACKGROUND = 10000;
|
||||
private static final long STOP_DELAY = 5000;
|
||||
|
||||
public interface LocationListener
|
||||
|
@ -52,9 +52,10 @@ public enum LocationHelper implements SensorEventListener
|
|||
void onLocationError(int errorCode);
|
||||
}
|
||||
|
||||
private final Set<LocationListener> mListeners = new LinkedHashSet<>();
|
||||
private final List<LocationListener> mListenersToRemove = new ArrayList<>();
|
||||
private boolean mIteratingListener;
|
||||
private final Listeners<LocationListener> mListeners = new Listeners<>();
|
||||
|
||||
private boolean mActive;
|
||||
private boolean mForegroundMode;
|
||||
|
||||
private Location mLastLocation;
|
||||
private MapObject.MyPosition mMyPosition;
|
||||
|
@ -76,6 +77,10 @@ public enum LocationHelper implements SensorEventListener
|
|||
@Override
|
||||
public void run()
|
||||
{
|
||||
if (!mActive)
|
||||
return;
|
||||
|
||||
mActive = false;
|
||||
mLocationProvider.stopUpdates();
|
||||
mMagneticField = null;
|
||||
if (mSensorManager != null)
|
||||
|
@ -93,6 +98,15 @@ public enum LocationHelper implements SensorEventListener
|
|||
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||
mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
|
||||
}
|
||||
|
||||
MwmApplication.backgroundTracker().addListener(new AppBackgroundTracker.OnTransitionListener()
|
||||
{
|
||||
@Override
|
||||
public void onTransit(boolean foreground)
|
||||
{
|
||||
setForegroundMode(foreground);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
|
@ -135,7 +149,8 @@ public enum LocationHelper implements SensorEventListener
|
|||
mLocationProvider = new AndroidNativeProvider();
|
||||
}
|
||||
|
||||
if (!mListeners.isEmpty())
|
||||
mActive = !mListeners.isEmpty();
|
||||
if (mActive)
|
||||
mLocationProvider.startUpdates();
|
||||
}
|
||||
|
||||
|
@ -168,77 +183,53 @@ public enum LocationHelper implements SensorEventListener
|
|||
notifyLocationUpdated();
|
||||
}
|
||||
|
||||
private void startIteratingListeners()
|
||||
{
|
||||
mIteratingListener = true;
|
||||
}
|
||||
|
||||
private void finishIteratingListeners()
|
||||
{
|
||||
mIteratingListener = false;
|
||||
if (!mListenersToRemove.isEmpty())
|
||||
{
|
||||
mListeners.removeAll(mListenersToRemove);
|
||||
mListenersToRemove.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void notifyLocationUpdated()
|
||||
{
|
||||
if (mLastLocation == null)
|
||||
return;
|
||||
|
||||
startIteratingListeners();
|
||||
for (LocationListener listener : mListeners)
|
||||
listener.onLocationUpdated(mLastLocation);
|
||||
finishIteratingListeners();
|
||||
mListeners.finishIterate();
|
||||
}
|
||||
|
||||
void notifyLocationError(int errCode)
|
||||
{
|
||||
startIteratingListeners();
|
||||
for (LocationListener listener : mListeners)
|
||||
listener.onLocationError(errCode);
|
||||
finishIteratingListeners();
|
||||
mListeners.finishIterate();
|
||||
}
|
||||
|
||||
private void notifyCompassUpdated(long time, double magneticNorth, double trueNorth, double accuracy)
|
||||
{
|
||||
startIteratingListeners();
|
||||
for (LocationListener listener : mListeners)
|
||||
listener.onCompassUpdated(time, magneticNorth, trueNorth, accuracy);
|
||||
finishIteratingListeners();
|
||||
mListeners.finishIterate();
|
||||
}
|
||||
|
||||
@android.support.annotation.UiThread
|
||||
public void addLocationListener(LocationListener listener)
|
||||
public void addLocationListener(LocationListener listener, boolean forceUpdate)
|
||||
{
|
||||
UiThread.cancelDelayedTasks(mStopLocationTask);
|
||||
|
||||
if (mListeners.isEmpty())
|
||||
{
|
||||
mActive = true;
|
||||
mLocationProvider.startUpdates();
|
||||
mListeners.add(listener);
|
||||
notifyLocationUpdated();
|
||||
}
|
||||
|
||||
mListeners.register(listener);
|
||||
if (forceUpdate)
|
||||
notifyLocationUpdated();
|
||||
}
|
||||
|
||||
@android.support.annotation.UiThread
|
||||
public void removeLocationListener(LocationListener listener)
|
||||
{
|
||||
boolean empty = false;
|
||||
if (mIteratingListener)
|
||||
{
|
||||
if (mListeners.contains(listener))
|
||||
{
|
||||
mListenersToRemove.add(listener);
|
||||
empty = (mListeners.size() == 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mListeners.remove(listener);
|
||||
empty = mListeners.isEmpty();
|
||||
}
|
||||
boolean wasEmpty = mListeners.isEmpty();
|
||||
mListeners.unregister(listener);
|
||||
|
||||
if (empty)
|
||||
if (!wasEmpty && mListeners.isEmpty())
|
||||
// Make a delay with disconnection from location providers, so that orientation changes and short app sleeps
|
||||
// doesn't take long time to connect again.
|
||||
UiThread.runLater(mStopLocationTask, STOP_DELAY);
|
||||
|
@ -248,18 +239,19 @@ public enum LocationHelper implements SensorEventListener
|
|||
{
|
||||
if (mSensorManager != null)
|
||||
{
|
||||
final int COMPASS_REFRESH_MKS = SensorManager.SENSOR_DELAY_UI;
|
||||
|
||||
if (mAccelerometer != null)
|
||||
mSensorManager.registerListener(this, mAccelerometer, COMPASS_REFRESH_MKS);
|
||||
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_UI);
|
||||
if (mMagnetometer != null)
|
||||
mSensorManager.registerListener(this, mMagnetometer, COMPASS_REFRESH_MKS);
|
||||
mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_UI);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event)
|
||||
{
|
||||
if (!MwmApplication.get().isFrameworkInitialized())
|
||||
return;
|
||||
|
||||
boolean hasOrientation = false;
|
||||
|
||||
switch (event.sensor.getType())
|
||||
|
@ -298,8 +290,6 @@ public enum LocationHelper implements SensorEventListener
|
|||
}
|
||||
}
|
||||
|
||||
private native float[] nativeUpdateCompassSensor(int ind, float[] arr);
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
|
||||
|
||||
|
@ -309,9 +299,41 @@ public enum LocationHelper implements SensorEventListener
|
|||
{
|
||||
// Recreate magneticField if location has changed significantly
|
||||
if (mMagneticField == null || mLastLocation == null ||
|
||||
newLocation.distanceTo(mLastLocation) > BaseLocationProvider.DISTANCE_TO_RECREATE_MAGNETIC_FIELD_M)
|
||||
newLocation.distanceTo(mLastLocation) > DISTANCE_TO_RECREATE_MAGNETIC_FIELD_M)
|
||||
mMagneticField = new GeomagneticField((float) newLocation.getLatitude(), (float) newLocation.getLongitude(),
|
||||
(float) newLocation.getAltitude(), newLocation.getTime());
|
||||
}
|
||||
}
|
||||
|
||||
private void setForegroundMode(boolean set)
|
||||
{
|
||||
mForegroundMode = set;
|
||||
if (!mActive)
|
||||
return;
|
||||
|
||||
mLocationProvider.stopUpdates();
|
||||
if (!mListeners.isEmpty())
|
||||
mLocationProvider.startUpdates();
|
||||
}
|
||||
|
||||
public long getUpdateInterval()
|
||||
{
|
||||
return (mForegroundMode ? UPDATE_INTERVAL_FOREGROUND
|
||||
: UPDATE_INTERVAL_BACKGROUND);
|
||||
}
|
||||
|
||||
public static void onLocationUpdated(Location location)
|
||||
{
|
||||
nativeLocationUpdated(location.getTime(),
|
||||
location.getLatitude(),
|
||||
location.getLongitude(),
|
||||
location.getAccuracy(),
|
||||
location.getAltitude(),
|
||||
location.getSpeed(),
|
||||
location.getBearing());
|
||||
}
|
||||
|
||||
public static native void nativeOnLocationError(int errorCode);
|
||||
private static native void nativeLocationUpdated(long time, double lat, double lon, float accuracy, double altitude, float speed, float bearing);
|
||||
private static native float[] nativeUpdateCompassSensor(int ind, float[] arr);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,108 @@
|
|||
package com.mapswithme.maps.location;
|
||||
|
||||
public class TrackRecorder
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.location.Location;
|
||||
|
||||
import com.mapswithme.maps.MwmApplication;
|
||||
import com.mapswithme.maps.background.AppBackgroundTracker;
|
||||
|
||||
public final class TrackRecorder
|
||||
{
|
||||
public static native void nativeSetEnabled(boolean enable);
|
||||
public static native boolean nativeIsEnabled();
|
||||
public static native void nativeSetDuration(int hours);
|
||||
public static native int nativeGetDuration();
|
||||
private static final AlarmManager sAlarmManager = (AlarmManager)MwmApplication.get().getSystemService(Context.ALARM_SERVICE);
|
||||
private static final Intent sAlarmIntent = new Intent("com.mapswithme.maps.TRACK_RECORDER_ALARM");
|
||||
|
||||
private static final LocationHelper.LocationListener mLocationListener = new LocationHelper.LocationListener()
|
||||
{
|
||||
@Override
|
||||
public void onLocationUpdated(Location location)
|
||||
{
|
||||
LocationHelper.onLocationUpdated(location);
|
||||
TrackRecorderWakeService.stop();
|
||||
checkState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationError(int errorCode)
|
||||
{
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompassUpdated(long time, double magneticNorth, double trueNorth, double accuracy) {}
|
||||
};
|
||||
|
||||
private TrackRecorder() {}
|
||||
|
||||
public static void init()
|
||||
{
|
||||
MwmApplication.backgroundTracker().addListener(new AppBackgroundTracker.OnTransitionListener()
|
||||
{
|
||||
@Override
|
||||
public void onTransit(boolean foreground)
|
||||
{
|
||||
checkState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void checkState()
|
||||
{
|
||||
if (MwmApplication.backgroundTracker().isForeground() || !isEnabled())
|
||||
{
|
||||
sAlarmManager.cancel(getAlarmIntent());
|
||||
TrackRecorderWakeService.stop();
|
||||
}
|
||||
else
|
||||
sAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + LocationHelper.INSTANCE.getUpdateInterval(), getAlarmIntent());
|
||||
}
|
||||
|
||||
private static PendingIntent getAlarmIntent()
|
||||
{
|
||||
return PendingIntent.getBroadcast(MwmApplication.get(), 0, sAlarmIntent, 0);
|
||||
}
|
||||
|
||||
public static boolean isEnabled()
|
||||
{
|
||||
return nativeIsEnabled();
|
||||
}
|
||||
|
||||
public static void setEnabled(boolean enabled)
|
||||
{
|
||||
nativeSetEnabled(enabled);
|
||||
checkState();
|
||||
}
|
||||
|
||||
public static int getDuration()
|
||||
{
|
||||
return nativeGetDuration();
|
||||
}
|
||||
|
||||
public static void setDuration(int hours)
|
||||
{
|
||||
nativeSetDuration(hours);
|
||||
}
|
||||
|
||||
static void onWakeAlarm()
|
||||
{
|
||||
if (nativeIsEnabled())
|
||||
TrackRecorderWakeService.start();
|
||||
}
|
||||
|
||||
static void onServiceStarted()
|
||||
{
|
||||
LocationHelper.INSTANCE.addLocationListener(mLocationListener, false);
|
||||
}
|
||||
|
||||
static void onServiceStopped()
|
||||
{
|
||||
LocationHelper.INSTANCE.removeLocationListener(mLocationListener);
|
||||
}
|
||||
|
||||
private static native void nativeSetEnabled(boolean enable);
|
||||
private static native boolean nativeIsEnabled();
|
||||
private static native void nativeSetDuration(int hours);
|
||||
private static native int nativeGetDuration();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package com.mapswithme.maps.location;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
public class TrackRecorderWakeReceiver extends BroadcastReceiver
|
||||
{
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent)
|
||||
{
|
||||
TrackRecorder.onWakeAlarm();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package com.mapswithme.maps.location;
|
||||
|
||||
import android.app.IntentService;
|
||||
import android.content.Intent;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.WakefulBroadcastReceiver;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.mapswithme.maps.MwmApplication;
|
||||
|
||||
public class TrackRecorderWakeService extends IntentService
|
||||
{
|
||||
private static final long TIMEOUT_MS = 30000;
|
||||
private static WeakReference<TrackRecorderWakeService> sServiceRef;
|
||||
private final CountDownLatch mWaitMonitor = new CountDownLatch(1);
|
||||
|
||||
private static @Nullable TrackRecorderWakeService getService()
|
||||
{
|
||||
if (sServiceRef == null)
|
||||
return null;
|
||||
|
||||
TrackRecorderWakeService res = sServiceRef.get();
|
||||
if (res == null)
|
||||
sServiceRef = null;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public TrackRecorderWakeService()
|
||||
{
|
||||
super("TrackRecorderWakeService");
|
||||
}
|
||||
|
||||
protected void cancel()
|
||||
{
|
||||
mWaitMonitor.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void onHandleIntent(Intent intent)
|
||||
{
|
||||
synchronized (TrackRecorderWakeService.class)
|
||||
{
|
||||
TrackRecorderWakeService svc = getService();
|
||||
if (svc != null)
|
||||
return;
|
||||
|
||||
sServiceRef = new WeakReference<>(this);
|
||||
}
|
||||
|
||||
TrackRecorder.onServiceStarted();
|
||||
|
||||
try
|
||||
{
|
||||
mWaitMonitor.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException ignored) {}
|
||||
|
||||
synchronized (getClass())
|
||||
{
|
||||
sServiceRef = null;
|
||||
}
|
||||
|
||||
TrackRecorder.onServiceStopped();
|
||||
WakefulBroadcastReceiver.completeWakefulIntent(intent);
|
||||
}
|
||||
|
||||
public synchronized static void start()
|
||||
{
|
||||
if (getService() == null)
|
||||
WakefulBroadcastReceiver.startWakefulService(MwmApplication.get(), new Intent(MwmApplication.get(), TrackRecorderWakeService.class));
|
||||
}
|
||||
|
||||
public synchronized static void stop()
|
||||
{
|
||||
TrackRecorderWakeService svc = getService();
|
||||
if (svc != null)
|
||||
svc.cancel();
|
||||
}
|
||||
}
|
|
@ -263,7 +263,7 @@ public class SearchFragment extends BaseMwmFragment
|
|||
public void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
LocationHelper.INSTANCE.addLocationListener(this);
|
||||
LocationHelper.INSTANCE.addLocationListener(this, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -95,7 +95,7 @@ public class DirectionFragment extends DialogFragment implements LocationHelper.
|
|||
public void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
LocationHelper.INSTANCE.addLocationListener(this);
|
||||
LocationHelper.INSTANCE.addLocationListener(this, true);
|
||||
refreshViews();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue