Page MenuHomeGitPull.it

D238.1778741519.diff
No OneTemporary

Authored By
Unknown
Size
43 KB
Referenced Files
None
Subscribers
None

D238.1778741519.diff

diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/GeneralMapLibreFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/GeneralMapLibreFragment.kt
--- a/app/src/main/java/it/reyboz/bustorino/fragments/GeneralMapLibreFragment.kt
+++ b/app/src/main/java/it/reyboz/bustorino/fragments/GeneralMapLibreFragment.kt
@@ -120,8 +120,9 @@
protected lateinit var locationProvider: FusedNativeLocationProvider
protected var shownToastNoPosition = false
+ private var locationEnabledOnDevice = true
-
+ //TODO ACTIVATE THIS
private val preferenceChangeListener = SharedPreferences.OnSharedPreferenceChangeListener(){ pref, key ->
/*when(key){
SettingsFragment.LIBREMAP_STYLE_PREF_KEY -> reloadMap()
@@ -217,6 +218,7 @@
//remove this
locationEngine?.removeLocationUpdates(this)
}
+
}
override fun onFailure(exception: Exception) {
@@ -224,6 +226,15 @@
}
}
+ protected val deviceLocationStatusListener = FusedNativeLocationProvider.LocationStatusListener { isEnabled ->
+ mapStateViewModel.locationDeviceEnabled.value = isEnabled
+ if(locationEnabledOnDevice && !isEnabled && locationInitialized) {
+ warnLocationNotEnabledOnDevice()
+ //setMapLocationEnabled(false)
+ }
+ locationEnabledOnDevice = isEnabled
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -288,11 +299,22 @@
super.onDestroy()
}
+ override fun onPause() {
+ super.onPause()
+ }
+
override fun onDestroyView() {
bottomLayout = null
+ locationProvider.removeListener(deviceLocationStatusListener)
super.onDestroyView()
}
+ protected fun warnLocationNotEnabledOnDevice(){
+ context?.let{
+ Toast.makeText(it,R.string.enable_location_message,Toast.LENGTH_SHORT).show()
+ }
+ }
+
protected fun reloadMap(){
/*map?.let {
Log.d("GeneralMapFragment", "RELOADING MAP")
@@ -320,63 +342,6 @@
} else throw RuntimeException("$context must implement CommonFragmentListener")
}
- /*
- protected fun restoreMapStateFromBundle(bundle: Bundle): Boolean{
- val nullDouble = -10_000.0
- var boundsRestored =false
- val latCenter = bundle.getDouble("center_map_lat", nullDouble)
- val lonCenter = bundle.getDouble("center_map_lon",nullDouble)
- val zoom = bundle.getDouble("map_zoom", nullDouble)
- val bearing = bundle.getDouble("map_bearing", nullDouble)
- val tilt = bundle.getDouble("map_tilt", nullDouble)
- if(lonCenter!=nullDouble &&latCenter!=nullDouble) map?.let {
- val center = LatLng(latCenter, lonCenter)
- val newPos = CameraPosition.Builder().target(center)
- if(zoom>0) newPos.zoom(zoom)
- if(bearing!=nullDouble) newPos.bearing(bearing)
- if(tilt != nullDouble) newPos.tilt(tilt)
- it.cameraPosition=newPos.build()
-
- Log.d(DEBUG_TAG, "Restored map state from Bundle, center: $center, zoom: $zoom, bearing $bearing, tilt $tilt")
- boundsRestored =true
- } else{
- Log.d(DEBUG_TAG, "Not restoring map state, center: $latCenter,$lonCenter; zoom: $zoom, bearing: $bearing, tilt $tilt")
- }
- val mStop = bundle.getBundle("shown_stop")?.let {
- Stop.fromBundle(it)
- }
- mStop?.let { openStopInBottomSheet(it) }
- return boundsRestored
- }
-
- protected fun saveMapStateBeforePause(bundle: Bundle){
- map?.let {
- val newBbox = it.projection.visibleRegion.latLngBounds
-
-
- val cp = it.cameraPosition
- bundle.putDouble("center_map_lat", newBbox.center.latitude)
- bundle.putDouble("center_map_lon", newBbox.center.longitude)
- it.cameraPosition.zoom.let { z-> bundle.putDouble("map_zoom",z) }
- bundle.putDouble("map_bearing",cp.bearing)
- bundle.putDouble("map_tilt", cp.tilt)
-
- val locationComponent = it.locationComponent
- bundle.putBoolean(KEY_LOCATION_ENABLED,locationComponent.isLocationComponentEnabled)
- bundle.putParcelable("last_location", locationComponent.lastKnownLocation)
- }
- shownStopInBottomSheet?.let {
- bundle.putBundle("shown_stop", it.toBundle())
- }
- }
-
- protected fun saveMapStateInBundle(): Bundle {
- val b = Bundle()
- saveMapStateBeforePause(b)
- return b
- }
-
- */
protected fun stopToGeoJsonFeature(s: Stop): Feature{
return Feature.fromGeometry(
@@ -477,6 +442,9 @@
if(locationComponent.isLocationComponentEnabled !=enabled)
locationComponent.isLocationComponentEnabled= enabled
changed = true}
+ Log.d(DEBUG_TAG, "Asked to set location component enabled: $enabled, changed: $changed")
+ mapStateViewModel.locationUserActive.value = enabled
+
return changed
}
@@ -492,21 +460,24 @@
locationComponent = map.locationComponent
locationProvider = FusedNativeLocationProvider(context)
+ locationProvider.addListener(deviceLocationStatusListener)
locationEngine = MapLibreLocationEngine(locationProvider)
val options = LocationComponentActivationOptions.builder(context, style)
.useDefaultLocationEngine(false)
.locationEngine(locationEngine)
.build()
locationComponent.activateLocationComponent(options)
- //locationComponent.cameraMode = CameraMode.TRACKING
- //locationComponent.renderMode = RenderMode.COMPASS
- locationInitialized = true
+
if(BuildConfig.DEBUG) Log.d(DEBUG_TAG, "Requesting location updates")
locationEngine!!.requestLocationUpdates(LocationEngineRequest.Builder(500).setDisplacement(20.0f).build(),
mapLibreLocationCallback, null)
- // signal to show user location icon as active
- mapStateViewModel.locationActive.value = true
- setLocationComponentEnabled(true)
+
+ if(!locationEnabledOnDevice){
+ warnLocationNotEnabledOnDevice()
+ }else {
+ setLocationComponentEnabled(true)
+ }
+ locationInitialized = true
onMapLocationComponentInitialized()
}
}
@@ -994,12 +965,14 @@
val context = context ?: return
if(enabled) {
setMapLocationEnabled(false)
- onMapLocationEnabled(false)
}
- else if(deviceHasGpsProvider()) {
+ else if(deviceHasLocationProvider()) {
if(Permissions.bothLocationPermissionsGranted(context)){
- setMapLocationEnabled(true)
- onMapLocationEnabled(true)
+ if(!locationEnabledOnDevice){
+ warnLocationNotEnabledOnDevice()
+ } else{
+ setMapLocationEnabled(true)
+ }
} else{
Log.d(DEBUG_TAG, "Requesting permissions to show location")
Permissions.getInstance(context).checkRequestLocationPermissions(requireActivity(), positionRequestResponder)
@@ -1012,15 +985,20 @@
}
+ /**
+ * Set the map location component enabled
+ */
@SuppressLint("MissingPermission")
protected fun setMapLocationEnabled(enabled: Boolean){
+ Log.d(DEBUG_TAG, "Setting map location enabled: $enabled")
map?.locationComponent?.isLocationComponentEnabled = enabled
//map?.cameraPosition =
- mapStateViewModel.locationActive.value = enabled
+ mapStateViewModel.locationUserActive.value = enabled
+ onMapLocationEnabled(enabled)
}
protected fun checkInitMapLocation(mapReady: MapLibreMap,style: Style, context: Context) {
//enable location
- val hasGps = deviceHasGpsProvider()
+ val hasGps = deviceHasLocationProvider()
val permissions = Permissions.getInstance(context)
if(hasGps) {
if (Permissions.bothLocationPermissionsGranted(context)) {
@@ -1031,11 +1009,9 @@
activity?.let{
req = permissions.checkRequestLocationPermissions(it, positionRequestResponder)
}
- //setLocationIconEnabled(false)
- //setFollowingUser(false)
+
if(!req) {
setMapLocationEnabled(false)
- onMapLocationEnabled(false)
}
}
@@ -1061,9 +1037,9 @@
return bottomSheetBehavior.state == BottomSheetBehavior.STATE_EXPANDED
}
- protected fun deviceHasGpsProvider(): Boolean{
+ protected fun deviceHasLocationProvider(): Boolean{
val locManager = requireContext().getSystemService(LOCATION_SERVICE) as LocationManager
- return locManager.allProviders.contains(LocationManager.GPS_PROVIDER)
+ return locManager.allProviders.size > 0
}
/**
diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/LinesDetailFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/LinesDetailFragment.kt
--- a/app/src/main/java/it/reyboz/bustorino/fragments/LinesDetailFragment.kt
+++ b/app/src/main/java/it/reyboz/bustorino/fragments/LinesDetailFragment.kt
@@ -351,7 +351,7 @@
descripTextView.text = route.longName
descripTextView.visibility = View.VISIBLE
}
- mapStateViewModel.locationActive.observe(viewLifecycleOwner) {
+ mapStateViewModel.locationUserActive.observe(viewLifecycleOwner) {
setLocationIconEnabled(it)
}
// enable info button if there are alerts on the line
@@ -507,7 +507,7 @@
true
}
if(!newStatus) setLocationComponentEnabled(newStatus)
- mapStateViewModel.locationActive.value = newStatus
+ mapStateViewModel.locationUserActive.value = newStatus
}
}
diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/MainScreenFragment.java b/app/src/main/java/it/reyboz/bustorino/fragments/MainScreenFragment.java
--- a/app/src/main/java/it/reyboz/bustorino/fragments/MainScreenFragment.java
+++ b/app/src/main/java/it/reyboz/bustorino/fragments/MainScreenFragment.java
@@ -173,34 +173,34 @@
boolean locationPermissionGranted, locationPermissionAsked = false;
AppLocationManager locationManager;
private final ActivityResultLauncher<String[]> requestPermissionLauncher =
- registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
+ registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<>() {
@Override
public void onActivityResult(Map<String, Boolean> result) {
- if(result==null) return;
+ if (result == null) return;
- if(result.get(Manifest.permission.ACCESS_COARSE_LOCATION) == null ||
+ if (result.get(Manifest.permission.ACCESS_COARSE_LOCATION) == null ||
result.get(Manifest.permission.ACCESS_FINE_LOCATION) == null)
return;
- Log.d(DEBUG_TAG, "Permissions for location are: "+result);
- if(Boolean.TRUE.equals(result.get(Manifest.permission.ACCESS_COARSE_LOCATION))
- || Boolean.TRUE.equals(result.get(Manifest.permission.ACCESS_FINE_LOCATION))){
+ Log.d(DEBUG_TAG, "Permissions for location are: " + result);
+ if (Boolean.TRUE.equals(result.get(Manifest.permission.ACCESS_COARSE_LOCATION))
+ || Boolean.TRUE.equals(result.get(Manifest.permission.ACCESS_FINE_LOCATION))) {
locationPermissionGranted = true;
Log.w(DEBUG_TAG, "Starting position");
- if (mListener!= null && getContext()!=null){
- if (locationManager==null)
+ if (mListener != null && getContext() != null) {
+ if (locationManager == null)
locationManager = AppLocationManager.getInstance(getContext());
locationManager.addLocationRequestFor(requester);
}
// show nearby fragment
//showNearbyStopsFragment();
Log.d(DEBUG_TAG, "We have location permission");
- if(pendingNearbyStopsFragmentRequest){
+ if (pendingNearbyStopsFragmentRequest) {
showNearbyFragmentIfPossible();
pendingNearbyStopsFragmentRequest = false;
}
}
- if(pendingNearbyStopsFragmentRequest) pendingNearbyStopsFragmentRequest =false;
+ if (pendingNearbyStopsFragmentRequest) pendingNearbyStopsFragmentRequest = false;
}
});
diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/MapLibreFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/MapLibreFragment.kt
--- a/app/src/main/java/it/reyboz/bustorino/fragments/MapLibreFragment.kt
+++ b/app/src/main/java/it/reyboz/bustorino/fragments/MapLibreFragment.kt
@@ -36,13 +36,13 @@
import androidx.preference.PreferenceManager
import androidx.room.concurrent.AtomicBoolean
import com.google.android.material.bottomsheet.BottomSheetBehavior
-import it.reyboz.bustorino.BuildConfig
import it.reyboz.bustorino.R
import it.reyboz.bustorino.backend.Stop
import it.reyboz.bustorino.backend.gtfs.LivePositionUpdate
import it.reyboz.bustorino.backend.mato.MQTTMatoClient
import it.reyboz.bustorino.data.PreferencesHolder
import it.reyboz.bustorino.data.gtfs.TripAndPatternWithStops
+import it.reyboz.bustorino.map.MapLibreLocationEngine
import it.reyboz.bustorino.map.MapLibreStyles
import it.reyboz.bustorino.viewmodels.StopsMapViewModel
import org.maplibre.android.camera.CameraPosition
@@ -50,7 +50,6 @@
import org.maplibre.android.geometry.LatLng
import org.maplibre.android.geometry.LatLngBounds
import org.maplibre.android.location.engine.LocationEngineCallback
-import org.maplibre.android.location.engine.LocationEngineRequest
import org.maplibre.android.location.engine.LocationEngineResult
import org.maplibre.android.location.modes.CameraMode
import org.maplibre.android.location.modes.RenderMode
@@ -234,7 +233,8 @@
usingMQTTPositions = useMQTT
}
- mapStateViewModel.locationActive.observe(viewLifecycleOwner){ setLocationIconEnabled(it)}
+ mapStateViewModel.locationUserActive.observe(viewLifecycleOwner){
+ setLocationIconEnabled(it)}
mapStateViewModel.followingUserPosition.observe(viewLifecycleOwner){ updateFollowingIcon(it)}
Log.d(DEBUG_TAG, "Fragment View Created!")
@@ -622,7 +622,10 @@
}
override fun onFailure(p0: java.lang.Exception) {
- Log.e(DEBUG_TAG, "Failed to get the last location", p0)
+ if( p0 is MapLibreLocationEngine.NoLocationException)
+ Log.d(DEBUG_TAG, "Cannot find location: ${p0.message}")
+ else
+ Log.w(DEBUG_TAG, "Failed to get the last location, error: ${p0.message}",)
}
})
@@ -653,7 +656,7 @@
}
setLocationComponentEnabled(false)
//Update UI Status
- mapStateViewModel.locationActive.value = false
+ mapStateViewModel.locationUserActive.value = false
mapStateViewModel.followingUserPosition.value = false
} else {
map?.apply {
@@ -665,7 +668,7 @@
)
setLocationComponentEnabled(true)
locationComponent.cameraMode = CameraMode.TRACKING
- mapStateViewModel.locationActive.value = true
+ mapStateViewModel.locationUserActive.value = true
}
setFollowUserLocation(true)
}
diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/NearbyStopsFragment.java b/app/src/main/java/it/reyboz/bustorino/fragments/NearbyStopsFragment.java
--- a/app/src/main/java/it/reyboz/bustorino/fragments/NearbyStopsFragment.java
+++ b/app/src/main/java/it/reyboz/bustorino/fragments/NearbyStopsFragment.java
@@ -22,13 +22,10 @@
import android.content.SharedPreferences;
import android.location.Location;
-import android.location.LocationManager;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.core.location.LocationListenerCompat;
-import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.core.util.Pair;
@@ -51,6 +48,7 @@
import it.reyboz.bustorino.data.DatabaseUpdate;
import it.reyboz.bustorino.adapters.SquareStopAdapter;
import it.reyboz.bustorino.middleware.AutoFitGridLayoutManager;
+import it.reyboz.bustorino.middleware.FusedNativeLocationProvider;
import it.reyboz.bustorino.util.Permissions;
import it.reyboz.bustorino.util.StopSorterByDistance;
import it.reyboz.bustorino.viewmodels.NearbyStopsViewModel;
@@ -58,7 +56,13 @@
import java.util.*;
-public class NearbyStopsFragment extends Fragment {
+public class NearbyStopsFragment extends ScreenBaseFragment {
+
+ @Nullable
+ @Override
+ public View getBaseViewForSnackBar() {
+ return null;
+ }
public enum FragType{
STOPS(1), ARRIVALS(2);
@@ -78,7 +82,6 @@
private enum LocationShowingStatus {SEARCHING, FIRST_FIX, DISABLED, NO_PERMISSION}
private FragmentListenerMain mListener;
- private FragmentLocationListener fragmentLocationListener;
private final static String DEBUG_TAG = "NearbyStopsFragment";
private final static String FRAGMENT_TYPE_KEY = "FragmentType";
@@ -104,18 +107,47 @@
private Integer MAX_DISTANCE = -3;
private int MIN_NUM_STOPS = -1;
- private int TIME_INTERVAL_REQUESTS = -1;
- private LocationManager locManager;
//These are useful for the case of nearby arrivals
private NearbyArrivalsDownloader arrivalsManager = null;
private ArrivalsStopAdapter arrivalsStopAdapter = null;
private ArrayList<Stop> currentNearbyStops = new ArrayList<>();
- private NearbyArrivalsDownloader nearbyArrivalsDownloader;
private LocationShowingStatus showingStatus = LocationShowingStatus.NO_PERMISSION;
+ private final FusedNativeLocationProvider.LocationUpdateListener locationUpdateListener = new FusedNativeLocationProvider.LocationUpdateListener() {
+ @Override
+ public void onLocationUpdate(@NotNull Location location) {
+ updateLocationViewModel(location);
+ }
+
+ @Override
+ public void onFusedStatusChanged(boolean isEnabled) {
+ Log.d(DEBUG_TAG, "Location provider is enabled: " + isEnabled);
+ if(isEnabled){
+ setShowingStatus(LocationShowingStatus.SEARCHING);
+ } else{
+ setShowingStatus(LocationShowingStatus.DISABLED);
+ }
+ }
+ };
+ private final FusedNativeLocationProvider.Options locationOptionsArrivals = new FusedNativeLocationProvider.Options(5*1000L, 50f),
+ locationOptionsStops = new FusedNativeLocationProvider.Options(1000L, 5f);;
+
+
+
+ /*
+ TODO: we do not request the permission in this fragment, only showing it when we have the location. Request position if this changes.
+ private final ActivityResultLauncher<String[]> permissionsResultLauncher = getPositionRequestLauncher(
+ granted ->{
+
+ }
+ );
+ */
+ private FusedNativeLocationProvider locationProvider = null;
+
+
private final NearbyArrivalsDownloader.ArrivalsListener arrivalsListener = new NearbyArrivalsDownloader.ArrivalsListener() {
@Override
public void setProgress(int completedRequests, int pendingRequests) {
@@ -171,16 +203,15 @@
if (getArguments() != null) {
setFragmentType(FragType.fromNum(getArguments().getInt(FRAGMENT_TYPE_KEY)));
}
- locManager = (LocationManager) requireContext().getSystemService(Context.LOCATION_SERVICE);
- fragmentLocationListener = new FragmentLocationListener();
+ //locManager = (LocationManager) requireContext().getSystemService(Context.LOCATION_SERVICE);
+ //fragmentLocationListener = new FragmentLocationListener();
if (getContext()!=null) {
//globalSharedPref = getContext().getSharedPreferences(getString(R.string.mainSharedPreferences), Context.MODE_PRIVATE);
//globalSharedPref.registerOnSharedPreferenceChangeListener(preferenceChangeListener);
}
- nearbyArrivalsDownloader = new NearbyArrivalsDownloader(getContext().getApplicationContext(), arrivalsListener);
-
-
+ //NearbyArrivalsDownloader nearbyArrivalsDownloader = new NearbyArrivalsDownloader(getContext().getApplicationContext(), arrivalsListener);
+ locationProvider = new FusedNativeLocationProvider(requireContext());
}
@Override
@@ -216,15 +247,19 @@
}
WorkInfo wi = workInfos.get(0);
- if (wi.getState() == WorkInfo.State.RUNNING && fragmentLocationListener.isRegistered) {
- locManager.removeUpdates(fragmentLocationListener);
- fragmentLocationListener.isRegistered = true;
+ if (wi.getState() == WorkInfo.State.RUNNING && locationProvider.isRunning()) {
+ locationProvider.stopUpdates();
viewModel.setDBUpdateRunning(true);
} else{
//start the request
- if(!fragmentLocationListener.isRegistered){
- requestLocationUpdates();
+ if(Permissions.bothLocationPermissionsGranted(requireContext())) {
+ if(!locationProvider.isRunning()){
+ startLocationUpdatesByType();
+ }
+ } else{
+ setShowingStatus(LocationShowingStatus.NO_PERMISSION);
}
+
viewModel.setDBUpdateRunning(false);
//actually restart request
}
@@ -255,6 +290,9 @@
setShowingStatus(LocationShowingStatus.NO_PERMISSION);
}
+ //add location listener
+ locationProvider.addListener(locationUpdateListener);
+
return root;
}
@@ -262,17 +300,21 @@
@SuppressLint("MissingPermission")
private boolean requestLocationUpdates(){
if(Permissions.anyLocationPermissionsGranted(requireContext())) {
- if (locManager.getAllProviders().contains(LocationManager.GPS_PROVIDER)) {
- locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
- 3000, 10.0f, fragmentLocationListener
- );
- fragmentLocationListener.isRegistered = true;
- }
- fragmentLocationListener.isRegistered = false;
+ startLocationUpdatesByType();
return true;
} else return false;
}
+ /**
+ * Internal bit used to start location updates
+ */
+ private void startLocationUpdatesByType(){
+ switch (fragment_type) {
+ case STOPS: locationProvider.startUpdates(locationOptionsStops); break;
+ case ARRIVALS: locationProvider.startUpdates(locationOptionsArrivals); break;
+ }
+ }
+
/**
@@ -280,8 +322,9 @@
* @param type the type, TYPE_ARRIVALS or TYPE_STOPS
*/
private void setFragmentType(FragType type){
+ boolean isChanged = fragment_type != type;
this.fragment_type = type;
- switch(type){
+ /*switch(type){
case ARRIVALS:
TIME_INTERVAL_REQUESTS = 5*1000;
break;
@@ -289,11 +332,35 @@
TIME_INTERVAL_REQUESTS = 1000;
}
+
+ */
+ if(isChanged){
+ startLocationUpdatesByType();
+ setShowingStatus(LocationShowingStatus.SEARCHING);
+ }
+ }
+ /**
+ * Set the location in the view model if it is good
+ * @param location new location
+ */
+ private void updateLocationViewModel(@NonNull Location location, float accuracy){
+ if(viewModel==null) {
+ return;
+ }
+ if(location.getAccuracy()<accuracy) {
+ lastPosition = new GPSPoint(location.getLatitude(), location.getLongitude());
+ //viewModel.requestStopsAtDistance(location.getLatitude(), location.getLongitude(), distance, true);
+ viewModel.setLastLocation(location);
+ }
+ }
+ private void updateLocationViewModel(@NonNull Location location){
+ updateLocationViewModel(location, 150);
}
+
private void setShowingStatus(@NonNull LocationShowingStatus newStatus){
+ if(BuildConfig.DEBUG)
+ Log.d(DEBUG_TAG, "Asked to set showing status : " + newStatus);
if(newStatus == showingStatus){
- if(BuildConfig.DEBUG)
- Log.d(DEBUG_TAG, "Asked to set new displaying status but it's the same");
return;
}
switch (newStatus){
@@ -314,7 +381,7 @@
circlingProgressBar.setVisibility(View.GONE);
loadingTextView.setVisibility(View.GONE);
}
- messageTextView.setText(R.string.enableGpsText);
+ messageTextView.setText(R.string.enable_location_message);
messageTextView.setVisibility(View.VISIBLE);
break;
case SEARCHING:
@@ -347,8 +414,6 @@
super.onPause();
gridRecyclerView.setAdapter(null);
- locManager.removeUpdates(fragmentLocationListener);
- fragmentLocationListener.isRegistered = false;
Log.d(DEBUG_TAG,"On paused called");
}
@@ -480,7 +545,6 @@
default:
}
prepareForFragmentType();
- fragmentLocationListener.lastUpdateTime = -1;
//locManager.removeLocationRequestFor(fragmentLocationListener);
//locManager.addLocationRequestFor(fragmentLocationListener);
if(lastPosition!=null) {
@@ -587,9 +651,10 @@
messageTextView.setVisibility(View.GONE);
}
- /**
+ /*
* Local locationListener, to use for the GPS
*/
+ /*
class FragmentLocationListener implements LocationListenerCompat {
private long lastUpdateTime = -1;
@@ -631,4 +696,6 @@
LocationListenerCompat.super.onStatusChanged(provider, status, extras);
}
}
+
+ */
}
diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/ScreenBaseFragment.java b/app/src/main/java/it/reyboz/bustorino/fragments/ScreenBaseFragment.java
--- a/app/src/main/java/it/reyboz/bustorino/fragments/ScreenBaseFragment.java
+++ b/app/src/main/java/it/reyboz/bustorino/fragments/ScreenBaseFragment.java
@@ -7,6 +7,7 @@
import android.content.SharedPreferences;
import android.net.Uri;
import android.provider.Settings;
+import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;
@@ -98,15 +99,19 @@
return;
final boolean coarseGranted = Boolean.TRUE.equals(result.get(Manifest.permission.ACCESS_COARSE_LOCATION));
final boolean fineGranted = Boolean.TRUE.equals(result.get(Manifest.permission.ACCESS_FINE_LOCATION));
+ if (coarseGranted != fineGranted){
+ Log.e("BusTO-ScreenBaseFragment", "the two permissions have different values, coarse "+
+ coarseGranted +", fineGranted "+fineGranted);
+ }
- listener.onPermissionResult(coarseGranted, fineGranted);
+ listener.onPermissionResult(coarseGranted || fineGranted);
}
});
}
public interface LocationRequestListener{
- void onPermissionResult(boolean isCoarseGranted, boolean isFineGranted);
+ void onPermissionResult(boolean locationGranted);
}
}
diff --git a/app/src/main/java/it/reyboz/bustorino/map/MapLibreLocationEngine.kt b/app/src/main/java/it/reyboz/bustorino/map/MapLibreLocationEngine.kt
--- a/app/src/main/java/it/reyboz/bustorino/map/MapLibreLocationEngine.kt
+++ b/app/src/main/java/it/reyboz/bustorino/map/MapLibreLocationEngine.kt
@@ -106,9 +106,13 @@
"MapLibreLocationEngine does not support PendingIntent removal."
)
}
-
class NoLocationException : Exception()
+
+
companion object {
const val DEBUG_TAG = "BusTO-MapLocationEngine"
+
+
+
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/it/reyboz/bustorino/middleware/FusedNativeLocationProvider.kt b/app/src/main/java/it/reyboz/bustorino/middleware/FusedNativeLocationProvider.kt
--- a/app/src/main/java/it/reyboz/bustorino/middleware/FusedNativeLocationProvider.kt
+++ b/app/src/main/java/it/reyboz/bustorino/middleware/FusedNativeLocationProvider.kt
@@ -9,8 +9,9 @@
import android.os.Looper
import android.util.Log
import it.reyboz.bustorino.BuildConfig
-import it.reyboz.bustorino.util.Permissions
+import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArraySet
+import java.util.concurrent.atomic.AtomicBoolean
/**
* Native Android location provider that fuses GPS_PROVIDER, NETWORK_PROVIDER
@@ -27,6 +28,12 @@
fun interface LocationUpdateListener {
fun onLocationUpdate(location: Location)
+
+ fun onFusedStatusChanged(isEnabled: Boolean) {}
+ }
+
+ fun interface LocationStatusListener {
+ fun onLocationStatusChanged(isEnabled: Boolean)
}
/**
@@ -40,13 +47,19 @@
* @param usePassive Enables PASSIVE_PROVIDER (zero consumption, opportunistic updates).
*/
data class Options(
- val minIntervalMs: Long = 500L,
+ val minIntervalMs: Long = 1000L,
val minDisplacementM: Float = 5f,
val looper: Looper? = null,
val useGps: Boolean = true,
val useNetwork: Boolean = true,
val usePassive: Boolean = true,
- )
+ ){
+ constructor(minIntervalMs: Long, minDisplacementM: Float) : this(
+ minIntervalMs = minIntervalMs,
+ minDisplacementM = minDisplacementM,
+ useGps = true
+ )
+ }
private val locationManager =
@@ -54,6 +67,7 @@
// List of registered listeners (called on the configured looper)
private val listeners = CopyOnWriteArraySet<LocationUpdateListener>()
+ private val statusListeners = CopyOnWriteArraySet<LocationStatusListener>()
// Active Android listeners, one per provider
private val activeAndroidListeners = mutableListOf<LocationListener>()
@@ -61,14 +75,15 @@
@Volatile
private var bestLocation: Location? = null
- @Volatile
- private var running = false
+ private var running = AtomicBoolean(false)
private var runningOptions = Options(500L, 5f, null, true, true, true)
- private val activeProviders = ArrayList<String>()
+ private val availableProviders = ArrayList<String>()
+
+ private var lastStatusUpdateEnabled = false
- private var havePermissions = false
+ private val providersAreEnabled = ConcurrentHashMap<String, Boolean>()
//private val removedListener = mutableSetOf<LocationUpdateListener>()
@@ -91,6 +106,12 @@
}
}
+ fun addListener(listener: LocationStatusListener) {
+ synchronized(listeners) {
+ statusListeners.add(listener)
+ }
+ }
+
/**
* Removes a previously registered listener.
*/
@@ -106,6 +127,12 @@
}
}
+ fun removeListener(listener: LocationStatusListener) {
+ synchronized(listeners) {
+ statusListeners.remove(listener)
+ }
+ }
+
/**
* Starts receiving location updates from the enabled providers.
* If already running, stops the existing providers first and restarts
@@ -114,11 +141,26 @@
* Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION.
*/
@SuppressLint("MissingPermission")
- fun startUpdates(options: Options?): Boolean {
- if (running) stopUpdates()
+ fun startUpdates(options: Options?) {
+ val wasNotRunning = running.compareAndSet(false, true)
+
+ if (!wasNotRunning) {
+ //it's already running, no need to stop
+ Log.d(DEBUG_TAG, "Requested to start updates, but provider is running")
+ if(options!=null){
+ if(runningOptions !== options){
+ Log.d(DEBUG_TAG, "Stopping and restarting")
+ //need to restart
+ stopUpdatesInternal()
+ startUpdates(options)
+ }
+ }
+ return
+ }
if (options!=null){
runningOptions = options
}
+ lastStatusUpdateEnabled = false
val selectedProviders = buildList {
if (runningOptions.useGps) add(LocationManager.GPS_PROVIDER)
if (runningOptions.useNetwork) add(LocationManager.NETWORK_PROVIDER)
@@ -128,32 +170,42 @@
val effectiveLooper = runningOptions.looper ?: Looper.getMainLooper()
selectedProviders.forEach { provider ->
- if (!locationManager.isProviderEnabled(provider)) return@forEach
+ val isEnabled = locationManager.isProviderEnabled(provider)
+ if(isEnabled) {
+ lastStatusUpdateEnabled = true
+ }
+ providersAreEnabled[provider] = isEnabled
+ //listen for location, even if the provider is not started yet
+ val locListener = object : LocationListener {
+ override fun onLocationChanged(location: Location) {
+ onReceiveLocation(location)
+ }
+
+ override fun onProviderDisabled(provider: String) {
+ super.onProviderDisabled(provider)
+ onProviderStatusChanged(provider, false)
+ }
- val locListener = LocationListener { location ->
- if (isBetterLocation(location, bestLocation)) {
- bestLocation = location
- //Log.d(DEBUG_TAG, "New best location: $bestLocation")
- notifyListeners(location)
+ override fun onProviderEnabled(provider: String) {
+ super.onProviderEnabled(provider)
+ onProviderStatusChanged(provider, true)
}
}
- //runCatching {
- locationManager.requestLocationUpdates(
- provider,
- runningOptions.minIntervalMs,
- runningOptions.minDisplacementM,
- locListener,
- effectiveLooper,
- )
- activeAndroidListeners.add(locListener)
- activeProviders.add(provider)
- //}
+ runCatching {
+ locationManager.requestLocationUpdates(
+ provider,
+ runningOptions.minIntervalMs,
+ runningOptions.minDisplacementM,
+ locListener,
+ effectiveLooper,
+ )
+ activeAndroidListeners.add(locListener)
+ availableProviders.add(provider)
+ }
}
-
- running = activeAndroidListeners.isNotEmpty()
- Log.d(DEBUG_TAG, "Started location updates, running: $running, with providers: $activeProviders")
- return running
+ notifyListenerStatus(lastStatusUpdateEnabled)
+ Log.d(DEBUG_TAG, "Started location updates, running: ${running.get()}, with providers: $availableProviders")
}
/**
@@ -162,17 +214,20 @@
* calling [startUpdates] again will resume delivering updates to them.
*/
private fun stopUpdatesInternal() {
- if(!running) //we have already done this
- return
- Log.d(DEBUG_TAG, "Actually stopping location updates, active providers: $activeProviders")
- activeAndroidListeners.forEach { listener ->
- runCatching { locationManager.removeUpdates(listener) }
+ if(running.compareAndSet(true, false)) {
+ //we have to stop updates
+ Log.d(DEBUG_TAG, "Actually stopping location updates, active providers: $availableProviders")
+ activeAndroidListeners.forEach { listener ->
+ runCatching { locationManager.removeUpdates(listener) }
+ }
+ activeAndroidListeners.clear()
+ //running = false is set by compareAndSet
+ availableProviders.clear()
}
- activeAndroidListeners.clear()
- running = false
- activeProviders.clear()
}
+ fun isRunning(): Boolean = running.get()
+
/**
* Returns the best known location cached by the enabled providers,
* without starting continuous updates.
@@ -208,6 +263,36 @@
//synchronized(listeners) {
listeners.forEach { it.onLocationUpdate(location) }
}
+ private fun notifyListenerStatus(enabled: Boolean){
+ Log.d(DEBUG_TAG, "Notifying listeners, the position is enabled: $enabled")
+ listeners.forEach { it.onFusedStatusChanged(enabled) }
+ statusListeners.forEach { it.onLocationStatusChanged(enabled) }
+ }
+
+ private fun onReceiveLocation(location: Location) {
+ if (isBetterLocation(location, bestLocation)) {
+ bestLocation = location
+ //Log.d(DEBUG_TAG, "New best location: $bestLocation")
+ notifyListeners(location)
+ }
+ }
+
+ private fun onProviderStatusChanged(provider: String,enabled: Boolean) {
+ providersAreEnabled.put(provider, enabled)
+ val actu = providersAreEnabled.reduceValues(1, Boolean::or)
+ if (actu!=null && actu!=lastStatusUpdateEnabled){
+ lastStatusUpdateEnabled = actu
+ notifyListenerStatus(actu)
+ }
+
+ }
+
+ fun isLocationEnabled(): Boolean {
+ val probValue = providersAreEnabled.reduceValues(1, Boolean::or)
+ return probValue ?: true
+ }
+
+
/**
* Public call for stopping the updates
diff --git a/app/src/main/java/it/reyboz/bustorino/viewmodels/MapStateViewModel.kt b/app/src/main/java/it/reyboz/bustorino/viewmodels/MapStateViewModel.kt
--- a/app/src/main/java/it/reyboz/bustorino/viewmodels/MapStateViewModel.kt
+++ b/app/src/main/java/it/reyboz/bustorino/viewmodels/MapStateViewModel.kt
@@ -6,7 +6,6 @@
import it.reyboz.bustorino.map.MapCameraState
import org.maplibre.android.camera.CameraPosition
import org.maplibre.android.geometry.LatLng
-import org.maplibre.android.geometry.LatLngBounds
import org.maplibre.android.maps.MapLibreMap
class MapStateViewModel : ViewModel() {
@@ -36,8 +35,9 @@
var locationToShow: Location? = null
- val locationActive = MutableLiveData(false)
+ val locationUserActive = MutableLiveData(false)
val followingUserPosition = MutableLiveData(false)
+ val locationDeviceEnabled = MutableLiveData(false)
companion object{
fun restoreMapState(map: MapLibreMap, savedCameraState: MapCameraState?): Boolean {
diff --git a/app/src/main/res/layout/fragment_nearby_stops.xml b/app/src/main/res/layout/fragment_nearby_stops.xml
--- a/app/src/main/res/layout/fragment_nearby_stops.xml
+++ b/app/src/main/res/layout/fragment_nearby_stops.xml
@@ -73,7 +73,7 @@
android:layout_centerHorizontal="true"
/>
<TextView
- android:text="@string/enableGpsText"
+ android:text="@string/enable_location_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="@+id/messageTextView"
android:visibility="gone"
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -62,7 +62,7 @@
<string name="enable_position_message_map">Autorisez l\'accès à la localisation pour l\'afficher sur la carte</string>
<string name="database_update_msg_inapp">Mise à jour de la base de données en cours…</string>
<string name="settings_reset_database">Lancer la mise à jour manuelle de la base de données</string>
- <string name="enableGpsText">Veuillez activer la localisation sur l\'appareil</string>
+ <string name="enable_location_message">Veuillez activer la localisation sur l\'appareil</string>
<string name="database_update_msg_notif">Mise à jour de la base de données</string>
<string name="database_update_req">Forcer la mise à jour de la base de données</string>
<string name="arrivals_card_at_the_stop">à l\'arrêt</string>
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -138,7 +138,7 @@
<string name="settings_reset_database">Comincia aggiornamento manuale del database</string>
<string name="enable_position_message_map">Consenti l\'accesso alla posizione per mostrarla sulla mappa</string>
<string name="enable_position_message_nearby">Consenti l\'accesso alla posizione per mostrare le fermate vicine</string>
- <string name="enableGpsText">Abilitare il GPS</string>
+ <string name="enable_location_message">Abilitare la posizione sul dispositivo</string>
<string name="bus_arriving_at">arriva alle</string>
<string name="arrivals_card_at_the_stop">alla fermata</string>
<string name="show_arrivals">Mostra arrivi</string>
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -83,7 +83,7 @@
<string name="settings_group_general">Algemene instellingen</string>
<string name="enable_position_message_map">Toegang tot locatie toestaan om te laten zien op de kaart</string>
<string name="enable_position_message_nearby">Toegang tot locatie toestaan om haltes in de buurt te weergeven</string>
- <string name="enableGpsText">Schakel aub de locatie in op het apparaat</string>
+ <string name="enable_location_message">Schakel aub de locatie in op het apparaat</string>
<string name="database_update_msg_inapp">Database update gaande…</string>
<string name="database_update_msg_notif">Database aan het updaten</string>
<string name="database_update_req">Forceer database update</string>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -174,7 +174,7 @@
<string name="enable_position_message_map">Allow access to location to show it on the map</string>
<string name="enable_position_message_nearby">Allow access to location to show stops nearby</string>
- <string name="enableGpsText">Please enable location on the device</string>
+ <string name="enable_location_message">Please enable location on the device</string>
<string name="no_gps_on_device">No GPS receiver found on the device!</string>
<string name="database_update_msg_inapp">Database update in progress&#8230;</string>
<string name="database_update_msg_notif">Updating the database</string>

File Metadata

Mime Type
text/plain
Expires
Thu, May 14, 08:51 (20 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1898045
Default Alt Text
D238.1778741519.diff (43 KB)

Event Timeline