forked from organicmaps/organicmaps
Compare commits
6 commits
Author | SHA1 | Date | |
---|---|---|---|
|
30134ff26f | ||
|
aad60785ba | ||
|
2586bdcc8c | ||
d727feb891 | |||
67a8e3f7a2 | |||
f1510351ef |
21 changed files with 615 additions and 45 deletions
|
@ -22,7 +22,7 @@ buildscript {
|
|||
googleFirebaseServicesDefault
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.3.2'
|
||||
classpath 'com.android.tools.build:gradle:8.4.0'
|
||||
|
||||
if (googleFirebaseServicesEnabled) {
|
||||
println('Building with Google Firebase Services')
|
||||
|
@ -376,18 +376,19 @@ dependencies {
|
|||
// > A failure occurred while executing com.android.build.gradle.internal.tasks.CheckDuplicatesRunnable
|
||||
// We don't use Kotlin, but some dependencies are actively using it.
|
||||
// See https://stackoverflow.com/a/75719642
|
||||
implementation 'androidx.core:core:1.12.0'
|
||||
implementation 'androidx.core:core:1.13.1'
|
||||
implementation(platform('org.jetbrains.kotlin:kotlin-bom:1.9.23'))
|
||||
implementation 'androidx.annotation:annotation:1.7.1'
|
||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||
implementation 'androidx.car.app:app:1.7.0-alpha02'
|
||||
implementation 'androidx.car.app:app-projected:1.7.0-alpha02'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
implementation 'androidx.fragment:fragment:1.6.2'
|
||||
implementation 'androidx.fragment:fragment:1.7.0'
|
||||
implementation 'androidx.preference:preference:1.2.1'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.3.2'
|
||||
implementation 'androidx.work:work-runtime:2.9.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-process:2.7.0'
|
||||
implementation 'com.google.android.material:material:1.11.0'
|
||||
implementation 'com.google.android.material:material:1.12.0'
|
||||
// Fix for app/organicmaps/util/FileUploadWorker.java:14: error: cannot access ListenableFuture
|
||||
// https://github.com/organicmaps/organicmaps/issues/6106
|
||||
implementation 'com.google.guava:guava:33.1.0-android'
|
||||
|
|
|
@ -451,6 +451,13 @@
|
|||
android:enabled="true"
|
||||
android:stopWithTask="false"/>
|
||||
|
||||
<service android:name=".location.TrackRecordingService"
|
||||
android:foregroundServiceType="location"
|
||||
android:exported="false"
|
||||
android:enabled="true"
|
||||
android:stopWithTask="false"
|
||||
/>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${FILE_PROVIDER_PLACEHOLDER}"
|
||||
|
|
|
@ -334,7 +334,7 @@ public final class Map
|
|||
}
|
||||
else
|
||||
{
|
||||
nativeSetupWidget(WIDGET_SCALE_FPS_LABEL, UiUtils.dimen(context, R.dimen.margin_base), mHeight - UiUtils.dimen(context, R.dimen.margin_base) * 5, ANCHOR_LEFT_TOP);
|
||||
nativeSetupWidget(WIDGET_SCALE_FPS_LABEL, (float) mWidth / 2 + UiUtils.dimen(context, R.dimen.margin_base) * 2, UiUtils.dimen(context, R.dimen.margin_base), ANCHOR_LEFT_TOP);
|
||||
updateCompassOffset(context, mWidth, mCurrentCompassOffsetY, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,7 @@ import app.organicmaps.location.LocationListener;
|
|||
import app.organicmaps.location.LocationState;
|
||||
import app.organicmaps.location.SensorHelper;
|
||||
import app.organicmaps.location.SensorListener;
|
||||
import app.organicmaps.location.TrackRecordingService;
|
||||
import app.organicmaps.maplayer.MapButtonsController;
|
||||
import app.organicmaps.maplayer.MapButtonsViewModel;
|
||||
import app.organicmaps.maplayer.ToggleMapLayerFragment;
|
||||
|
|
|
@ -26,8 +26,11 @@ import app.organicmaps.display.DisplayManager;
|
|||
import app.organicmaps.downloader.CountryItem;
|
||||
import app.organicmaps.downloader.MapManager;
|
||||
import app.organicmaps.location.LocationHelper;
|
||||
import app.organicmaps.location.LocationListener;
|
||||
import app.organicmaps.location.LocationState;
|
||||
import app.organicmaps.location.SensorHelper;
|
||||
import app.organicmaps.location.TrackRecorder;
|
||||
import app.organicmaps.location.TrackRecordingService;
|
||||
import app.organicmaps.maplayer.isolines.IsolinesManager;
|
||||
import app.organicmaps.maplayer.subway.SubwayManager;
|
||||
import app.organicmaps.maplayer.traffic.TrafficManager;
|
||||
|
@ -36,8 +39,10 @@ import app.organicmaps.routing.RoutingController;
|
|||
import app.organicmaps.search.SearchEngine;
|
||||
import app.organicmaps.settings.StoragePathManager;
|
||||
import app.organicmaps.sound.TtsPlayer;
|
||||
import app.organicmaps.util.AppStateListener;
|
||||
import app.organicmaps.util.Config;
|
||||
import app.organicmaps.util.ConnectionState;
|
||||
import app.organicmaps.util.Listeners;
|
||||
import app.organicmaps.util.SharedPropertiesUtils;
|
||||
import app.organicmaps.util.StorageUtils;
|
||||
import app.organicmaps.util.ThemeSwitcher;
|
||||
|
@ -48,6 +53,8 @@ import app.organicmaps.util.log.LogsManager;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class MwmApplication extends Application implements Application.ActivityLifecycleCallbacks
|
||||
|
@ -77,6 +84,7 @@ public class MwmApplication extends Application implements Application.ActivityL
|
|||
|
||||
private volatile boolean mFrameworkInitialized;
|
||||
private volatile boolean mPlatformInitialized;
|
||||
private final Listeners<AppStateListener> mAppStateListeners = new Listeners<>();
|
||||
|
||||
private Handler mMainLoopHandler;
|
||||
private final Object mMainQueueToken = new Object();
|
||||
|
@ -157,6 +165,7 @@ public class MwmApplication extends Application implements Application.ActivityL
|
|||
|
||||
DownloaderNotifier.createNotificationChannel(this);
|
||||
NavigationService.createNotificationChannel(this);
|
||||
TrackRecordingService.createNotificationChannel(this);
|
||||
|
||||
registerActivityLifecycleCallbacks(this);
|
||||
mSubwayManager = new SubwayManager(this);
|
||||
|
@ -348,11 +357,25 @@ public class MwmApplication extends Application implements Application.ActivityL
|
|||
|
||||
nativeOnTransit(true);
|
||||
|
||||
mLocationHelper.resumeLocationInForeground();
|
||||
Iterator<AppStateListener> listenerIterator = mAppStateListeners.iterator();
|
||||
while(listenerIterator.hasNext())
|
||||
{
|
||||
AppStateListener listener = listenerIterator.next();
|
||||
listener.onAppForeground();
|
||||
}
|
||||
mAppStateListeners.finishIterate();
|
||||
}
|
||||
|
||||
private void onBackground()
|
||||
{
|
||||
Iterator<AppStateListener> listenerIterator = mAppStateListeners.iterator();
|
||||
while(listenerIterator.hasNext())
|
||||
{
|
||||
AppStateListener listener = listenerIterator.next();
|
||||
listener.onAppBackround();
|
||||
}
|
||||
mAppStateListeners.finishIterate();
|
||||
|
||||
Logger.d(TAG);
|
||||
|
||||
nativeOnTransit(false);
|
||||
|
@ -365,6 +388,9 @@ public class MwmApplication extends Application implements Application.ActivityL
|
|||
Logger.i(LOCATION_TAG, "Navigation is in progress, keeping location in the background");
|
||||
else if (!Map.isEngineCreated() || LocationState.getMode() == LocationState.PENDING_POSITION)
|
||||
Logger.i(LOCATION_TAG, "PENDING_POSITION mode, keeping location in the background");
|
||||
else if(TrackRecorder.nativeIsEnabled()){
|
||||
Logger.i(LOCATION_TAG,"Recent Track Recorder is running in background");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.i(LOCATION_TAG, "Stopping location in the background");
|
||||
|
@ -392,4 +418,14 @@ public class MwmApplication extends Application implements Application.ActivityL
|
|||
@Override
|
||||
public void onProgress(String countryId, long localSize, long remoteSize) {}
|
||||
}
|
||||
|
||||
public void addListener(AppStateListener listener)
|
||||
{
|
||||
mAppStateListeners.register(listener);
|
||||
}
|
||||
|
||||
public void removeListener(AppStateListener listener)
|
||||
{
|
||||
mAppStateListeners.unregister(listener);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ import androidx.lifecycle.DefaultLifecycleObserver;
|
|||
import androidx.lifecycle.LifecycleOwner;
|
||||
|
||||
import app.organicmaps.Framework;
|
||||
import app.organicmaps.Map;
|
||||
import app.organicmaps.MwmApplication;
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.bookmarks.data.MapObject;
|
||||
|
@ -25,16 +24,14 @@ import app.organicmaps.car.screens.RequestPermissionsScreen;
|
|||
import app.organicmaps.car.screens.base.BaseMapScreen;
|
||||
import app.organicmaps.car.screens.download.DownloadMapsScreenBuilder;
|
||||
import app.organicmaps.car.screens.download.DownloaderHelpers;
|
||||
import app.organicmaps.car.util.CarSensorsManager;
|
||||
import app.organicmaps.car.util.CurrentCountryChangedListener;
|
||||
import app.organicmaps.car.util.IntentUtils;
|
||||
import app.organicmaps.car.util.ThemeUtils;
|
||||
import app.organicmaps.display.DisplayChangedListener;
|
||||
import app.organicmaps.display.DisplayManager;
|
||||
import app.organicmaps.display.DisplayType;
|
||||
import app.organicmaps.location.LocationHelper;
|
||||
import app.organicmaps.location.LocationState;
|
||||
import app.organicmaps.location.SensorHelper;
|
||||
import app.organicmaps.location.SensorListener;
|
||||
import app.organicmaps.routing.RoutingController;
|
||||
import app.organicmaps.util.Config;
|
||||
import app.organicmaps.util.LocationUtils;
|
||||
|
@ -46,7 +43,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
public final class CarAppSession extends Session implements DefaultLifecycleObserver,
|
||||
SensorListener, LocationState.ModeChangeListener, DisplayChangedListener, Framework.PlacePageActivationListener
|
||||
LocationState.ModeChangeListener, DisplayChangedListener, Framework.PlacePageActivationListener
|
||||
{
|
||||
private static final String TAG = CarAppSession.class.getSimpleName();
|
||||
|
||||
|
@ -56,6 +53,9 @@ public final class CarAppSession extends Session implements DefaultLifecycleObse
|
|||
private final SurfaceRenderer mSurfaceRenderer;
|
||||
@NonNull
|
||||
private final ScreenManager mScreenManager;
|
||||
@SuppressWarnings("NotNullFieldNotInitialized")
|
||||
@NonNull
|
||||
private CarSensorsManager mSensorsManager;
|
||||
@NonNull
|
||||
private final CurrentCountryChangedListener mCurrentCountryChangedListener;
|
||||
@SuppressWarnings("NotNullFieldNotInitialized")
|
||||
|
@ -111,6 +111,7 @@ public final class CarAppSession extends Session implements DefaultLifecycleObse
|
|||
public void onCreate(@NonNull LifecycleOwner owner)
|
||||
{
|
||||
Logger.d(TAG);
|
||||
mSensorsManager = new CarSensorsManager(getCarContext());
|
||||
mDisplayManager = DisplayManager.from(getCarContext());
|
||||
mDisplayManager.addListener(DisplayType.Car, this);
|
||||
init();
|
||||
|
@ -126,9 +127,8 @@ public final class CarAppSession extends Session implements DefaultLifecycleObse
|
|||
Framework.nativePlacePageActivationListener(this);
|
||||
mCurrentCountryChangedListener.onStart(getCarContext());
|
||||
}
|
||||
SensorHelper.from(getCarContext()).addListener(this);
|
||||
if (LocationUtils.checkFineLocationPermission(getCarContext()) && !LocationHelper.from(getCarContext()).isActive())
|
||||
LocationHelper.from(getCarContext()).start();
|
||||
if (LocationUtils.checkFineLocationPermission(getCarContext()))
|
||||
mSensorsManager.onStart();
|
||||
|
||||
if (mDisplayManager.isCarDisplayUsed())
|
||||
{
|
||||
|
@ -141,7 +141,7 @@ public final class CarAppSession extends Session implements DefaultLifecycleObse
|
|||
public void onStop(@NonNull LifecycleOwner owner)
|
||||
{
|
||||
Logger.d(TAG);
|
||||
SensorHelper.from(getCarContext()).removeListener(this);
|
||||
mSensorsManager.onStop();
|
||||
if (mDisplayManager.isCarDisplayUsed())
|
||||
{
|
||||
LocationState.nativeRemoveListener();
|
||||
|
@ -182,7 +182,7 @@ public final class CarAppSession extends Session implements DefaultLifecycleObse
|
|||
screensStack.add(new DownloadMapsScreenBuilder(getCarContext()).setDownloaderType(DownloadMapsScreenBuilder.DownloaderType.FirstLaunch).build());
|
||||
|
||||
if (!LocationUtils.checkFineLocationPermission(getCarContext()))
|
||||
screensStack.add(new RequestPermissionsScreen(getCarContext(), () -> LocationHelper.from(getCarContext()).start()));
|
||||
screensStack.add(new RequestPermissionsScreen(getCarContext(), mSensorsManager::onStart));
|
||||
|
||||
if (mDisplayManager.isDeviceDisplayUsed())
|
||||
{
|
||||
|
@ -205,11 +205,6 @@ public final class CarAppSession extends Session implements DefaultLifecycleObse
|
|||
screen.invalidate();
|
||||
}
|
||||
|
||||
public void onCompassUpdated(double north)
|
||||
{
|
||||
Map.onCompassUpdated(north, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayChangedToDevice(@NonNull Runnable onTaskFinishedCallback)
|
||||
{
|
||||
|
|
|
@ -7,10 +7,10 @@ import androidx.car.app.CarContext;
|
|||
import androidx.car.app.constraints.ConstraintManager;
|
||||
import androidx.car.app.model.Action;
|
||||
import androidx.car.app.model.CarIcon;
|
||||
import androidx.car.app.model.GridItem;
|
||||
import androidx.car.app.model.GridTemplate;
|
||||
import androidx.car.app.model.Header;
|
||||
import androidx.car.app.model.ItemList;
|
||||
import androidx.car.app.model.ListTemplate;
|
||||
import androidx.car.app.model.Row;
|
||||
import androidx.car.app.model.Template;
|
||||
import androidx.car.app.navigation.model.MapWithContentTemplate;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
|
@ -70,14 +70,14 @@ public class CategoriesScreen extends BaseMapScreen
|
|||
}
|
||||
|
||||
@NonNull
|
||||
private ListTemplate createCategoriesListTemplate()
|
||||
private GridTemplate createCategoriesListTemplate()
|
||||
{
|
||||
final boolean isNightMode = ThemeUtils.isNightMode(getCarContext());
|
||||
final ItemList.Builder builder = new ItemList.Builder();
|
||||
final int categoriesSize = Math.min(CATEGORIES.size(), MAX_CATEGORIES_SIZE);
|
||||
for (int i = 0; i < categoriesSize; ++i)
|
||||
{
|
||||
final Row.Builder itemBuilder = new Row.Builder();
|
||||
final GridItem.Builder itemBuilder = new GridItem.Builder();
|
||||
final String title = getCarContext().getString(CATEGORIES.get(i).nameResId);
|
||||
@DrawableRes final int iconResId = isNightMode ? CATEGORIES.get(i).iconNightResId : CATEGORIES.get(i).iconResId;
|
||||
|
||||
|
@ -86,6 +86,6 @@ public class CategoriesScreen extends BaseMapScreen
|
|||
itemBuilder.setOnClickListener(() -> getScreenManager().push(new SearchOnMapScreen.Builder(getCarContext(), getSurfaceRenderer()).setCategory(title).build()));
|
||||
builder.addItem(itemBuilder.build());
|
||||
}
|
||||
return new ListTemplate.Builder().setHeader(createHeader()).setSingleList(builder.build()).build();
|
||||
return new GridTemplate.Builder().setHeader(createHeader()).setSingleList(builder.build()).build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,11 @@ import androidx.car.app.CarContext;
|
|||
import androidx.car.app.model.Action;
|
||||
import androidx.car.app.model.ActionStrip;
|
||||
import androidx.car.app.model.CarIcon;
|
||||
import androidx.car.app.model.GridItem;
|
||||
import androidx.car.app.model.GridTemplate;
|
||||
import androidx.car.app.model.Header;
|
||||
import androidx.car.app.model.Item;
|
||||
import androidx.car.app.model.ItemList;
|
||||
import androidx.car.app.model.ListTemplate;
|
||||
import androidx.car.app.model.Row;
|
||||
import androidx.car.app.model.Template;
|
||||
import androidx.car.app.navigation.model.MapWithContentTemplate;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
|
@ -19,6 +19,7 @@ import app.organicmaps.car.SurfaceRenderer;
|
|||
import app.organicmaps.car.screens.base.BaseMapScreen;
|
||||
import app.organicmaps.car.screens.bookmarks.BookmarkCategoriesScreen;
|
||||
import app.organicmaps.car.screens.search.SearchScreen;
|
||||
import app.organicmaps.car.screens.settings.SettingsScreen;
|
||||
import app.organicmaps.car.util.SuggestionsHelpers;
|
||||
import app.organicmaps.car.util.UiHelpers;
|
||||
|
||||
|
@ -38,7 +39,7 @@ public class MapScreen extends BaseMapScreen
|
|||
final MapWithContentTemplate.Builder builder = new MapWithContentTemplate.Builder();
|
||||
builder.setMapController(UiHelpers.createMapController(getCarContext(), getSurfaceRenderer()));
|
||||
builder.setActionStrip(createActionStrip());
|
||||
builder.setContentTemplate(createListTemplate());
|
||||
builder.setContentTemplate(createGridTemplate());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
@ -60,19 +61,19 @@ public class MapScreen extends BaseMapScreen
|
|||
|
||||
final ActionStrip.Builder builder = new ActionStrip.Builder();
|
||||
builder.addAction(freeDriveScreenBuilder.build());
|
||||
builder.addAction(UiHelpers.createSettingsAction(this, getSurfaceRenderer()));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private ListTemplate createListTemplate()
|
||||
private GridTemplate createGridTemplate()
|
||||
{
|
||||
final ListTemplate.Builder builder = new ListTemplate.Builder();
|
||||
final GridTemplate.Builder builder = new GridTemplate.Builder();
|
||||
|
||||
final ItemList.Builder itemsBuilder = new ItemList.Builder();
|
||||
itemsBuilder.addItem(createSearchItem());
|
||||
itemsBuilder.addItem(createCategoriesItem());
|
||||
itemsBuilder.addItem(createBookmarksItem());
|
||||
itemsBuilder.addItem(createSettingsItem());
|
||||
|
||||
builder.setHeader(createHeader());
|
||||
builder.setSingleList(itemsBuilder.build());
|
||||
|
@ -84,10 +85,9 @@ public class MapScreen extends BaseMapScreen
|
|||
{
|
||||
final CarIcon iconSearch = new CarIcon.Builder(IconCompat.createWithResource(getCarContext(), R.drawable.ic_search)).build();
|
||||
|
||||
final Row.Builder builder = new Row.Builder();
|
||||
final GridItem.Builder builder = new GridItem.Builder();
|
||||
builder.setTitle(getCarContext().getString(R.string.search));
|
||||
builder.setImage(iconSearch);
|
||||
builder.setBrowsable(true);
|
||||
builder.setOnClickListener(this::openSearch);
|
||||
return builder.build();
|
||||
}
|
||||
|
@ -95,9 +95,11 @@ public class MapScreen extends BaseMapScreen
|
|||
@NonNull
|
||||
private Item createCategoriesItem()
|
||||
{
|
||||
final Row.Builder builder = new Row.Builder();
|
||||
final CarIcon iconCategories = new CarIcon.Builder(IconCompat.createWithResource(getCarContext(), R.drawable.ic_address)).build();
|
||||
|
||||
final GridItem.Builder builder = new GridItem.Builder();
|
||||
builder.setImage(iconCategories);
|
||||
builder.setTitle(getCarContext().getString(R.string.categories));
|
||||
builder.setBrowsable(true);
|
||||
builder.setOnClickListener(this::openCategories);
|
||||
return builder.build();
|
||||
}
|
||||
|
@ -105,13 +107,27 @@ public class MapScreen extends BaseMapScreen
|
|||
@NonNull
|
||||
private Item createBookmarksItem()
|
||||
{
|
||||
final Row.Builder builder = new Row.Builder();
|
||||
final CarIcon iconBookmarks = new CarIcon.Builder(IconCompat.createWithResource(getCarContext(), R.drawable.ic_bookmarks)).build();
|
||||
|
||||
final GridItem.Builder builder = new GridItem.Builder();
|
||||
builder.setImage(iconBookmarks);
|
||||
builder.setTitle(getCarContext().getString(R.string.bookmarks));
|
||||
builder.setBrowsable(true);
|
||||
builder.setOnClickListener(this::openBookmarks);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Item createSettingsItem()
|
||||
{
|
||||
final CarIcon iconSettings = new CarIcon.Builder(IconCompat.createWithResource(getCarContext(), R.drawable.ic_settings)).build();
|
||||
|
||||
final GridItem.Builder builder = new GridItem.Builder();
|
||||
builder.setImage(iconSettings);
|
||||
builder.setTitle(getCarContext().getString(R.string.settings));
|
||||
builder.setOnClickListener(this::openSettings);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private void openSearch()
|
||||
{
|
||||
// Details in UiHelpers.createSettingsAction()
|
||||
|
@ -135,4 +151,12 @@ public class MapScreen extends BaseMapScreen
|
|||
return;
|
||||
getScreenManager().push(new BookmarkCategoriesScreen(getCarContext(), getSurfaceRenderer()));
|
||||
}
|
||||
|
||||
private void openSettings()
|
||||
{
|
||||
// Details in UiHelpers.createSettingsAction()
|
||||
if (getScreenManager().getTop() != this)
|
||||
return;
|
||||
getScreenManager().push(new SettingsScreen(getCarContext(), getSurfaceRenderer()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
package app.organicmaps.car.util;
|
||||
|
||||
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
|
||||
|
||||
import android.location.Location;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresPermission;
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.hardware.CarHardwareManager;
|
||||
import androidx.car.app.hardware.common.CarValue;
|
||||
import androidx.car.app.hardware.info.CarHardwareLocation;
|
||||
import androidx.car.app.hardware.info.CarSensors;
|
||||
import androidx.car.app.hardware.info.Compass;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import app.organicmaps.Map;
|
||||
import app.organicmaps.location.LocationHelper;
|
||||
import app.organicmaps.location.SensorHelper;
|
||||
import app.organicmaps.util.log.Logger;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class CarSensorsManager
|
||||
{
|
||||
private static final String TAG = CarSensorsManager.class.getSimpleName();
|
||||
|
||||
@NonNull
|
||||
private final CarContext mCarContext;
|
||||
@NonNull
|
||||
private final CarSensors mCarSensors;
|
||||
|
||||
private boolean mIsCarCompassUsed = true;
|
||||
private boolean mIsCarLocationUsed = true;
|
||||
|
||||
public CarSensorsManager(@NonNull final CarContext context)
|
||||
{
|
||||
mCarContext = context;
|
||||
mCarSensors = mCarContext.getCarService(CarHardwareManager.class).getCarSensors();
|
||||
}
|
||||
|
||||
@RequiresPermission(ACCESS_FINE_LOCATION)
|
||||
public void onStart()
|
||||
{
|
||||
final Executor executor = ContextCompat.getMainExecutor(mCarContext);
|
||||
|
||||
if (mIsCarCompassUsed)
|
||||
mCarSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, executor, this::onCarCompassDataAvailable);
|
||||
else
|
||||
SensorHelper.from(mCarContext).addListener(this::onCompassUpdated);
|
||||
|
||||
if (!LocationHelper.from(mCarContext).isActive())
|
||||
LocationHelper.from(mCarContext).start();
|
||||
|
||||
if (mIsCarLocationUsed)
|
||||
mCarSensors.addCarHardwareLocationListener(CarSensors.UPDATE_RATE_FASTEST, executor, this::onCarLocationDataAvailable);
|
||||
}
|
||||
|
||||
public void onStop()
|
||||
{
|
||||
if (mIsCarCompassUsed)
|
||||
mCarSensors.removeCompassListener(this::onCarCompassDataAvailable);
|
||||
else
|
||||
SensorHelper.from(mCarContext).removeListener(this::onCompassUpdated);
|
||||
|
||||
if (mIsCarLocationUsed)
|
||||
mCarSensors.removeCarHardwareLocationListener(this::onCarLocationDataAvailable);
|
||||
}
|
||||
|
||||
private void onCarCompassDataAvailable(@NonNull final Compass compass)
|
||||
{
|
||||
final CarValue<List<Float>> data = compass.getOrientations();
|
||||
if (data.getStatus() == CarValue.STATUS_UNIMPLEMENTED)
|
||||
onCarCompassUnsupported();
|
||||
else if (data.getStatus() == CarValue.STATUS_SUCCESS)
|
||||
{
|
||||
final List<Float> orientations = compass.getOrientations().getValue();
|
||||
if (orientations == null)
|
||||
return;
|
||||
final float azimuth = orientations.get(0);
|
||||
Map.onCompassUpdated(Math.toRadians(azimuth), true);
|
||||
}
|
||||
}
|
||||
|
||||
private void onCompassUpdated(double north)
|
||||
{
|
||||
Map.onCompassUpdated(north, true);
|
||||
}
|
||||
|
||||
private void onCarLocationDataAvailable(@NonNull final CarHardwareLocation hardwareLocation)
|
||||
{
|
||||
final CarValue<Location> location = hardwareLocation.getLocation();
|
||||
if (location.getStatus() == CarValue.STATUS_UNIMPLEMENTED)
|
||||
onCarLocationUnsupported();
|
||||
else if (location.getStatus() == CarValue.STATUS_SUCCESS)
|
||||
{
|
||||
final Location loc = location.getValue();
|
||||
if (loc != null)
|
||||
LocationHelper.from(mCarContext).onLocationChanged(loc);
|
||||
}
|
||||
}
|
||||
|
||||
private void onCarLocationUnsupported()
|
||||
{
|
||||
Logger.d(TAG);
|
||||
mIsCarLocationUsed = false;
|
||||
mCarSensors.removeCarHardwareLocationListener(this::onCarLocationDataAvailable);
|
||||
}
|
||||
|
||||
private void onCarCompassUnsupported()
|
||||
{
|
||||
Logger.d(TAG);
|
||||
mIsCarCompassUsed = false;
|
||||
mCarSensors.removeCompassListener(this::onCarCompassDataAvailable);
|
||||
SensorHelper.from(mCarContext).addListener(this::onCompassUpdated);
|
||||
}
|
||||
}
|
|
@ -3,9 +3,11 @@ package app.organicmaps.location;
|
|||
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
|
||||
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
|
||||
|
@ -13,6 +15,7 @@ import androidx.annotation.NonNull;
|
|||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresPermission;
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.location.GnssStatusCompat;
|
||||
import androidx.core.location.LocationManagerCompat;
|
||||
|
@ -24,6 +27,7 @@ import app.organicmaps.bookmarks.data.FeatureId;
|
|||
import app.organicmaps.bookmarks.data.MapObject;
|
||||
import app.organicmaps.routing.JunctionInfo;
|
||||
import app.organicmaps.routing.RoutingController;
|
||||
import app.organicmaps.util.AppStateListener;
|
||||
import app.organicmaps.util.Config;
|
||||
import app.organicmaps.util.LocationUtils;
|
||||
import app.organicmaps.util.NetworkPolicy;
|
||||
|
@ -32,11 +36,14 @@ import app.organicmaps.util.log.Logger;
|
|||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class LocationHelper implements BaseLocationProvider.Listener
|
||||
public class LocationHelper
|
||||
implements BaseLocationProvider.Listener,
|
||||
AppStateListener
|
||||
{
|
||||
private static final long INTERVAL_FOLLOW_MS = 0;
|
||||
private static final long INTERVAL_NOT_FOLLOW_MS = 3000;
|
||||
private static final long INTERVAL_NAVIGATION_MS = 0;
|
||||
private static final long INTERVAL_TRACK_RECORDING_BACKGROUND = 10000;
|
||||
|
||||
private static final long AGPS_EXPIRATION_TIME_MS = 16 * 60 * 60 * 1000; // 16 hours
|
||||
|
||||
|
@ -79,6 +86,7 @@ public class LocationHelper implements BaseLocationProvider.Listener
|
|||
@Override
|
||||
public void onSatelliteStatusChanged(@NonNull GnssStatusCompat status)
|
||||
{
|
||||
Logger.d(TAG,"value of interval "+ mInterval);
|
||||
int used = 0;
|
||||
boolean fixed = false;
|
||||
for (int i = 0; i < status.getSatelliteCount(); i++)
|
||||
|
@ -103,6 +111,7 @@ public class LocationHelper implements BaseLocationProvider.Listener
|
|||
{
|
||||
mContext = context;
|
||||
mLocationProvider = LocationProviderFactory.getProvider(mContext, this);
|
||||
MwmApplication.from(mContext).addListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -172,6 +181,7 @@ public class LocationHelper implements BaseLocationProvider.Listener
|
|||
public void onLocationChanged(@NonNull Location location)
|
||||
{
|
||||
Logger.d(TAG, "provider = " + mLocationProvider.getClass().getSimpleName() + " location = " + location);
|
||||
Logger.d(TAG,"value of interval "+ mInterval);
|
||||
|
||||
if (!isActive())
|
||||
{
|
||||
|
@ -230,7 +240,7 @@ public class LocationHelper implements BaseLocationProvider.Listener
|
|||
{
|
||||
// Try to downgrade to the native provider first and restart the service before notifying the user.
|
||||
Logger.d(TAG, "provider = " + mLocationProvider.getClass().getSimpleName() + " is not supported," +
|
||||
" downgrading to use native provider");
|
||||
" downgrading to use native provider");
|
||||
mLocationProvider.stop();
|
||||
mLocationProvider = new AndroidNativeProvider(mContext, this);
|
||||
mActive = true;
|
||||
|
@ -394,7 +404,6 @@ public class LocationHelper implements BaseLocationProvider.Listener
|
|||
Logger.i(TAG, "Permissions ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION are not granted");
|
||||
return;
|
||||
}
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
|
@ -466,4 +475,29 @@ public class LocationHelper implements BaseLocationProvider.Listener
|
|||
Framework.nativeRunFirstLaunchAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppBackround()
|
||||
{
|
||||
Logger.i("kavi", "Location helper knows app went in background");
|
||||
if (!RoutingController.get().isNavigating() && isActive() && TrackRecorder.nativeIsEnabled() && mInterval != INTERVAL_TRACK_RECORDING_BACKGROUND)
|
||||
{
|
||||
Logger.i(TAG, "update refresh interval: old = " + mInterval + " new = " + INTERVAL_TRACK_RECORDING_BACKGROUND);
|
||||
if (LocationUtils.checkLocationPermission(mContext))
|
||||
{
|
||||
mLocationProvider.stop();
|
||||
mInterval = INTERVAL_TRACK_RECORDING_BACKGROUND;
|
||||
mLocationProvider.start(INTERVAL_TRACK_RECORDING_BACKGROUND);
|
||||
}
|
||||
}
|
||||
Logger.i("kavi","interval is "+ mInterval);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppForeground()
|
||||
{
|
||||
Logger.i("kavi", "Location helper knows app came in foreground");
|
||||
resumeLocationInForeground();
|
||||
if(LocationUtils.checkLocationPermission(mContext)) restartWithNewMode();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package app.organicmaps.location;
|
||||
|
||||
public abstract 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();
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
package app.organicmaps.location;
|
||||
|
||||
import android.app.ForegroundServiceStartNotAllowedException;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.location.Location;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.annotation.RequiresPermission;
|
||||
import androidx.core.app.NotificationChannelCompat;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import app.organicmaps.MwmActivity;
|
||||
import app.organicmaps.MwmApplication;
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.settings.TrackRecordSettingsFragment;
|
||||
import app.organicmaps.util.LocationUtils;
|
||||
import app.organicmaps.util.log.Logger;
|
||||
|
||||
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
|
||||
|
||||
public class TrackRecordingService extends Service implements LocationListener
|
||||
{
|
||||
public static final String TRACK_REC_CHANNEL_ID = "TRACK RECORDING";
|
||||
public static final int TRACK_REC_NOTIFICATION_ID = 54321;
|
||||
private static NotificationCompat.Builder mNotificationBuilder;
|
||||
private static final String TAG = TrackRecordingService.class.getSimpleName();
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IBinder onBind(Intent intent)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@RequiresPermission(value = ACCESS_FINE_LOCATION)
|
||||
public static void startForegroundService(@NonNull Context context)
|
||||
{
|
||||
ContextCompat.startForegroundService(context, new Intent(context, TrackRecordingService.class));
|
||||
}
|
||||
|
||||
public static void createNotificationChannel(@NonNull Context context)
|
||||
{
|
||||
final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
|
||||
final NotificationChannelCompat channel = new NotificationChannelCompat.Builder(TRACK_REC_CHANNEL_ID,
|
||||
NotificationManagerCompat.IMPORTANCE_LOW)
|
||||
.setName("Track Recording")
|
||||
.setLightsEnabled(false)
|
||||
.setVibrationEnabled(false)
|
||||
.build();
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
public static NotificationCompat.Builder getNotificationBuilder(@NonNull Context context)
|
||||
{
|
||||
if (mNotificationBuilder != null)
|
||||
return mNotificationBuilder;
|
||||
|
||||
final int FLAG_IMMUTABLE = Build.VERSION.SDK_INT < Build.VERSION_CODES.M ? 0 : PendingIntent.FLAG_IMMUTABLE;
|
||||
final Intent contentIntent = new Intent(context, MwmActivity.class);
|
||||
final PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, contentIntent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE);
|
||||
|
||||
mNotificationBuilder = new NotificationCompat.Builder(context, TRACK_REC_CHANNEL_ID)
|
||||
.setCategory(NotificationCompat.CATEGORY_SERVICE)
|
||||
.setPriority(NotificationManager.IMPORTANCE_LOW)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
.setOngoing(true)
|
||||
.setShowWhen(true)
|
||||
.setOnlyAlertOnce(true)
|
||||
.setSmallIcon(R.drawable.ic_splash)
|
||||
.setContentTitle("Track Recording is Running")
|
||||
.setContentText("Recording your traversed tracks in background")
|
||||
.setContentIntent(pendingIntent)
|
||||
.setColor(ContextCompat.getColor(context, R.color.notification));
|
||||
|
||||
return mNotificationBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy()
|
||||
{
|
||||
mNotificationBuilder = null;
|
||||
LocationHelper.from(this).removeListener(this);
|
||||
if(TrackRecorder.nativeIsEnabled()) TrackRecorder.nativeSetEnabled(false);
|
||||
// The notification is cancelled automatically by the system.
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(@NonNull Intent intent, int flags, int startId)
|
||||
{
|
||||
|
||||
if (!MwmApplication.from(this).arePlatformAndCoreInitialized())
|
||||
{
|
||||
Logger.w(TAG, "Application is not initialized");
|
||||
stopSelf();
|
||||
return START_NOT_STICKY; // The service will be stopped by stopSelf().
|
||||
}
|
||||
|
||||
if (!LocationUtils.checkFineLocationPermission(this))
|
||||
{
|
||||
// In a hypothetical scenario, the user could revoke location permissions after the app's process crashed,
|
||||
// but before the service with START_STICKY was restarted by the system.
|
||||
Logger.w(TAG, "Permission ACCESS_FINE_LOCATION is not granted, skipping TrackRecordingService");
|
||||
stopSelf();
|
||||
return START_NOT_STICKY; // The service will be stopped by stopSelf().
|
||||
}
|
||||
|
||||
if(!TrackRecorder.nativeIsEnabled())
|
||||
{
|
||||
Logger.i("kavi","Service can't be started because Track Recorder is turned off in settings");
|
||||
stopSelf();
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
Logger.i(TAG, "Starting foreground");
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
|
||||
{
|
||||
try
|
||||
{
|
||||
startForeground(TrackRecordingService.TRACK_REC_NOTIFICATION_ID, getNotificationBuilder(this).build());
|
||||
} catch (ForegroundServiceStartNotAllowedException e)
|
||||
{
|
||||
Logger.e(TAG, "Oops! ForegroundService is not allowed", e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
startForeground(TrackRecordingService.TRACK_REC_NOTIFICATION_ID, getNotificationBuilder(this).build());
|
||||
}
|
||||
|
||||
final LocationHelper locationHelper = LocationHelper.from(this);
|
||||
|
||||
// Subscribe to location updates. This call is idempotent.
|
||||
locationHelper.addListener(this);
|
||||
|
||||
// Restart the location with more frequent refresh interval for Track Recording.
|
||||
locationHelper.restartWithNewMode();
|
||||
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
public static void stopService(@NonNull Context context)
|
||||
{
|
||||
Logger.i(TAG);
|
||||
context.stopService(new Intent(context, TrackRecordingService.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationUpdated(@NonNull Location location)
|
||||
{
|
||||
Logger.i(TAG,"Location is being updated in Track Recording service");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationDisabled()
|
||||
{
|
||||
LocationListener.super.onLocationDisabled();
|
||||
TrackRecorder.nativeSetEnabled(false);
|
||||
stopSelf();
|
||||
}
|
||||
|
||||
}
|
|
@ -104,6 +104,10 @@ public class SettingsPrefsFragment extends BaseXmlSettingsFragment
|
|||
{
|
||||
startActivity(new Intent(requireActivity(), HelpActivity.class));
|
||||
}
|
||||
else if (key.equals(getString(R.string.pref_track_record)))
|
||||
{
|
||||
getSettingsActivity().stackFragment(TrackRecordSettingsFragment.class,"Track Recorder",null);
|
||||
}
|
||||
}
|
||||
return super.onPreferenceTreeClick(preference);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
package app.organicmaps.settings;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.location.Location;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.TwoStatePreference;
|
||||
import app.organicmaps.MwmApplication;
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.location.LocationHelper;
|
||||
import app.organicmaps.location.LocationListener;
|
||||
import app.organicmaps.location.TrackRecorder;
|
||||
import app.organicmaps.location.TrackRecordingService;
|
||||
import app.organicmaps.util.LocationUtils;
|
||||
import app.organicmaps.util.log.Logger;
|
||||
|
||||
import static app.organicmaps.location.TrackRecordingService.stopService;
|
||||
|
||||
public class TrackRecordSettingsFragment extends BaseXmlSettingsFragment implements LocationListener
|
||||
{
|
||||
private ListPreference mRecordTime;
|
||||
private TwoStatePreference mRecentTrack;
|
||||
|
||||
@Override
|
||||
protected int getXmlResources()
|
||||
{
|
||||
return R.xml.pref_track_record;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
|
||||
{
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
mRecentTrack = getPreference(getString(R.string.pref_recent_track));
|
||||
mRecordTime = getPreference(getString(R.string.pref_track_record_time));
|
||||
LocationHelper.from(requireContext()).addListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart()
|
||||
{
|
||||
super.onStart();
|
||||
mRecentTrack.setChecked(TrackRecorder.nativeIsEnabled());
|
||||
mRecordTime.setValue(Integer.toString(TrackRecorder.nativeGetDuration()));
|
||||
if(TrackRecorder.nativeIsEnabled())
|
||||
{
|
||||
mRecordTime.setSummary("Last " + TrackRecorder.nativeGetDuration() + " hours trails will be shown on map");
|
||||
}
|
||||
else
|
||||
{
|
||||
mRecordTime.setSummary("Enable Recent Track Recorder to select duration for which recorded point will be shown on map");
|
||||
}
|
||||
mRecordTime.setEnabled(TrackRecorder.nativeIsEnabled());
|
||||
mRecentTrack.setOnPreferenceChangeListener(((preference, newValue) -> {
|
||||
if (newValue == null)
|
||||
return false;
|
||||
|
||||
boolean newVal = (boolean) newValue;
|
||||
|
||||
if (newVal)
|
||||
{
|
||||
if(!LocationUtils.areLocationServicesTurnedOn(MwmApplication.from(requireContext()))){
|
||||
Toast.makeText(getActivity(),"Please turn on location",Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
if (!LocationUtils.checkLocationPermission(MwmApplication.from(requireContext())))
|
||||
{
|
||||
Toast.makeText(getActivity(),"Please give permission of precise location access",Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
TrackRecordingService.startForegroundService(MwmApplication.from(requireContext()));
|
||||
mRecordTime.setSummary("Last " + TrackRecorder.nativeGetDuration() + " hour trails will be shown on map");
|
||||
}
|
||||
else
|
||||
{
|
||||
stopService(MwmApplication.from(requireContext()));
|
||||
mRecordTime.setSummary("Enable Recent Track Recorder to select duration for which recorded point will be shown on map");
|
||||
}
|
||||
mRecentTrack.setChecked(newVal);
|
||||
mRecordTime.setEnabled(newVal);
|
||||
TrackRecorder.nativeSetEnabled(newVal);
|
||||
|
||||
return true;
|
||||
}));
|
||||
|
||||
mRecordTime.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
if (newValue == null)
|
||||
return false;
|
||||
String newVal = (String) newValue;
|
||||
if(newVal.equals(mRecordTime.getValue()))
|
||||
return false;
|
||||
|
||||
mRecordTime.setSummary("Last " + newVal + " hour trails will be shown on map");
|
||||
int hours = Integer.parseInt(newVal);
|
||||
TrackRecorder.nativeSetDuration(hours);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView()
|
||||
{
|
||||
super.onDestroyView();
|
||||
LocationHelper.from(requireContext()).removeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationUpdated(@NonNull Location location)
|
||||
{
|
||||
//No requirement of this method here
|
||||
}
|
||||
|
||||
//This method has been added to make the toggle switch of Record Recent Track alive
|
||||
@Override
|
||||
public void onLocationDisabled()
|
||||
{
|
||||
LocationListener.super.onLocationDisabled();
|
||||
Logger.i("kavi","yaha tak aya");
|
||||
if(mRecentTrack == null || mRecentTrack.getOnPreferenceChangeListener() == null) return;
|
||||
Logger.i("kavi","yaha tak bhi aya waah");
|
||||
mRecentTrack.getOnPreferenceChangeListener().onPreferenceChange(getPreference(getString(R.string.pref_recent_track)),false);
|
||||
// mRecentTrack.setChecked(false);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package app.organicmaps.util;
|
||||
|
||||
public interface AppStateListener
|
||||
{
|
||||
void onAppBackround();
|
||||
void onAppForeground();
|
||||
}
|
|
@ -25,6 +25,10 @@
|
|||
<string name="pref_tts_info" translatable="false">TtsInfo</string>
|
||||
<string name="pref_tts_info_link" translatable="false">TtsInfoLink</string>
|
||||
<string name="pref_tts_speed_cameras" translatable="false">SpeedCameras</string>
|
||||
<string name="pref_recent_track" translatable="false">RecentTrackRecord</string>
|
||||
<string name="pref_track_record" translatable="false">TrackRecord</string>
|
||||
<string name="pref_track_record_switch" translatable="false">TrackRecordSwitch</string>
|
||||
<string name="pref_track_record_time" translatable="false">TrackRecordTime</string>
|
||||
<!-- TODO: Move to another domain. -->
|
||||
<string name="tts_info_link" translatable="false">https://mapsme.zendesk.com/hc/en-us/articles/208628985-How-can-I-check-TTS-settings-on-my-Android-device-</string>
|
||||
<string name="prefs_routing" translatable="false">RoutingOptions</string>
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
</string-array>
|
||||
|
||||
<string-array name="track_length">
|
||||
<item>@string/duration_disabled</item>
|
||||
<item>@string/duration_1_hour</item>
|
||||
<item>@string/duration_2_hours</item>
|
||||
<item>@string/duration_6_hours</item>
|
||||
|
@ -59,7 +58,6 @@
|
|||
</string-array>
|
||||
|
||||
<string-array name="track_length_values">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>6</item>
|
||||
|
|
|
@ -2196,4 +2196,6 @@
|
|||
<string name="type.amenity.events_venue">Events Venue</string>
|
||||
<string name="type.shop.auction">Auction</string>
|
||||
<string name="type.shop.collector">Collectables</string>
|
||||
<string name="pref_track_record_title">Record Track</string>
|
||||
<string name="recent_track_help_text">This option allows you to record traveled path for a certain period and see it on the map. Please note: activation of this function causes increased battery usage. The track will be removed automatically from the map after the time interval will expire.</string>
|
||||
</resources>
|
||||
|
|
18
android/app/src/main/res/xml/pref_track_record.xml
Normal file
18
android/app/src/main/res/xml/pref_track_record.xml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<SwitchPreferenceCompat
|
||||
android:key="@string/pref_recent_track"
|
||||
android:title="Record Recent Track"
|
||||
android:order="1"/>
|
||||
<ListPreference
|
||||
android:key="@string/pref_track_record_time"
|
||||
android:title="Record time"
|
||||
app:singleLineTitle="false"
|
||||
android:summary="Select duration for which recorded point will be shown on map"
|
||||
android:entries="@array/track_length"
|
||||
android:entryValues="@array/track_length_values"
|
||||
android:order="2"/>
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
|
@ -54,6 +54,12 @@
|
|||
app:singleLineTitle="false"
|
||||
android:summary="@string/maps_storage_summary"
|
||||
android:order="8"/>
|
||||
<Preference
|
||||
android:key="@string/pref_track_record"
|
||||
android:title="@string/pref_track_record_title"
|
||||
app:singleLineTitle="false"
|
||||
android:summary="This option allows you to record your recent traversed tracks"
|
||||
android:order="9"/>
|
||||
<SwitchPreferenceCompat
|
||||
android:key="@string/pref_enable_logging"
|
||||
android:title="@string/enable_logging"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
plugins {
|
||||
id 'com.android.application' version '8.3.2' apply false
|
||||
id 'com.android.library' version '8.3.2' apply false
|
||||
id 'com.android.application' version '8.4.0' apply false
|
||||
id 'com.android.library' version '8.4.0' apply false
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue