From 382b1e0642906ce92d2e46b557eb50b3edb43ae3 Mon Sep 17 00:00:00 2001 From: Roman Tsisyk Date: Sat, 2 Sep 2023 11:15:25 +0300 Subject: [PATCH] [android] Decouple SensorHelper from LocationHelper Compass and location are two different things. Rename SensorsHelper to CompassHelper and extract it from LocationHelper to the upper level to simplify LocationHelper. Please note that SensorHelper is still started by LocationHelper to avoid any semantic changes. Signed-off-by: Roman Tsisyk --- .../java/app/organicmaps/MwmActivity.java | 24 +++- .../java/app/organicmaps/MwmApplication.java | 14 +- .../organicmaps/location/LocationHelper.java | 35 +---- .../location/LocationListener.java | 5 - .../app/organicmaps/location/SensorData.java | 38 ------ .../organicmaps/location/SensorHelper.java | 127 +++++++++++++----- .../organicmaps/location/SensorListener.java | 16 +++ .../widget/placepage/DirectionFragment.java | 6 +- .../widget/placepage/PlacePageView.java | 6 +- 9 files changed, 161 insertions(+), 110 deletions(-) delete mode 100644 android/app/src/main/java/app/organicmaps/location/SensorData.java create mode 100644 android/app/src/main/java/app/organicmaps/location/SensorListener.java diff --git a/android/app/src/main/java/app/organicmaps/MwmActivity.java b/android/app/src/main/java/app/organicmaps/MwmActivity.java index 60ae1ed8c4..16bee7408a 100644 --- a/android/app/src/main/java/app/organicmaps/MwmActivity.java +++ b/android/app/src/main/java/app/organicmaps/MwmActivity.java @@ -16,6 +16,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; import android.widget.TextView; +import android.widget.Toast; import androidx.activity.result.ActivityResult; import androidx.activity.result.ActivityResultLauncher; @@ -63,6 +64,8 @@ import app.organicmaps.intent.MapTask; import app.organicmaps.location.LocationHelper; import app.organicmaps.location.LocationListener; import app.organicmaps.location.LocationState; +import app.organicmaps.location.SensorHelper; +import app.organicmaps.location.SensorListener; import app.organicmaps.maplayer.MapButtonsController; import app.organicmaps.maplayer.MapButtonsViewModel; import app.organicmaps.maplayer.Mode; @@ -121,6 +124,7 @@ public class MwmActivity extends BaseMwmFragmentActivity CustomNavigateUpListener, RoutingController.Container, LocationListener, + SensorListener, LocationState.ModeChangeListener, RoutingPlanInplaceController.RoutingPlanListener, RoutingBottomMenuListener, @@ -1011,6 +1015,7 @@ public class MwmActivity extends BaseMwmFragmentActivity refreshLightStatusBar(); LocationState.nativeSetLocationPendingTimeoutListener(this::onLocationPendingTimeout); + SensorHelper.from(this).addListener(this); } @Override @@ -1038,6 +1043,7 @@ public class MwmActivity extends BaseMwmFragmentActivity mOnmapDownloader.onPause(); mNavigationController.onActivityPaused(this); LocationState.nativeRemoveLocationPendingTimeoutListener(); + SensorHelper.from(this).removeListener(this); dismissLocationErrorDialog(); dismissAlertDialog(); super.onPause(); @@ -1229,7 +1235,7 @@ public class MwmActivity extends BaseMwmFragmentActivity mMapFragment.updateCompassOffset(offsetX, offsetY); - final double north = LocationHelper.INSTANCE.getSavedNorth(); + final double north = SensorHelper.from(this).getSavedNorth(); if (!Double.isNaN(north)) Map.onCompassUpdated(north, true); } @@ -1739,6 +1745,22 @@ public class MwmActivity extends BaseMwmFragmentActivity mNavigationController.updateNorth(); } + @Override + @UiThread + public void onCompassCalibrationRecommended() + { + Toast.makeText(this, getString(R.string.compass_calibration_recommended), + Toast.LENGTH_LONG).show(); + } + + @Override + @UiThread + public void onCompassCalibrationRequired() + { + Toast.makeText(this, getString(R.string.compass_calibration_required), + Toast.LENGTH_LONG).show(); + } + /** * Start location services when the user presses a button or starts routing. */ diff --git a/android/app/src/main/java/app/organicmaps/MwmApplication.java b/android/app/src/main/java/app/organicmaps/MwmApplication.java index d88f002d2d..aff6656ba2 100644 --- a/android/app/src/main/java/app/organicmaps/MwmApplication.java +++ b/android/app/src/main/java/app/organicmaps/MwmApplication.java @@ -23,6 +23,7 @@ import app.organicmaps.bookmarks.data.BookmarkManager; import app.organicmaps.downloader.CountryItem; import app.organicmaps.downloader.MapManager; import app.organicmaps.location.LocationHelper; +import app.organicmaps.location.SensorHelper; import app.organicmaps.maplayer.isolines.IsolinesManager; import app.organicmaps.maplayer.subway.SubwayManager; import app.organicmaps.maplayer.traffic.TrafficManager; @@ -59,6 +60,10 @@ public class MwmApplication extends Application implements Application.ActivityL @NonNull private IsolinesManager mIsolinesManager; + @SuppressWarnings("NotNullFieldNotInitialized") + @NonNull + private SensorHelper mSensorHelper; + private volatile boolean mFrameworkInitialized; private volatile boolean mPlatformInitialized; @@ -90,6 +95,12 @@ public class MwmApplication extends Application implements Application.ActivityL return mIsolinesManager; } + @NonNull + public SensorHelper getSensorHelper() + { + return mSensorHelper; + } + public MwmApplication() { super(); @@ -131,6 +142,7 @@ public class MwmApplication extends Application implements Application.ActivityL registerActivityLifecycleCallbacks(this); mSubwayManager = new SubwayManager(this); mIsolinesManager = new IsolinesManager(this); + mSensorHelper = new SensorHelper(this); mPlayer = new MediaPlayerWrapper(this); } @@ -294,7 +306,7 @@ public class MwmApplication extends Application implements Application.ActivityL { Logger.d(TAG, "activity = " + activity); Utils.showOnLockScreen(Config.isShowOnLockScreenEnabled(), activity); - LocationHelper.INSTANCE.setRotation(activity.getWindowManager().getDefaultDisplay().getRotation()); + mSensorHelper.setRotation(activity.getWindowManager().getDefaultDisplay().getRotation()); mTopActivity = new WeakReference<>(activity); } diff --git a/android/app/src/main/java/app/organicmaps/location/LocationHelper.java b/android/app/src/main/java/app/organicmaps/location/LocationHelper.java index 513657404b..db07af7354 100644 --- a/android/app/src/main/java/app/organicmaps/location/LocationHelper.java +++ b/android/app/src/main/java/app/organicmaps/location/LocationHelper.java @@ -3,7 +3,6 @@ package app.organicmaps.location; import static android.Manifest.permission.ACCESS_COARSE_LOCATION; import static android.Manifest.permission.ACCESS_FINE_LOCATION; import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static app.organicmaps.location.LocationState.LOCATION_TAG; import android.app.PendingIntent; import android.content.Context; @@ -14,7 +13,6 @@ 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 app.organicmaps.Framework; @@ -54,25 +52,18 @@ public enum LocationHelper implements Initializable, BaseLocationProvid private final Set mListeners = new LinkedHashSet<>(); @Nullable private Location mSavedLocation; - private double mSavedNorth = Double.NaN; private MapObject mMyPosition; @SuppressWarnings("NotNullFieldNotInitialized") @NonNull - private SensorHelper mSensorHelper; - @SuppressWarnings("NotNullFieldNotInitialized") - @NonNull private BaseLocationProvider mLocationProvider; private long mInterval; private boolean mInFirstRun; private boolean mActive; - private int mRotation = 0; - @Override public void initialize(@NonNull Context context) { mContext = context; - mSensorHelper = new SensorHelper(context); mLocationProvider = LocationProviderFactory.getProvider(mContext, this); } @@ -119,19 +110,6 @@ public enum LocationHelper implements Initializable, BaseLocationProvid return mActive; } - public void setRotation(int rotation) - { - Logger.i(TAG, "rotation = " + rotation); - mRotation = rotation; - } - - void notifyCompassUpdated(double north) - { - mSavedNorth = LocationUtils.correctCompassAngle(mRotation, north); - for (LocationListener listener : mListeners) - listener.onCompassUpdated(mSavedNorth); - } - private void notifyLocationUpdated() { if (mSavedLocation == null) @@ -243,8 +221,6 @@ public enum LocationHelper implements Initializable, BaseLocationProvid mListeners.add(listener); if (mSavedLocation != null) listener.onLocationUpdated(mSavedLocation); - if (!Double.isNaN(mSavedNorth)) - listener.onCompassUpdated(mSavedNorth); } /** @@ -345,7 +321,9 @@ public enum LocationHelper implements Initializable, BaseLocationProvid Logger.i(TAG); checkForAgpsUpdates(); - mSensorHelper.start(); + if (ContextCompat.checkSelfPermission(mContext, ACCESS_FINE_LOCATION) == PERMISSION_GRANTED) + SensorHelper.from(mContext).start(); + final long oldInterval = mInterval; calcLocationUpdatesInterval(); Logger.i(TAG, "provider = " + mLocationProvider.getClass().getSimpleName() + @@ -367,7 +345,7 @@ public enum LocationHelper implements Initializable, BaseLocationProvid Logger.i(TAG); mLocationProvider.stop(); - mSensorHelper.stop(); + SensorHelper.from(mContext).stop(); mActive = false; } @@ -444,9 +422,4 @@ public enum LocationHelper implements Initializable, BaseLocationProvid Framework.nativeRunFirstLaunchAnimation(); } } - - public double getSavedNorth() - { - return mSavedNorth; - } } diff --git a/android/app/src/main/java/app/organicmaps/location/LocationListener.java b/android/app/src/main/java/app/organicmaps/location/LocationListener.java index a6d0c3eadb..17143bf449 100644 --- a/android/app/src/main/java/app/organicmaps/location/LocationListener.java +++ b/android/app/src/main/java/app/organicmaps/location/LocationListener.java @@ -9,11 +9,6 @@ public interface LocationListener { void onLocationUpdated(@NonNull Location location); - default void onCompassUpdated(double north) - { - // No op. - } - default void onLocationDisabled() { // No op. diff --git a/android/app/src/main/java/app/organicmaps/location/SensorData.java b/android/app/src/main/java/app/organicmaps/location/SensorData.java deleted file mode 100644 index f772719ad4..0000000000 --- a/android/app/src/main/java/app/organicmaps/location/SensorData.java +++ /dev/null @@ -1,38 +0,0 @@ -package app.organicmaps.location; - -import androidx.annotation.Nullable; - -class SensorData -{ - @Nullable - private float[] mGravity; - @Nullable - private float[] mGeomagnetic; - - @Nullable - public float[] getGravity() - { - return mGravity; - } - - public void setGravity(@Nullable float[] gravity) - { - mGravity = gravity; - } - - @Nullable - public float[] getGeomagnetic() - { - return mGeomagnetic; - } - - public void setGeomagnetic(@Nullable float[] geomagnetic) - { - mGeomagnetic = geomagnetic; - } - - public boolean isAbsent() - { - return mGravity == null || mGeomagnetic == null; - } -} diff --git a/android/app/src/main/java/app/organicmaps/location/SensorHelper.java b/android/app/src/main/java/app/organicmaps/location/SensorHelper.java index ee3f2f17bb..57d11c8ed5 100644 --- a/android/app/src/main/java/app/organicmaps/location/SensorHelper.java +++ b/android/app/src/main/java/app/organicmaps/location/SensorHelper.java @@ -6,27 +6,42 @@ import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.util.Log; -import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import app.organicmaps.MwmApplication; -import app.organicmaps.R; +import app.organicmaps.util.LocationUtils; +import app.organicmaps.util.log.Logger; -class SensorHelper implements SensorEventListener +import java.util.LinkedHashSet; +import java.util.Set; + +public class SensorHelper implements SensorEventListener { + private static final String TAG = SensorHelper.class.getSimpleName(); + @NonNull private final SensorManager mSensorManager; @Nullable - private final Sensor mRotationVectorSensor; - @NonNull - private final MwmApplication mMwmApplication; + private Sensor mRotationVectorSensor; private final float[] mRotationMatrix = new float[9]; private final float[] mRotationValues = new float[3]; // Initialized with purposely invalid value. private int mLastAccuracy = -42; + private double mSavedNorth = Double.NaN; + private int mRotation = 0; + + @NonNull + private final Set mListeners = new LinkedHashSet<>(); + + @NonNull + public static SensorHelper from(@NonNull Context context) + { + return MwmApplication.from(context).getSensorHelper(); + } @Override public void onSensorChanged(SensorEvent event) @@ -43,16 +58,14 @@ class SensorHelper implements SensorEventListener case SensorManager.SENSOR_STATUS_ACCURACY_HIGH: break; case SensorManager.SENSOR_STATUS_ACCURACY_MEDIUM: - Toast.makeText(mMwmApplication, - mMwmApplication.getString(R.string.compass_calibration_recommended), - Toast.LENGTH_LONG).show(); + for (SensorListener listener : mListeners) + listener.onCompassCalibrationRecommended(); break; case SensorManager.SENSOR_STATUS_ACCURACY_LOW: case SensorManager.SENSOR_STATUS_UNRELIABLE: default: - Toast.makeText(mMwmApplication, - mMwmApplication.getString(R.string.compass_calibration_required), - Toast.LENGTH_LONG).show(); + for (SensorListener listener : mListeners) + listener.onCompassCalibrationRequired(); } } @@ -63,7 +76,9 @@ class SensorHelper implements SensorEventListener SensorManager.getOrientation(mRotationMatrix, mRotationValues); // mRotationValues indexes: 0 - yaw (azimuth), 1 - pitch, 2 - roll. - LocationHelper.INSTANCE.notifyCompassUpdated(mRotationValues[0]); + mSavedNorth = LocationUtils.correctCompassAngle(mRotation, mRotationValues[0]); + for (SensorListener listener : mListeners) + listener.onCompassUpdated(mSavedNorth); } @Override @@ -75,31 +90,79 @@ class SensorHelper implements SensorEventListener // Looks like modern Androids can send this event after starting the sensor. } - SensorHelper(@NonNull Context context) + public SensorHelper(@NonNull Context context) { - mMwmApplication = MwmApplication.from(context); - mSensorManager = (SensorManager) mMwmApplication.getSystemService(Context.SENSOR_SERVICE); - Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR); - if (sensor == null) + mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); + } + + public double getSavedNorth() + { + return mSavedNorth; + } + + public void setRotation(int rotation) + { + Logger.i(TAG, "rotation = " + rotation); + mRotation = rotation; + } + + /** + * Registers listener to obtain compass updates. + * @param listener listener to be registered. + */ + @UiThread + public void addListener(@NonNull SensorListener listener) + { + Logger.d(TAG, "listener: " + listener + " count was: " + mListeners.size()); + + mListeners.add(listener); + if (!Double.isNaN(mSavedNorth)) + listener.onCompassUpdated(mSavedNorth); + } + + /** + * Removes given compass listener. + * @param listener listener to unregister. + */ + @UiThread + public void removeListener(@NonNull SensorListener listener) + { + Logger.d(TAG, "listener: " + listener + " count was: " + mListeners.size()); + mListeners.remove(listener); + } + + public void start() + { + if (mRotationVectorSensor != null) { - Log.w("SensorHelper", "WARNING: There is no ROTATION_VECTOR sensor, requesting GEOMAGNETIC_ROTATION_VECTOR"); - sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR); - if (sensor == null) - Log.w("SensorHelper", "WARNING: There is no GEOMAGNETIC_ROTATION_VECTOR sensor, device orientation can not be calculated"); + Logger.d(TAG, "Already started"); + return; } - // Can be null in rare cases on devices without magnetic sensors. - mRotationVectorSensor = sensor; + + mRotationVectorSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR); + if (mRotationVectorSensor == null) + { + Logger.w(TAG, "There is no ROTATION_VECTOR sensor, requesting GEOMAGNETIC_ROTATION_VECTOR"); + mRotationVectorSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR); + if (mRotationVectorSensor == null) + { + // Can be null in rare cases on devices without magnetic sensors. + Logger.w(TAG, "There is no GEOMAGNETIC_ROTATION_VECTOR sensor, device orientation can not be calculated"); + return; + } + } + + Logger.d(TAG); + mSensorManager.registerListener(this, mRotationVectorSensor, SensorManager.SENSOR_DELAY_UI); } - void start() + public void stop() { - if (mRotationVectorSensor != null) - mSensorManager.registerListener(this, mRotationVectorSensor, SensorManager.SENSOR_DELAY_UI); - } + if (mRotationVectorSensor == null) + return; + Logger.d(TAG); - void stop() - { - if (mRotationVectorSensor != null) - mSensorManager.unregisterListener(this); + mSensorManager.unregisterListener(this); + mRotationVectorSensor = null; } } diff --git a/android/app/src/main/java/app/organicmaps/location/SensorListener.java b/android/app/src/main/java/app/organicmaps/location/SensorListener.java new file mode 100644 index 0000000000..92350acd36 --- /dev/null +++ b/android/app/src/main/java/app/organicmaps/location/SensorListener.java @@ -0,0 +1,16 @@ +package app.organicmaps.location; + +public interface SensorListener +{ + void onCompassUpdated(double north); + + default void onCompassCalibrationRecommended() + { + // No op. + } + + default void onCompassCalibrationRequired() + { + // No op. + } +} diff --git a/android/app/src/main/java/app/organicmaps/widget/placepage/DirectionFragment.java b/android/app/src/main/java/app/organicmaps/widget/placepage/DirectionFragment.java index ddc994d6e9..6df564ab2f 100644 --- a/android/app/src/main/java/app/organicmaps/widget/placepage/DirectionFragment.java +++ b/android/app/src/main/java/app/organicmaps/widget/placepage/DirectionFragment.java @@ -18,12 +18,14 @@ import app.organicmaps.bookmarks.data.DistanceAndAzimut; import app.organicmaps.bookmarks.data.MapObject; import app.organicmaps.location.LocationHelper; import app.organicmaps.location.LocationListener; +import app.organicmaps.location.SensorHelper; +import app.organicmaps.location.SensorListener; import app.organicmaps.widget.ArrowView; import app.organicmaps.util.UiUtils; import app.organicmaps.util.Utils; public class DirectionFragment extends BaseMwmDialogFragment - implements LocationListener + implements LocationListener, SensorListener { private static final String EXTRA_MAP_OBJECT = "MapObject"; @@ -101,6 +103,7 @@ public class DirectionFragment extends BaseMwmDialogFragment { super.onResume(); LocationHelper.INSTANCE.addListener(this); + SensorHelper.from(requireContext()).addListener(this); refreshViews(); } @@ -109,6 +112,7 @@ public class DirectionFragment extends BaseMwmDialogFragment { super.onPause(); LocationHelper.INSTANCE.removeListener(this); + SensorHelper.from(requireContext()).removeListener(this); } @Override diff --git a/android/app/src/main/java/app/organicmaps/widget/placepage/PlacePageView.java b/android/app/src/main/java/app/organicmaps/widget/placepage/PlacePageView.java index bcba9e3815..fa511acccf 100644 --- a/android/app/src/main/java/app/organicmaps/widget/placepage/PlacePageView.java +++ b/android/app/src/main/java/app/organicmaps/widget/placepage/PlacePageView.java @@ -36,6 +36,8 @@ import app.organicmaps.downloader.MapManager; import app.organicmaps.editor.Editor; import app.organicmaps.location.LocationHelper; import app.organicmaps.location.LocationListener; +import app.organicmaps.location.SensorHelper; +import app.organicmaps.location.SensorListener; import app.organicmaps.routing.RoutingController; import app.organicmaps.util.SharingUtils; import app.organicmaps.util.StringUtils; @@ -52,7 +54,6 @@ import com.google.android.material.button.MaterialButton; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Objects; import static android.view.View.GONE; import static android.view.View.VISIBLE; @@ -60,6 +61,7 @@ import static android.view.View.VISIBLE; public class PlacePageView extends Fragment implements View.OnClickListener, View.OnLongClickListener, LocationListener, + SensorListener, Observer { @@ -257,6 +259,7 @@ public class PlacePageView extends Fragment implements View.OnClickListener, super.onStart(); mViewModel.getMapObject().observe(requireActivity(), this); LocationHelper.INSTANCE.addListener(this); + SensorHelper.from(requireContext()).addListener(this); } @Override @@ -265,6 +268,7 @@ public class PlacePageView extends Fragment implements View.OnClickListener, super.onStop(); mViewModel.getMapObject().removeObserver(this); LocationHelper.INSTANCE.removeListener(this); + SensorHelper.from(requireContext()).removeListener(this); detachCountry(); }