diff --git a/android/app/build.gradle b/android/app/build.gradle index a8a0f0ef65b90..1800b39c88e66 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -381,6 +381,7 @@ dependencies { 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.preference:preference:1.2.1' diff --git a/android/app/src/main/java/app/organicmaps/car/CarAppSession.java b/android/app/src/main/java/app/organicmaps/car/CarAppSession.java index 5d8797d7d05d3..e2a5c2111ef59 100644 --- a/android/app/src/main/java/app/organicmaps/car/CarAppSession.java +++ b/android/app/src/main/java/app/organicmaps/car/CarAppSession.java @@ -13,7 +13,6 @@ 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.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.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 void onNewIntent(@NonNull Intent intent) 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 void onStart(@NonNull LifecycleOwner owner) 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 void onStart(@NonNull LifecycleOwner owner) 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 @@ private Screen prepareScreens() 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 void onMyPositionModeChanged(int newMode) screen.invalidate(); } - public void onCompassUpdated(double north) - { - Map.onCompassUpdated(north, true); - } - @Override public void onDisplayChangedToDevice(@NonNull Runnable onTaskFinishedCallback) { diff --git a/android/app/src/main/java/app/organicmaps/car/util/CarSensorsManager.java b/android/app/src/main/java/app/organicmaps/car/util/CarSensorsManager.java new file mode 100644 index 0000000000000..b8c9a68c371bd --- /dev/null +++ b/android/app/src/main/java/app/organicmaps/car/util/CarSensorsManager.java @@ -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> data = compass.getOrientations(); + if (data.getStatus() == CarValue.STATUS_UNIMPLEMENTED) + onCarCompassUnsupported(); + else if (data.getStatus() == CarValue.STATUS_SUCCESS) + { + final List 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 = 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); + } +}