Page Menu
Home
GitPull.it
Search
Configure Global Search
Log In
Files
F13304292
D238.1778679528.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Authored By
Unknown
Size
43 KB
Referenced Files
None
Subscribers
None
D238.1778679528.diff
View Options
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…</string>
<string name="database_update_msg_notif">Updating the database</string>
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, May 13, 15:38 (3 h, 34 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1898045
Default Alt Text
D238.1778679528.diff (43 KB)
Attached To
Mode
D238: Use new location engine on Nearby, consider case when GPS is disabled on device
Attached
Detach File
Event Timeline