Merge pull request #5388 from alexzatsepin/android-my-pos-fix

Android my pos fix
This commit is contained in:
Arsentiy Milchakov 2017-02-13 14:01:23 +03:00 committed by GitHub
commit 5f43e2cd31
26 changed files with 428 additions and 522 deletions

View file

@ -95,14 +95,8 @@ void Framework::OnLocationError(int errorCode)
void Framework::OnLocationUpdated(location::GpsInfo const & info)
{
ASSERT(IsDrapeEngineCreated(), ());
m_work.OnLocationUpdate(info);
if (!IsDrapeEngineCreated())
{
location::EMyPositionMode const mode = GetMyPositionMode();
if (mode == location::PendingPosition)
SetMyPositionMode(location::Follow);
}
}
void Framework::OnCompassUpdated(location::CompassInfo const & info, bool forceRedraw)
@ -135,13 +129,6 @@ void Framework::TrafficStateChanged(TrafficManager::TrafficState state)
m_onTrafficStateChangedFn(state);
}
void Framework::SetMyPositionMode(location::EMyPositionMode mode)
{
OnMyPositionModeChanged(mode);
settings::Set(settings::kLocationStateMode, m_currentMode);
MyPositionModeChanged(m_currentMode, false /* routingActive, does not matter */);
}
bool Framework::CreateDrapeEngine(JNIEnv * env, jobject jSurface, int densityDpi, bool firstLaunch)
{
m_contextFactory = make_unique_dp<dp::ThreadSafeFactory>(new AndroidOGLContextFactory(env, jSurface));
@ -463,15 +450,8 @@ void Framework::OnMyPositionModeChanged(location::EMyPositionMode mode)
void Framework::SwitchMyPositionNextMode()
{
if (IsDrapeEngineCreated())
{
m_work.SwitchMyPositionNextMode();
return;
}
// Engine is not available, but the client requests to change mode.
if (GetMyPositionMode() == location::NotFollowNoPosition)
SetMyPositionMode(location::PendingPosition);
ASSERT(IsDrapeEngineCreated(), ());
m_work.SwitchMyPositionNextMode();
}
void Framework::SetupWidget(gui::EWidget widget, float x, float y, dp::Anchor anchor)

View file

@ -52,7 +52,6 @@ namespace android
void TrafficStateChanged(TrafficManager::TrafficState state);
void MyPositionModeChanged(location::EMyPositionMode mode, bool routingActive);
void SetMyPositionMode(location::EMyPositionMode mode);
location::TMyPositionModeChanged m_myPositionModeSignal;
location::EMyPositionMode m_currentMode;

View file

@ -54,7 +54,6 @@ public class MapFragment extends BaseMwmFragment
private int mWidth;
private boolean mRequireResize;
private boolean mContextCreated;
private boolean mFirstStart;
private static boolean sWasCopyrightDisplayed;
interface MapRenderingListener
@ -167,11 +166,11 @@ public class MapFragment extends BaseMwmFragment
getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
final float exactDensityDpi = metrics.densityDpi;
mFirstStart = ((MwmActivity) getMwmActivity()).isFirstStart();
if (mFirstStart)
boolean firstStart = ((MwmActivity) getMwmActivity()).isFirstStart();
if (firstStart)
PushwooshHelper.nativeProcessFirstLaunch();
if (!nativeCreateEngine(surface, (int) exactDensityDpi, mFirstStart))
if (!nativeCreateEngine(surface, (int) exactDensityDpi, firstStart))
{
reportUnsupported();
return;
@ -286,13 +285,6 @@ public class MapFragment extends BaseMwmFragment
}
}
boolean isFirstStart()
{
boolean res = mFirstStart;
mFirstStart = false;
return res;
}
boolean isContextCreated()
{
return mContextCreated;

View file

@ -1,6 +1,7 @@
package com.mapswithme.maps;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@ -174,6 +175,8 @@ public class MwmActivity extends BaseMwmFragmentActivity
private boolean mPlacePageRestored;
private boolean mLocationErrorDialogAnnoying = false;
@Nullable
private Dialog mLocationErrorDialog;
@NonNull
private final OnClickListener mOnMyPositionClickListener = new OnClickListener()
@ -183,6 +186,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
{
mLocationErrorDialogAnnoying = false;
LocationHelper.INSTANCE.switchToNextMode();
LocationHelper.INSTANCE.restart();
Statistics.INSTANCE.trackEvent(Statistics.EventName.TOOLBAR_MY_POSITION);
AlohaHelper.logClick(AlohaHelper.TOOLBAR_MY_POSITION);
}
@ -1006,20 +1010,9 @@ public class MwmActivity extends BaseMwmFragmentActivity
{
mFirstStart = FirstStartFragment.showOn(this);
if (mFirstStart)
{
if (LocationHelper.INSTANCE.isTurnedOn())
addTask(new MwmActivity.MapTask()
{
@Override
public boolean run(MwmActivity target)
{
if (LocationHelper.INSTANCE.isTurnedOn())
LocationHelper.INSTANCE.switchToNextMode();
return false;
}
});
}
else if (!NewsFragment.showOn(this))
return;
if (!NewsFragment.showOn(this))
{
if (ViralFragment.shouldDisplay())
new ViralFragment().show(getSupportFragmentManager(), "");
@ -1792,7 +1785,10 @@ public class MwmActivity extends BaseMwmFragmentActivity
private void showLocationErrorDialog(@NonNull final Intent intent)
{
new AlertDialog.Builder(this)
if (mLocationErrorDialog != null && mLocationErrorDialog.isShowing())
return;
mLocationErrorDialog = new AlertDialog.Builder(this)
.setTitle(R.string.enable_location_services)
.setMessage(R.string.location_is_disabled_long_text)
.setNegativeButton(R.string.close, new DialogInterface.OnClickListener()
@ -1824,9 +1820,6 @@ public class MwmActivity extends BaseMwmFragmentActivity
@Override
public void onLocationNotFound()
{
if (!shouldNotifyLocationNotFound())
return;
showLocationNotFoundDialog();
}
@ -1836,34 +1829,15 @@ public class MwmActivity extends BaseMwmFragmentActivity
getString(R.string.current_location_unknown_title));
new AlertDialog.Builder(this)
.setMessage(message)
.setNegativeButton(R.string.current_location_unknown_stop_button, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
LocationHelper.INSTANCE.stop();
}
})
.setNegativeButton(R.string.current_location_unknown_stop_button, null)
.setPositiveButton(R.string.current_location_unknown_continue_button, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
LocationHelper.INSTANCE.switchToNextMode();
LocationHelper.INSTANCE.start();
}
}).setOnDismissListener(new DialogInterface.OnDismissListener()
{
@Override
public void onDismiss(DialogInterface dialog)
{
LocationHelper.INSTANCE.stop();
}
}).show();
}
private boolean shouldNotifyLocationNotFound()
{
return mMapFragment != null && !mMapFragment.isFirstStart();
}).show();
}
public static class ShowAuthorizationTask implements MapTask

View file

@ -23,6 +23,7 @@ import com.mapswithme.maps.bookmarks.data.BookmarkManager;
import com.mapswithme.maps.downloader.CountryItem;
import com.mapswithme.maps.downloader.MapManager;
import com.mapswithme.maps.editor.Editor;
import com.mapswithme.maps.location.LocationHelper;
import com.mapswithme.maps.location.TrackRecorder;
import com.mapswithme.maps.routing.RoutingController;
import com.mapswithme.maps.settings.StoragePathManager;
@ -179,6 +180,7 @@ public class MwmApplication extends Application
BookmarkManager.nativeLoadBookmarks();
TtsPlayer.INSTANCE.init(this);
ThemeSwitcher.restart();
LocationHelper.INSTANCE.initialize();
RoutingController.get().initialize();
TrafficManager.INSTANCE.initialize();
mIsFrameworkInitialized = true;

View file

@ -7,6 +7,7 @@ import android.os.Bundle;
import android.support.annotation.NonNull;
import android.view.View;
import com.mapswithme.maps.location.LocationHelper;
import com.mapswithme.maps.location.LocationState;
import com.mapswithme.maps.routing.RoutingController;
import com.mapswithme.util.Animations;
@ -219,7 +220,7 @@ class NavigationButtonsAnimationController
private boolean shouldBeHidden()
{
return LocationState.getMode() == LocationState.FOLLOW_AND_ROTATE
return LocationHelper.INSTANCE.getMyPositionMode() == LocationState.FOLLOW_AND_ROTATE
&& (RoutingController.get().isPlanning() || RoutingController.get().isNavigating());
}

View file

@ -21,7 +21,6 @@ class AndroidNativeProvider extends BaseLocationProvider
LocationManager.GPS_PROVIDER };
@NonNull
private final LocationManager mLocationManager;
private boolean mIsActive;
@NonNull
private final List<LocationListener> mListeners = new ArrayList<>();
@ -32,22 +31,27 @@ class AndroidNativeProvider extends BaseLocationProvider
}
@Override
protected boolean start()
protected void start()
{
sLogger.d(TAG, "Android native provider is started");
if (mIsActive)
return true;
LOGGER.d(TAG, "Android native provider is started");
if (isActive())
return;
List<String> providers = getAvailableProviders(mLocationManager);
if (providers.isEmpty())
return false;
{
setActive(false);
return;
}
mIsActive = true;
setActive(true);
for (String provider : providers)
{
sLogger.d(TAG, "Request location updates from the provider: " + provider);
LocationListener listener = new BaseLocationListener(getLocationFixChecker());
mLocationManager.requestLocationUpdates(provider, LocationHelper.INSTANCE.getInterval(), 0, listener);
long interval = LocationHelper.INSTANCE.getInterval();
LOGGER.d(TAG, "Request Android native provider '" + provider
+ "' to get locations at this interval = " + interval + " ms");
mLocationManager.requestLocationUpdates(provider, interval, 0, listener);
mListeners.add(listener);
}
@ -61,14 +65,12 @@ class AndroidNativeProvider extends BaseLocationProvider
if (location == null || LocationUtils.isExpired(location, LocationHelper.INSTANCE.getSavedLocationTime(),
LocationUtils.LOCATION_EXPIRATION_TIME_MILLIS_SHORT))
{
return true;
return;
}
}
if (location != null)
onLocationChanged(location);
return true;
}
private void onLocationChanged(@NonNull Location location)
@ -85,14 +87,14 @@ class AndroidNativeProvider extends BaseLocationProvider
@Override
protected void stop()
{
sLogger.d(TAG, "Android native provider is stopped");
LOGGER.d(TAG, "Android native provider is stopped");
ListIterator<LocationListener> iterator = mListeners.listIterator();
// noinspection WhileLoopReplaceableByForEach
while (iterator.hasNext())
mLocationManager.removeUpdates(iterator.next());
mListeners.clear();
mIsActive = false;
setActive(false);
}
@Nullable

View file

@ -7,10 +7,11 @@ import com.mapswithme.util.log.LoggerFactory;
abstract class BaseLocationProvider
{
static final Logger sLogger = LoggerFactory.INSTANCE.getLogger(LoggerFactory.Type.LOCATION);
static final Logger LOGGER = LoggerFactory.INSTANCE.getLogger(LoggerFactory.Type.LOCATION);
private static final String TAG = BaseLocationProvider.class.getSimpleName();
@NonNull
private final LocationFixChecker mLocationFixChecker;
private boolean mActive;
@NonNull
LocationFixChecker getLocationFixChecker()
{
@ -22,9 +23,21 @@ abstract class BaseLocationProvider
mLocationFixChecker = locationFixChecker;
}
/**
* @return whether location polling was started successfully.
*/
protected abstract boolean start();
protected abstract void start();
protected abstract void stop();
/**
* Indicates whether this provider is providing location updates or not
* @return true - if locations are actively coming from this provider, false - otherwise
*/
public final boolean isActive()
{
return mActive;
}
final void setActive(boolean active)
{
LOGGER.d(TAG, "setActive active = " + active);
mActive = active;
}
}

View file

@ -11,6 +11,8 @@ public class GPSCheck extends BroadcastReceiver
@Override
public void onReceive(Context context, Intent intent) {
if (MwmApplication.get().isFrameworkInitialized() && MwmApplication.backgroundTracker().isForeground())
LocationHelper.INSTANCE.checkProvidersAndStartIfNeeded();
{
LocationHelper.INSTANCE.restart();
}
}
}

View file

@ -39,33 +39,31 @@ class GoogleFusedLocationProvider extends BaseLocationProvider
}
@Override
protected boolean start()
protected void start()
{
sLogger.d(TAG, "Google fused provider is started");
LOGGER.d(TAG, "Google fused provider is started");
if (mGoogleApiClient.isConnected() || mGoogleApiClient.isConnecting())
return true;
{
setActive(true);
return;
}
mLocationRequest = LocationRequest.create();
// mLocationRequest.setPriority(LocationHelper.INSTANCE.isHighAccuracy() ? LocationRequest.PRIORITY_HIGH_ACCURACY
// : LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
// TODO @yunikkk
// Currently there are some problems concerning location strategies switching.
// With LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY priority GPS is not used and location icon isn't shown in system navbar,
// hence it confuses user.
// We should reconsider if balanced mode is needed at all after results of tests for battery usage will arrive.
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
long interval = LocationHelper.INSTANCE.getInterval();
mLocationRequest.setInterval(interval);
LOGGER.d(TAG, "Request Google fused provider to provide locations at this interval = "
+ interval + " ms");
mLocationRequest.setFastestInterval(interval / 2);
mGoogleApiClient.connect();
return true;
setActive(true);
}
@Override
protected void stop()
{
sLogger.d(TAG, "Google fused provider is stopped");
LOGGER.d(TAG, "Google fused provider is stopped");
if (mGoogleApiClient.isConnected())
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, mListener);
@ -73,18 +71,19 @@ class GoogleFusedLocationProvider extends BaseLocationProvider
mLocationSettingsResult.cancel();
mGoogleApiClient.disconnect();
setActive(false);
}
@Override
public void onConnected(Bundle bundle)
{
sLogger.d(TAG, "Fused onConnected. Bundle " + bundle);
LOGGER.d(TAG, "Fused onConnected. Bundle " + bundle);
checkSettingsAndRequestUpdates();
}
private void checkSettingsAndRequestUpdates()
{
sLogger.d(TAG, "checkSettingsAndRequestUpdates()");
LOGGER.d(TAG, "checkSettingsAndRequestUpdates()");
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(mLocationRequest);
builder.setAlwaysShow(true); // hides 'never' button in resolve dialog afterwards.
mLocationSettingsResult = LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build());
@ -94,19 +93,21 @@ class GoogleFusedLocationProvider extends BaseLocationProvider
public void onResult(@NonNull LocationSettingsResult locationSettingsResult)
{
final Status status = locationSettingsResult.getStatus();
sLogger.d(TAG, "onResult status: " + status);
LOGGER.d(TAG, "onResult status: " + status);
switch (status.getStatusCode())
{
case LocationSettingsStatusCodes.SUCCESS:
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
setActive(false);
// Location settings are not satisfied. AndroidNativeProvider should be used.
resolveError(status);
resolveResolutionRequired();
return;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
// Location settings are not satisfied. However, we have no way to fix the settings so we won't show the dialog.
setActive(false);
break;
}
@ -115,13 +116,11 @@ class GoogleFusedLocationProvider extends BaseLocationProvider
});
}
private static void resolveError(Status status)
private static void resolveResolutionRequired()
{
sLogger.d(TAG, "resolveError()");
if (LocationHelper.INSTANCE.isLocationStopped())
return;
LocationHelper.INSTANCE.initProvider(true /* forceNative */);
LOGGER.d(TAG, "resolveResolutionRequired()");
LocationHelper.INSTANCE.initNativeProvider();
LocationHelper.INSTANCE.start();
}
private void requestLocationUpdates()
@ -139,14 +138,17 @@ class GoogleFusedLocationProvider extends BaseLocationProvider
@Override
public void onConnectionSuspended(int i)
{
sLogger.d(TAG, "Fused onConnectionSuspended. Code " + i);
setActive(false);
LOGGER.d(TAG, "Fused onConnectionSuspended. Code " + i);
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult)
{
sLogger.d(TAG, "Fused onConnectionFailed. Fall back to native provider. ConnResult " + connectionResult);
setActive(false);
LOGGER.d(TAG, "Fused onConnectionFailed. Fall back to native provider. ConnResult " + connectionResult);
// TODO handle error in a smarter way
LocationHelper.INSTANCE.initProvider(true);
LocationHelper.INSTANCE.initNativeProvider();
LocationHelper.INSTANCE.start();
}
}

View file

@ -1,13 +1,10 @@
package com.mapswithme.maps.location;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.Location;
import android.location.LocationManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
@ -20,12 +17,9 @@ import com.mapswithme.util.Config;
import com.mapswithme.util.Listeners;
import com.mapswithme.util.LocationUtils;
import com.mapswithme.util.Utils;
import com.mapswithme.util.concurrency.UiThread;
import com.mapswithme.util.log.Logger;
import com.mapswithme.util.log.LoggerFactory;
import static com.mapswithme.maps.background.AppBackgroundTracker.OnTransitionListener;
public enum LocationHelper
{
INSTANCE;
@ -46,49 +40,11 @@ public enum LocationHelper
private static final long INTERVAL_NAVIGATION_BICYCLE_MS = 1000;
private static final long INTERVAL_NAVIGATION_PEDESTRIAN_MS = 1000;
private static final long STOP_DELAY_MS = 5000;
private boolean mErrorOccurred;
public interface UiCallback
{
Activity getActivity();
void onMyPositionModeChanged(int newMode);
void onLocationUpdated(@NonNull Location location);
void onCompassUpdated(@NonNull CompassData compass);
void onLocationError();
void onLocationNotFound();
}
private final OnTransitionListener mOnTransition = new OnTransitionListener()
{
private final GPSCheck mReceiver = new GPSCheck();
private boolean mReceiverRegistered;
@Override
public void onTransit(boolean foreground)
{
if (foreground && !mReceiverRegistered)
{
final IntentFilter filter = new IntentFilter();
filter.addAction(LocationManager.PROVIDERS_CHANGED_ACTION);
filter.addCategory(Intent.CATEGORY_DEFAULT);
MwmApplication.get().registerReceiver(mReceiver, filter);
mReceiverRegistered = true;
return;
}
if (!foreground && mReceiverRegistered)
{
MwmApplication.get().unregisterReceiver(mReceiver);
mReceiverRegistered = false;
}
}
};
@NonNull
private final TransitionListener mOnTransition = new TransitionListener();
@NonNull
private final LocationListener mLocationListener = new LocationListener()
private final LocationListener mCoreLocationListener = new LocationListener()
{
@Override
public void onLocationUpdated(Location location)
@ -123,13 +79,11 @@ public enum LocationHelper
@Override
public void onLocationError(int errorCode)
{
mErrorOccurred = true;
mLogger.d(TAG, "onLocationError errorCode = " + errorCode);
mLogger.d(TAG, "onLocationError errorCode = " + errorCode, new Throwable());
nativeOnLocationError(errorCode);
mLogger.d(TAG, "nativeOnLocationError errorCode = " + errorCode +
", current state = " + LocationState.nameOf(LocationState.getMode()));
stop();
", current state = " + LocationState.nameOf(getMyPositionMode()));
if (mUiCallback == null)
return;
@ -140,7 +94,7 @@ public enum LocationHelper
@Override
public String toString()
{
return "LocationHelper.mLocationListener";
return "LocationHelper.mCoreLocationListener";
}
};
@ -148,128 +102,91 @@ public enum LocationHelper
private final Logger mLogger = LoggerFactory.INSTANCE.getLogger(LoggerFactory.Type.LOCATION);
@NonNull
private final Listeners<LocationListener> mListeners = new Listeners<>();
private boolean mActive;
private boolean mLocationStopped;
private boolean mColdStart = true;
private Location mSavedLocation;
private MapObject mMyPosition;
private long mSavedLocationTime;
@NonNull
private final SensorHelper mSensorHelper = new SensorHelper();
@Nullable
private BaseLocationProvider mLocationProvider;
@NonNull
private final LocationPredictor mPredictor = new LocationPredictor(mLocationListener);
private final LocationPredictor mPredictor = new LocationPredictor(mCoreLocationListener);
@Nullable
private UiCallback mUiCallback;
private long mInterval;
private boolean mHighAccuracy;
private CompassData mCompassData;
private boolean mInFirstRun;
@SuppressWarnings("FieldCanBeLocal")
private final LocationState.ModeChangeListener mModeChangeListener = new LocationState.ModeChangeListener()
private final LocationState.ModeChangeListener mMyPositionModeListener =
new LocationState.ModeChangeListener()
{
@Override
public void onMyPositionModeChanged(int newMode)
{
notifyMyPositionModeChanged(newMode);
mLogger.d(TAG, "onMyPositionModeChanged mode = " + LocationState.nameOf(newMode) +
" mColdStart = " + mColdStart + " mErrorOccurred = " + mErrorOccurred);
switch (newMode)
mLogger.d(TAG, "onMyPositionModeChanged mode = " + LocationState.nameOf(newMode));
if (mUiCallback == null)
{
case LocationState.PENDING_POSITION:
addListener(mLocationListener, true);
break;
case LocationState.NOT_FOLLOW_NO_POSITION:
if (mColdStart && !mErrorOccurred)
{
LocationState.nativeSwitchToNextMode();
break;
}
removeListener(mLocationListener);
if (mLocationStopped)
break;
if (LocationUtils.areLocationServicesTurnedOn())
{
mLocationStopped = true;
notifyLocationNotFound();
}
break;
default:
mLocationStopped = false;
restart();
break;
mLogger.d(TAG, "UI is not ready to listen my position changes, i.e. it's not attached yet.");
return;
}
mColdStart = false;
mErrorOccurred = false;
switch (newMode)
{
case LocationState.NOT_FOLLOW_NO_POSITION:
// In the first run mode, the NOT_FOLLOW_NO_POSITION state doesn't mean that location
// is actually not found.
if (mInFirstRun)
{
mLogger.i(TAG, "It's the first run, so this state should be skipped");
return;
}
stop();
if (LocationUtils.areLocationServicesTurnedOn())
notifyLocationNotFound();
break;
}
}
};
private final Runnable mStopLocationTask = new Runnable()
{
@Override
public void run()
{
mLogger.d(TAG, "mStopLocationTask.run(). Was active: " + mActive);
if (mActive)
stopInternal();
}
};
LocationHelper()
{
mLogger.d(LocationHelper.class.getSimpleName(), "ctor()");
}
// TODO consider refactoring.
// Actually we shouldn't initialize Framework here,
// to allow app components to retrieve location updates without all heavy framework's stuff initialized.
// For now this is necessary to connect mModeChangeListener below.
MwmApplication.get().initNativeCore();
LocationState.nativeSetListener(mModeChangeListener);
calcParams();
initProvider(false);
@UiThread
public void initialize()
{
initProvider();
LocationState.nativeSetListener(mMyPositionModeListener);
MwmApplication.backgroundTracker().addListener(mOnTransition);
}
public void initProvider(boolean forceNative)
private void initProvider()
{
mLogger.d(TAG, "initProvider forceNative = " + forceNative, new Throwable());
mActive = !mListeners.isEmpty();
if (mActive)
{
mLogger.d(TAG, "Stop the active provider '" + mLocationProvider + "' before starting the new one");
stopInternal();
}
mLogger.d(TAG, "initProvider", new Throwable());
final MwmApplication application = MwmApplication.get();
final boolean containsGoogleServices = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(application) == ConnectionResult.SUCCESS;
final boolean googleServicesTurnedInSettings = Config.useGoogleServices();
if (!forceNative &&
containsGoogleServices &&
googleServicesTurnedInSettings)
if (containsGoogleServices && googleServicesTurnedInSettings)
{
mLogger.d(TAG, "Use fused provider.");
mLocationProvider = new GoogleFusedLocationProvider(new FusedLocationFixChecker());
}
else
{
mLogger.d(TAG, "Use native provider.");
mLocationProvider = new AndroidNativeProvider(new DefaultLocationFixChecker());
initNativeProvider();
}
}
mActive = !mListeners.isEmpty();
if (mActive)
startInternal();
void initNativeProvider()
{
mLogger.d(TAG, "Use native provider");
mLocationProvider = new AndroidNativeProvider(new DefaultLocationFixChecker());
}
public void onLocationUpdated(@NonNull Location location)
@ -313,12 +230,7 @@ public enum LocationHelper
public void switchToNextMode()
{
if (mErrorOccurred)
{
mLogger.d(TAG, "Location services are still not available, no need to switch to the next mode.");
notifyLocationError(ERROR_DENIED);
return;
}
mLogger.d(TAG, "switchToNextMode()");
LocationState.nativeSwitchToNextMode();
}
@ -345,6 +257,15 @@ public enum LocationHelper
return;
}
// If we are still in the first run mode, i.e. user stays on the first run screens,
// not on the map, we mustn't post location update to the core. Only this preserving allows us
// to play nice zoom animation once a user will see map.
if (mInFirstRun)
{
mLogger.d(TAG, "Location update is obtained, but ignore, because it's a first run mode");
return;
}
for (LocationListener listener : mListeners)
listener.onLocationUpdated(mSavedLocation);
mListeners.finishIterate();
@ -385,7 +306,7 @@ public enum LocationHelper
private void notifyMyPositionModeChanged(int newMode)
{
mLogger.d(TAG, "notifyMyPositionModeChanged(): " + LocationState.nameOf(newMode));
mLogger.d(TAG, "notifyMyPositionModeChanged(): " + LocationState.nameOf(newMode) , new Throwable());
if (mUiCallback != null)
mUiCallback.onMyPositionModeChanged(newMode);
@ -400,105 +321,33 @@ public enum LocationHelper
mUiCallback.onLocationNotFound();
}
boolean isLocationStopped()
{
return mLocationStopped;
}
public void stop()
{
mLogger.d(TAG, "stop()");
mLocationStopped = true;
removeListener(mLocationListener, false);
}
void checkProvidersAndStartIfNeeded()
{
Context context = MwmApplication.get();
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
boolean networkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
boolean gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
mLocationStopped = !networkEnabled && !gpsEnabled;
LocationUtils.logAvailableProviders();
if (mLocationStopped)
{
if (LocationState.getMode() == LocationState.PENDING_POSITION)
notifyLocationError(ERROR_DENIED);
return;
}
initProvider(false);
mLogger.i(TAG, "checkProvidersAndStartIfNeeded, current mode '" + LocationState.nameOf(LocationState.getMode()) + "'");
LocationState.nativeSwitchToNextMode();
}
/**
* Registers listener about location changes. Starts polling on the first listener registration.
* Registers listener about location changes.
* @param listener listener to register.
* @param forceUpdate instantly notify given listener about available location, if any.
*/
@android.support.annotation.UiThread
public void addListener(LocationListener listener, boolean forceUpdate)
@UiThread
public void addListener(@NonNull LocationListener listener, boolean forceUpdate)
{
mLogger.d(TAG, "addListener(): " + listener + ", forceUpdate: " + forceUpdate);
mLogger.d(TAG, " - listener count was: " + mListeners.getSize());
UiThread.cancelDelayedTasks(mStopLocationTask);
boolean wasEmpty = mListeners.isEmpty();
mListeners.register(listener);
if (wasEmpty)
{
calcParams();
startInternal();
}
if (mActive && forceUpdate)
if (forceUpdate)
notifyLocationUpdated(listener);
}
@android.support.annotation.UiThread
private void removeListener(LocationListener listener, boolean delayed)
{
mLogger.d(TAG, "removeListener(), delayed: " + delayed + ", listener: " + listener);
mLogger.d(TAG, " - listener count was: " + mListeners.getSize());
boolean wasEmpty = mListeners.isEmpty();
mListeners.unregister(listener);
if (!wasEmpty && mListeners.isEmpty())
{
mLogger.d(TAG, " - was not empty");
if (delayed)
{
mLogger.d(TAG, " - schedule stop");
stopDelayed();
}
else
{
mLogger.d(TAG, " - stop now");
stopInternal();
}
}
}
@UiThread
/**
* Removes given location listener. Stops polling if there are no listeners left.
* Removes given location listener.
* @param listener listener to unregister.
*/
@android.support.annotation.UiThread
public void removeListener(LocationListener listener)
public void removeListener(@NonNull LocationListener listener)
{
removeListener(listener, false);
}
@android.support.annotation.UiThread
public void removeListener()
{
removeListener(mLocationListener);
mLogger.d(TAG, "removeListener(), listener: " + listener);
mLogger.d(TAG, " - listener count was: " + mListeners.getSize());
mListeners.unregister(listener);
}
void startSensors()
@ -511,11 +360,12 @@ public enum LocationHelper
mSensorHelper.resetMagneticField(mSavedLocation, location);
}
private void calcParams()
private void calcLocationUpdatesInterval()
{
mHighAccuracy = true;
mLogger.d(TAG, "calcLocationUpdatesInterval()");
if (RoutingController.get().isNavigating())
{
mLogger.d(TAG, "calcLocationUpdatesInterval(), it's navigation mode");
final @Framework.RouterType int router = Framework.nativeGetRouter();
switch (router)
{
@ -538,22 +388,20 @@ public enum LocationHelper
return;
}
int mode = LocationState.getMode();
int mode = getMyPositionMode();
switch (mode)
{
default:
case LocationState.NOT_FOLLOW:
mHighAccuracy = false;
mInterval = INTERVAL_NOT_FOLLOW_MS;
break;
case LocationState.FOLLOW:
mInterval = INTERVAL_FOLLOW_MS;
break;
case LocationState.FOLLOW:
mInterval = INTERVAL_FOLLOW_MS;
break;
case LocationState.FOLLOW_AND_ROTATE:
mInterval = INTERVAL_FOLLOW_AND_ROTATE_MS;
break;
case LocationState.FOLLOW_AND_ROTATE:
mInterval = INTERVAL_FOLLOW_AND_ROTATE_MS;
break;
default:
mInterval = INTERVAL_NOT_FOLLOW_MS;
break;
}
}
@ -562,41 +410,71 @@ public enum LocationHelper
return mInterval;
}
// TODO (trashkalmar): Usage of this method was temporarily commented out from GoogleFusedLocationProvider.start(). See comments there.
boolean isHighAccuracy()
{
return mHighAccuracy;
}
/**
* Recalculates location parameters and restarts locator if it was in a progress before.
* <p>Does nothing if there were no subscribers.
* Stops the current provider. Then initialize the location provider again,
* because location settings could be changed and a new location provider can be used,
* such as Google fused provider. And we think that Google fused provider is preferable
* for the most cases. And starts the initialized location provider.
*
* @see #start()
*
*/
public void restart()
{
mLogger.d(TAG, "restart()");
mActive &= !mListeners.isEmpty();
if (!mActive)
checkProviderInitialization();
stopInternal();
initProvider();
start();
}
/**
* Adds the {@link #mCoreLocationListener} to listen location updates and notify UI.
* Notifies about {@link #ERROR_DENIED} if there are no enabled location providers.
* Calculates minimum time interval for location updates.
* Starts polling location updates.
*/
public void start()
{
checkProviderInitialization();
//noinspection ConstantConditions
if (mLocationProvider.isActive())
throw new AssertionError("Location provider '" + mLocationProvider + "' must be stopped first");
addListener(mCoreLocationListener, true);
if (!LocationUtils.checkProvidersAvailability())
{
stopInternal();
// No need to notify about an error in first run mode
if (!mInFirstRun)
notifyLocationError(ERROR_DENIED);
return;
}
boolean oldHighAccuracy = mHighAccuracy;
long oldInterval = mInterval;
mLogger.d(TAG, "restart. Old params: " + oldInterval + " / " + (oldHighAccuracy ? "high" : "normal"));
mLogger.d(TAG, "Old time interval (ms): " + oldInterval);
calcLocationUpdatesInterval();
mLogger.d(TAG, "start(), params: " + mInterval);
startInternal();
}
calcParams();
mLogger.d(TAG, "New params: " + mInterval + " / " + (mHighAccuracy ? "high" : "normal"));
if (mHighAccuracy != oldHighAccuracy || mInterval != oldInterval)
/**
* Stops the polling location updates, i.e. removes the {@link #mCoreLocationListener} and stops
* the current active provider.
*/
private void stop()
{
mLogger.d(TAG, "stop()");
checkProviderInitialization();
//noinspection ConstantConditions
if (!mLocationProvider.isActive())
{
boolean active = mActive;
stopInternal();
if (active)
startInternal();
mLogger.i(TAG, "Provider '" + mLocationProvider + "' is already stopped");
return;
}
removeListener(mCoreLocationListener);
stopInternal();
}
/**
@ -604,18 +482,30 @@ public enum LocationHelper
*/
private void startInternal()
{
mLogger.d(TAG, "startInternal(), current provider is '" + mLocationProvider + "'");
mLogger.d(TAG, "startInternal(), current provider is '" + mLocationProvider
+ "' , my position mode = " + LocationState.nameOf(getMyPositionMode())
+ ", mInFirstRun = " + mInFirstRun);
checkProviderInitialization();
//noinspection ConstantConditions
mLocationProvider.start();
mLogger.d(TAG, mLocationProvider.isActive() ? "SUCCESS" : "FAILURE");
mActive = mLocationProvider.start();
mLogger.d(TAG, mActive ? "SUCCESS" : "FAILURE");
if (mActive)
if (mLocationProvider.isActive())
{
mErrorOccurred = false;
if (!mInFirstRun && getMyPositionMode() == LocationState.NOT_FOLLOW_NO_POSITION)
switchToNextMode();
mPredictor.resume();
}
else
notifyLocationError(LocationHelper.ERROR_DENIED);
}
private void checkProviderInitialization()
{
if (mLocationProvider == null)
{
String error = "A location provider must be initialized!";
mLogger.e(TAG, error, new Throwable());
throw new AssertionError(error);
}
}
/**
@ -624,29 +514,20 @@ public enum LocationHelper
private void stopInternal()
{
mLogger.d(TAG, "stopInternal()");
mActive = false;
checkProviderInitialization();
//noinspection ConstantConditions
mLocationProvider.stop();
mSensorHelper.stop();
mPredictor.pause();
notifyMyPositionModeChanged(LocationState.getMode());
}
/**
* Schedules poll termination after {@link #STOP_DELAY_MS}.
*/
private void stopDelayed()
{
mLogger.d(TAG, "stopDelayed()");
UiThread.runLater(mStopLocationTask, STOP_DELAY_MS);
}
/**
* Attach UI to helper.
*/
public void attach(UiCallback callback)
@UiThread
public void attach(@NonNull UiCallback callback)
{
mLogger.d(TAG, "attach() callback = " + callback + " mColdStart = " + mColdStart);
mLogger.d(TAG, "attach() callback = " + callback);
if (mUiCallback != null)
{
@ -658,20 +539,27 @@ public enum LocationHelper
Utils.keepScreenOn(true, mUiCallback.getActivity().getWindow());
mUiCallback.onMyPositionModeChanged(LocationState.getMode());
mUiCallback.onMyPositionModeChanged(getMyPositionMode());
if (mCompassData != null)
mUiCallback.onCompassUpdated(mCompassData);
if (!mLocationStopped)
addListener(mLocationListener, true);
checkProviderInitialization();
//noinspection ConstantConditions
if (mLocationProvider.isActive())
{
mLogger.d(TAG, "attach() provider '" + mLocationProvider + "' is active, just add the listener");
addListener(mCoreLocationListener, true);
}
else
checkProvidersAndStartIfNeeded();
{
restart();
}
}
/**
* Detach UI from helper.
*/
@UiThread
public void detach(boolean delayed)
{
mLogger.d(TAG, "detach(), delayed: " + delayed);
@ -684,7 +572,47 @@ public enum LocationHelper
Utils.keepScreenOn(false, mUiCallback.getActivity().getWindow());
mUiCallback = null;
removeListener(mLocationListener, delayed);
stop();
}
@UiThread
public void onEnteredIntoFirstRun()
{
mLogger.i(TAG, "onEnteredIntoFirstRun");
mInFirstRun = true;
}
@UiThread
public void onExitFromFirstRun()
{
mLogger.i(TAG, "onExitFromFirstRun");
if (!mInFirstRun)
throw new AssertionError("Must be called only after 'onEnteredIntoFirstRun' method!");
mInFirstRun = false;
if (getMyPositionMode() != LocationState.NOT_FOLLOW_NO_POSITION)
throw new AssertionError("My position mode must be equal NOT_FOLLOW_NO_POSITION");
// If there is a location we need just to pass it to the listeners, so that
// my position state machine will be switched to the FOLLOW state.
Location location = getSavedLocation();
if (location != null)
{
notifyLocationUpdated();
mLogger.d(TAG, "Current location is available, so play the nice zoom animation");
Framework.nativeZoomToPoint(location.getLatitude(), location.getLongitude(), 14, true);
return;
}
checkProviderInitialization();
// If the location hasn't been obtained yet we need to switch to the next mode and wait for locations.
// Otherwise, try to restart location updates polling.
// noinspection ConstantConditions
if (mLocationProvider.isActive())
switchToNextMode();
else
restart();
}
/**
@ -712,8 +640,24 @@ public enum LocationHelper
return mCompassData;
}
@LocationState.Value
public int getMyPositionMode()
{
return LocationState.nativeGetMode();
}
private 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);
static native float[] nativeUpdateCompassSensor(int ind, float[] arr);
public interface UiCallback
{
Activity getActivity();
void onMyPositionModeChanged(int newMode);
void onLocationUpdated(@NonNull Location location);
void onCompassUpdated(@NonNull CompassData compass);
void onLocationError();
void onLocationNotFound();
}
}

View file

@ -38,7 +38,7 @@ class LocationPredictor
void resume()
{
onMyPositionModeChanged(LocationState.getMode());
onMyPositionModeChanged(LocationHelper.INSTANCE.getMyPositionMode());
}
void pause()

View file

@ -1,6 +1,9 @@
package com.mapswithme.maps.location;
import com.mapswithme.maps.MwmApplication;
import android.support.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public final class LocationState
{
@ -10,6 +13,10 @@ public final class LocationState
void onMyPositionModeChanged(int newMode);
}
@Retention(RetentionPolicy.SOURCE)
@IntDef({ PENDING_POSITION, NOT_FOLLOW_NO_POSITION, NOT_FOLLOW, FOLLOW, FOLLOW_AND_ROTATE})
@interface Value {}
// These values should correspond to location::EMyPositionMode enum (from platform/location.hpp)
public static final int PENDING_POSITION = 0;
public static final int NOT_FOLLOW_NO_POSITION = 1;
@ -18,7 +25,8 @@ public final class LocationState
public static final int FOLLOW_AND_ROTATE = 4;
static native void nativeSwitchToNextMode();
private static native int nativeGetMode();
@Value
static native int nativeGetMode();
static native void nativeSetListener(ModeChangeListener listener);
static native void nativeRemoveListener();
@ -30,7 +38,7 @@ public final class LocationState
*/
static boolean isTurnedOn()
{
return hasLocation(getMode());
return hasLocation(nativeGetMode());
}
static boolean hasLocation(int mode)
@ -38,13 +46,7 @@ public final class LocationState
return (mode > NOT_FOLLOW_NO_POSITION);
}
public static int getMode()
{
MwmApplication.get().initNativeCore();
return nativeGetMode();
}
static String nameOf(int mode)
static String nameOf(@Value int mode)
{
switch (mode)
{

View file

@ -0,0 +1,37 @@
package com.mapswithme.maps.location;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.LocationManager;
import android.support.annotation.NonNull;
import com.mapswithme.maps.MwmApplication;
import com.mapswithme.maps.background.AppBackgroundTracker;
class TransitionListener implements AppBackgroundTracker.OnTransitionListener
{
@NonNull
private final GPSCheck mReceiver = new GPSCheck();
private boolean mReceiverRegistered;
@Override
public void onTransit(boolean foreground)
{
if (foreground && !mReceiverRegistered)
{
final IntentFilter filter = new IntentFilter();
filter.addAction(LocationManager.PROVIDERS_CHANGED_ACTION);
filter.addCategory(Intent.CATEGORY_DEFAULT);
MwmApplication.get().registerReceiver(mReceiver, filter);
mReceiverRegistered = true;
return;
}
if (!foreground && mReceiverRegistered)
{
MwmApplication.get().unregisterReceiver(mReceiver);
mReceiverRegistered = false;
}
}
}

View file

@ -277,7 +277,7 @@ abstract class BaseNewsFragment extends BaseMwmDialogFragment
@Override
public void onClick(View v)
{
dismissAllowingStateLoss();
onDoneClick();
}
});
@ -285,6 +285,11 @@ abstract class BaseNewsFragment extends BaseMwmDialogFragment
return res;
}
protected void onDoneClick()
{
dismissAllowingStateLoss();
}
@SuppressWarnings("TryWithIdenticalCatches")
static void create(FragmentActivity activity, Class<? extends BaseNewsFragment> clazz)
{

View file

@ -1,43 +1,18 @@
package com.mapswithme.maps.news;
import android.app.Dialog;
import android.content.DialogInterface;
import android.location.Location;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import com.mapswithme.maps.BuildConfig;
import com.mapswithme.maps.Framework;
import com.mapswithme.maps.R;
import com.mapswithme.maps.location.LocationHelper;
import com.mapswithme.maps.location.LocationListener;
import com.mapswithme.util.Config;
import com.mapswithme.util.statistics.Statistics;
public class FirstStartFragment extends BaseNewsFragment
{
private static Location sLocation;
private static int sError = LocationHelper.ERROR_UNKNOWN;
private final LocationListener mLocationListener = new LocationListener.Simple()
{
@Override
public void onLocationUpdated(Location location)
{
sLocation = location;
sError = LocationHelper.ERROR_UNKNOWN;
}
@Override
public void onLocationError(int errorCode)
{
sLocation = null;
sError = errorCode;
}
};
private class Adapter extends BaseNewsFragment.Adapter
{
@Override
@ -87,37 +62,15 @@ public class FirstStartFragment extends BaseNewsFragment
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
LocationHelper.INSTANCE.addListener(mLocationListener, true);
LocationHelper.INSTANCE.onEnteredIntoFirstRun();
return super.onCreateDialog(savedInstanceState);
}
@Override
public void onDismiss(DialogInterface dialog)
protected void onDoneClick()
{
super.onDismiss(dialog);
if (sLocation == null)
{
String reason;
switch (sError)
{
case LocationHelper.ERROR_DENIED:
reason = "unavailable";
break;
default:
Statistics.INSTANCE.trackEvent(Statistics.EventName.FIRST_START_DONT_ZOOM);
return;
}
Statistics.INSTANCE.trackEvent(Statistics.EventName.FIRST_START_NO_LOCATION, Statistics.params().add("reason", reason));
return;
}
Framework.nativeZoomToPoint(sLocation.getLatitude(), sLocation.getLongitude(), 14, true);
sLocation = null;
LocationHelper.INSTANCE.removeListener(mLocationListener);
super.onDoneClick();
LocationHelper.INSTANCE.onExitFromFirstRun();
}
public static boolean showOn(FragmentActivity activity)
@ -136,8 +89,6 @@ public class FirstStartFragment extends BaseNewsFragment
create(activity, FirstStartFragment.class);
Config.setFirstStartDialogSeen();
Statistics.INSTANCE.trackEvent(Statistics.EventName.FIRST_START_SHOWN);
return true;
}
}

View file

@ -6,6 +6,7 @@ import android.util.Pair;
import java.util.ArrayList;
import java.util.List;
import com.mapswithme.maps.location.LocationHelper;
import com.mapswithme.maps.location.LocationState;
import com.mapswithme.maps.MwmApplication;
import com.mapswithme.maps.R;
@ -34,7 +35,7 @@ class ResultCodesHelper
switch (errorCode)
{
case NO_POSITION:
if (LocationState.getMode() == LocationState.NOT_FOLLOW_NO_POSITION)
if (LocationHelper.INSTANCE.getMyPositionMode() == LocationState.NOT_FOLLOW_NO_POSITION)
{
titleRes = R.string.dialog_routing_location_turn_on;
messages.add(resources.getString(R.string.dialog_routing_location_unknown_turn_on));

View file

@ -61,7 +61,7 @@ public class MiscPrefsFragment extends BaseXmlSettingsFragment
if (oldVal != newVal)
{
Config.setUseGoogleService(newVal);
LocationHelper.INSTANCE.initProvider(false /* forceNative */);
LocationHelper.INSTANCE.restart();
}
return true;
}

View file

@ -119,7 +119,7 @@ public class LocationUtils
}
}
public static void logAvailableProviders()
private static void logAvailableProviders()
{
LocationManager locMngr = (LocationManager) MwmApplication.get().getSystemService(Context.LOCATION_SERVICE);
List<String> providers = locMngr.getProviders(true);
@ -134,6 +134,22 @@ public class LocationUtils
{
sb = new StringBuilder("There are no enabled location providers!");
}
LOGGER.i(TAG, sb.toString(), new Throwable());
LOGGER.i(TAG, sb.toString());
}
public static boolean checkProvidersAvailability()
{
Context context = MwmApplication.get();
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
if (locationManager == null)
{
LOGGER.e(TAG, "This device doesn't support the location service.");
return false;
}
boolean networkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
boolean gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
LocationUtils.logAvailableProviders();
return networkEnabled || gpsEnabled;
}
}

View file

@ -47,11 +47,6 @@ public enum Statistics
public static final String DOWNLOADER_ACTION = "Downloader_Map_action";
public static final String DOWNLOADER_CANCEL = "Downloader_Cancel_downloading";
// First start
public static final String FIRST_START_SHOWN = "FirstStart_Dialog_show";
public static final String FIRST_START_NO_LOCATION = "FirstStart_Location_disable";
public static final String FIRST_START_DONT_ZOOM = "FirstStart_ZAnimation_disable";
// bookmarks
public static final String BMK_DESCRIPTION_CHANGED = "Bookmark. Description changed";
public static final String BMK_GROUP_CREATED = "Bookmark. Group created";

View file

@ -16,7 +16,8 @@
namespace df
{
DrapeEngine::DrapeEngine(Params && params)
: m_viewport(params.m_viewport)
: m_myPositionModeChanged(move(params.m_myPositionModeChanged))
, m_viewport(move(params.m_viewport))
{
VisualParams::Init(params.m_vs, df::CalculateTileSize(m_viewport.GetWidth(), m_viewport.GetHeight()));
@ -321,11 +322,6 @@ void DrapeEngine::SetModelViewListener(TModelViewListenerFn && fn)
m_modelViewChanged = move(fn);
}
void DrapeEngine::SetMyPositionModeListener(location::TMyPositionModeChanged && fn)
{
m_myPositionModeChanged = move(fn);
}
void DrapeEngine::SetTapEventInfoListener(TTapEventInfoFn && fn)
{
m_tapListener = move(fn);

View file

@ -46,6 +46,7 @@ public:
double fontsScaleFactor,
gui::TWidgetsInitInfo && info,
pair<location::EMyPositionMode, bool> const & initialMyPositionMode,
location::TMyPositionModeChanged && myPositionModeChanged,
bool allow3dBuildings,
bool trafficEnabled,
bool blockTapEvents,
@ -62,6 +63,7 @@ public:
, m_fontsScaleFactor(fontsScaleFactor)
, m_info(move(info))
, m_initialMyPositionMode(initialMyPositionMode)
, m_myPositionModeChanged(move(myPositionModeChanged))
, m_allow3dBuildings(allow3dBuildings)
, m_trafficEnabled(trafficEnabled)
, m_blockTapEvents(blockTapEvents)
@ -80,6 +82,7 @@ public:
double m_fontsScaleFactor;
gui::TWidgetsInitInfo m_info;
pair<location::EMyPositionMode, bool> m_initialMyPositionMode;
location::TMyPositionModeChanged m_myPositionModeChanged;
bool m_allow3dBuildings;
bool m_trafficEnabled;
bool m_blockTapEvents;
@ -125,7 +128,6 @@ public:
void SwitchMyPositionNextMode();
void LoseLocation();
void StopLocationFollow();
void SetMyPositionModeListener(location::TMyPositionModeChanged && fn);
using TTapEventInfoFn = FrontendRenderer::TTapEventInfoFn;
void SetTapEventInfoListener(TTapEventInfoFn && fn);
@ -198,11 +200,11 @@ private:
drape_ptr<ThreadsCommutator> m_threadCommutator;
drape_ptr<dp::TextureManager> m_textureManager;
drape_ptr<RequestedTiles> m_requestedTiles;
location::TMyPositionModeChanged m_myPositionModeChanged;
Viewport m_viewport;
TModelViewListenerFn m_modelViewChanged;
location::TMyPositionModeChanged m_myPositionModeChanged;
TUserPositionChangedFn m_userPositionChanged;
TTapEventInfoFn m_tapListener;

View file

@ -151,9 +151,7 @@ FrontendRenderer::FrontendRenderer(Params const & params)
m_myPositionController.reset(new MyPositionController(params.m_initMyPositionMode, params.m_timeInBackground,
params.m_firstLaunch, params.m_isRoutingActive,
params.m_isAutozoomEnabled));
m_myPositionController->SetModeListener(params.m_myPositionModeCallback);
params.m_isAutozoomEnabled, params.m_myPositionModeCallback));
StartThread();
}

View file

@ -124,9 +124,11 @@ double CalculateZoomBySpeed(double speed, bool isPerspectiveAllowed)
} // namespace
MyPositionController::MyPositionController(location::EMyPositionMode initMode, double timeInBackground,
bool isFirstLaunch, bool isRoutingActive, bool isAutozoomEnabled)
bool isFirstLaunch, bool isRoutingActive, bool isAutozoomEnabled,
location::TMyPositionModeChanged const & fn)
: m_mode(location::PendingPosition)
, m_desiredInitMode(initMode)
, m_modeChangeCallback(fn)
, m_isFirstLaunch(isFirstLaunch)
, m_isInRouting(isRoutingActive)
, m_needBlockAnimation(false)
@ -163,6 +165,9 @@ MyPositionController::MyPositionController(location::EMyPositionMode initMode, d
{
m_desiredInitMode = location::Follow;
}
if (m_modeChangeCallback != nullptr)
m_modeChangeCallback(m_mode, m_isInRouting);
}
MyPositionController::~MyPositionController()
@ -486,18 +491,6 @@ void MyPositionController::OnCompassUpdate(location::CompassInfo const & info, S
}
}
void MyPositionController::SetModeListener(location::TMyPositionModeChanged const & fn)
{
m_modeChangeCallback = fn;
location::EMyPositionMode mode = m_mode;
if (m_isFirstLaunch)
mode = location::NotFollowNoPosition;
if (m_modeChangeCallback != nullptr)
m_modeChangeCallback(mode, m_isInRouting);
}
bool MyPositionController::IsInStateWithPosition() const
{
return m_mode == location::NotFollow || m_mode == location::Follow ||

View file

@ -41,7 +41,8 @@ public:
};
MyPositionController(location::EMyPositionMode initMode, double timeInBackground,
bool isFirstLaunch, bool isRoutingActive, bool isAutozoomEnabled);
bool isFirstLaunch, bool isRoutingActive, bool isAutozoomEnabled,
location::TMyPositionModeChanged const & fn);
~MyPositionController();
void UpdatePosition();
@ -90,8 +91,6 @@ public:
void OnLocationUpdate(location::GpsInfo const & info, bool isNavigable, ScreenBase const & screen);
void OnCompassUpdate(location::CompassInfo const & info, ScreenBase const & screen);
void SetModeListener(location::TMyPositionModeChanged const & fn);
void Render(ScreenBase const & screen, int zoomLevel, ref_ptr<dp::GpuProgramManager> mng,
dp::UniformValuesStorage const & commonUniforms);
@ -133,6 +132,7 @@ private:
private:
location::EMyPositionMode m_mode;
location::EMyPositionMode m_desiredInitMode;
location::TMyPositionModeChanged m_modeChangeCallback;
bool m_isFirstLaunch;
bool m_isInRouting;
@ -140,7 +140,6 @@ private:
bool m_needBlockAnimation;
bool m_wasRotationInScaling;
location::TMyPositionModeChanged m_modeChangeCallback;
drape_ptr<MyPosition> m_shape;
ref_ptr<Listener> m_listener;

View file

@ -1654,6 +1654,19 @@ void Framework::CreateDrapeEngine(ref_ptr<dp::OGLContextFactory> contextFactory,
m_model.ReadFeatures(fn, ids);
};
auto myPositionModeChangedFn = [this](location::EMyPositionMode mode, bool routingActive)
{
GetPlatform().RunOnGuiThread([this, mode, routingActive]()
{
// Deactivate selection (and hide place page) if we return to routing in F&R mode.
if (routingActive && mode == location::FollowAndRotate)
DeactivateMapSelection(true /* notifyUI */);
if (m_myPositionListener != nullptr)
m_myPositionListener(mode, routingActive);
});
};
auto isCountryLoadedByNameFn = bind(&Framework::IsCountryLoadedByName, this, _1);
auto updateCurrentCountryFn = bind(&Framework::OnUpdateCurrentCountry, this, _1, _2);
@ -1673,7 +1686,7 @@ void Framework::CreateDrapeEngine(ref_ptr<dp::OGLContextFactory> contextFactory,
df::MapDataProvider(idReadFn, featureReadFn, isCountryLoadedByNameFn, updateCurrentCountryFn),
params.m_visualScale, fontsScaleFactor, move(params.m_widgetsInitInfo),
make_pair(params.m_initialMyPositionState, params.m_hasMyPositionState),
allow3dBuildings, trafficEnabled, params.m_isChoosePositionMode,
move(myPositionModeChangedFn), allow3dBuildings, trafficEnabled, params.m_isChoosePositionMode,
params.m_isChoosePositionMode, GetSelectedFeatureTriangles(), params.m_isFirstLaunch,
m_routingSession.IsActive() && m_routingSession.IsFollowing(), isAutozoomEnabled);
@ -1694,19 +1707,6 @@ void Framework::CreateDrapeEngine(ref_ptr<dp::OGLContextFactory> contextFactory,
OnSize(params.m_surfaceWidth, params.m_surfaceHeight);
m_drapeEngine->SetMyPositionModeListener([this](location::EMyPositionMode mode, bool routingActive)
{
GetPlatform().RunOnGuiThread([this, mode, routingActive]()
{
// Deactivate selection (and hide place page) if we return to routing in F&R mode.
if (routingActive && mode == location::FollowAndRotate)
DeactivateMapSelection(true /* notifyUI */);
if (m_myPositionListener != nullptr)
m_myPositionListener(mode, routingActive);
});
});
InvalidateUserMarks();
Allow3dMode(allow3d, allow3dBuildings);