Changeset View
Changeset View
Standalone View
Standalone View
src/it/reyboz/bustorino/fragments/MapFragment.java
package it.reyboz.bustorino.fragments; | package it.reyboz.bustorino.fragments; | ||||
import android.Manifest; | import android.Manifest; | ||||
import android.annotation.SuppressLint; | |||||
import android.content.Context; | import android.content.Context; | ||||
import android.content.pm.PackageManager; | |||||
import android.location.Location; | import android.location.Location; | ||||
import android.location.LocationManager; | import android.location.LocationManager; | ||||
import android.os.AsyncTask; | import android.os.AsyncTask; | ||||
import android.os.Bundle; | import android.os.Bundle; | ||||
import android.util.Log; | import android.util.Log; | ||||
import android.view.LayoutInflater; | import android.view.LayoutInflater; | ||||
import android.view.View; | import android.view.View; | ||||
import android.view.ViewGroup; | import android.view.ViewGroup; | ||||
import android.widget.ImageButton; | import android.widget.ImageButton; | ||||
import android.widget.Toast; | |||||
import androidx.activity.result.ActivityResultCallback; | |||||
import androidx.activity.result.ActivityResultLauncher; | |||||
import androidx.activity.result.contract.ActivityResultContracts; | |||||
import androidx.annotation.NonNull; | import androidx.annotation.NonNull; | ||||
import androidx.annotation.Nullable; | import androidx.annotation.Nullable; | ||||
import androidx.core.app.ActivityCompat; | |||||
import androidx.core.content.res.ResourcesCompat; | import androidx.core.content.res.ResourcesCompat; | ||||
import androidx.preference.PreferenceManager; | import androidx.preference.PreferenceManager; | ||||
import org.osmdroid.api.IGeoPoint; | import org.osmdroid.api.IGeoPoint; | ||||
import org.osmdroid.api.IMapController; | import org.osmdroid.api.IMapController; | ||||
import org.osmdroid.config.Configuration; | import org.osmdroid.config.Configuration; | ||||
import org.osmdroid.events.DelayedMapListener; | import org.osmdroid.events.DelayedMapListener; | ||||
import org.osmdroid.events.MapListener; | import org.osmdroid.events.MapListener; | ||||
import org.osmdroid.events.ScrollEvent; | import org.osmdroid.events.ScrollEvent; | ||||
import org.osmdroid.events.ZoomEvent; | import org.osmdroid.events.ZoomEvent; | ||||
import org.osmdroid.tileprovider.tilesource.TileSourceFactory; | import org.osmdroid.tileprovider.tilesource.TileSourceFactory; | ||||
import org.osmdroid.util.BoundingBox; | import org.osmdroid.util.BoundingBox; | ||||
import org.osmdroid.util.GeoPoint; | import org.osmdroid.util.GeoPoint; | ||||
import org.osmdroid.views.MapView; | import org.osmdroid.views.MapView; | ||||
import org.osmdroid.views.overlay.FolderOverlay; | import org.osmdroid.views.overlay.FolderOverlay; | ||||
import org.osmdroid.views.overlay.Marker; | import org.osmdroid.views.overlay.Marker; | ||||
import org.osmdroid.views.overlay.infowindow.InfoWindow; | import org.osmdroid.views.overlay.infowindow.InfoWindow; | ||||
import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider; | import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider; | ||||
import java.lang.ref.WeakReference; | import java.lang.ref.WeakReference; | ||||
import java.util.Arrays; | import java.util.Arrays; | ||||
import java.util.HashSet; | import java.util.HashSet; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | |||||
import it.reyboz.bustorino.R; | import it.reyboz.bustorino.R; | ||||
import it.reyboz.bustorino.backend.Stop; | import it.reyboz.bustorino.backend.Stop; | ||||
import it.reyboz.bustorino.data.NextGenDB; | import it.reyboz.bustorino.data.NextGenDB; | ||||
import it.reyboz.bustorino.map.CustomInfoWindow; | import it.reyboz.bustorino.map.CustomInfoWindow; | ||||
import it.reyboz.bustorino.map.LocationOverlay; | import it.reyboz.bustorino.map.LocationOverlay; | ||||
import it.reyboz.bustorino.middleware.GeneralActivity; | import it.reyboz.bustorino.middleware.GeneralActivity; | ||||
import it.reyboz.bustorino.util.Permissions; | |||||
import static it.reyboz.bustorino.util.Permissions.PERMISSION_REQUEST_POSITION; | |||||
public class MapFragment extends BaseFragment { | public class MapFragment extends BaseFragment { | ||||
private static final String TAG = "Busto-MapActivity"; | private static final String TAG = "Busto-MapActivity"; | ||||
private static final String MAP_CURRENT_ZOOM_KEY = "map-current-zoom"; | private static final String MAP_CURRENT_ZOOM_KEY = "map-current-zoom"; | ||||
private static final String MAP_CENTER_LAT_KEY = "map-center-lat"; | private static final String MAP_CENTER_LAT_KEY = "map-center-lat"; | ||||
private static final String MAP_CENTER_LON_KEY = "map-center-lon"; | private static final String MAP_CENTER_LON_KEY = "map-center-lon"; | ||||
private static final String FOLLOWING_LOCAT_KEY ="following"; | private static final String FOLLOWING_LOCAT_KEY ="following"; | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | protected final LocationOverlay.OverlayCallbacks locationCallbacks = new LocationOverlay.OverlayCallbacks() { | ||||
@Override | @Override | ||||
public void onEnableFollowMyLocation() { | public void onEnableFollowMyLocation() { | ||||
updateGUIForLocationFollowing(true); | updateGUIForLocationFollowing(true); | ||||
followingLocation=true; | followingLocation=true; | ||||
} | } | ||||
}; | }; | ||||
private final ActivityResultLauncher<String[]> positionRequestLauncher = | |||||
registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() { | |||||
@Override | |||||
@SuppressLint("MissingPermission") | |||||
public void onActivityResult(Map<String, Boolean> result) { | |||||
if(result.get(Manifest.permission.ACCESS_COARSE_LOCATION) && result.get(Manifest.permission.ACCESS_FINE_LOCATION)){ | |||||
map.getOverlays().remove(mLocationOverlay); | |||||
startLocationOverlay(true); | |||||
if(getContext()==null || getContext().getSystemService(Context.LOCATION_SERVICE)==null) | |||||
return; | |||||
LocationManager locationManager = (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE); | |||||
Location userLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); | |||||
if (userLocation != null) { | |||||
map.getController().setZoom(POSITION_FOUND_ZOOM); | |||||
GeoPoint startPoint = new GeoPoint(userLocation); | |||||
setLocationFollowing(true); | |||||
map.getController().setCenter(startPoint); | |||||
} | |||||
} | |||||
else Log.w(DEBUG_TAG,"No location permission"); | |||||
} | |||||
}); | |||||
public MapFragment() { | public MapFragment() { | ||||
} | } | ||||
public static MapFragment getInstance(){ | public static MapFragment getInstance(){ | ||||
return new MapFragment(); | return new MapFragment(); | ||||
} | } | ||||
public static MapFragment getInstance(double stopLatit, double stopLong, String stopName, String stopID){ | public static MapFragment getInstance(double stopLatit, double stopLong, String stopName, String stopID){ | ||||
MapFragment fragment= new MapFragment(); | MapFragment fragment= new MapFragment(); | ||||
Bundle args = new Bundle(); | Bundle args = new Bundle(); | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { | ||||
return true; | return true; | ||||
} | } | ||||
})); | })); | ||||
btCenterMap.setOnClickListener(v -> { | btCenterMap.setOnClickListener(v -> { | ||||
//Log.i(TAG, "centerMap clicked "); | //Log.i(TAG, "centerMap clicked "); | ||||
if(Permissions.locationPermissionGranted(getContext())) { | |||||
final GeoPoint myPosition = mLocationOverlay.getMyLocation(); | final GeoPoint myPosition = mLocationOverlay.getMyLocation(); | ||||
map.getController().animateTo(myPosition); | map.getController().animateTo(myPosition); | ||||
} else | |||||
Toast.makeText(getContext(), R.string.enable_position_message_map, Toast.LENGTH_SHORT) | |||||
.show(); | |||||
}); | }); | ||||
btFollowMe.setOnClickListener(v -> { | btFollowMe.setOnClickListener(v -> { | ||||
//Log.i(TAG, "btFollowMe clicked "); | //Log.i(TAG, "btFollowMe clicked "); | ||||
switchLocationFollowing(!followingLocation); | if(Permissions.locationPermissionGranted(getContext())) | ||||
setLocationFollowing(!followingLocation); | |||||
else | |||||
Toast.makeText(getContext(), R.string.enable_position_message_map, Toast.LENGTH_SHORT) | |||||
.show(); | |||||
}); | }); | ||||
return root; | return root; | ||||
} | } | ||||
@Override | @Override | ||||
public void onAttach(@NonNull Context context) { | public void onAttach(@NonNull Context context) { | ||||
super.onAttach(context); | super.onAttach(context); | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | public class MapFragment extends BaseFragment { | ||||
} | } | ||||
//own methods | //own methods | ||||
/** | /** | ||||
* Switch following the location on and off | * Switch following the location on and off | ||||
* @param value true if we want to follow location | * @param value true if we want to follow location | ||||
*/ | */ | ||||
public void switchLocationFollowing(Boolean value){ | public void setLocationFollowing(Boolean value){ | ||||
followingLocation = value; | followingLocation = value; | ||||
if(mLocationOverlay==null || getContext() == null) | |||||
//nothing else to do | |||||
return; | |||||
if (value){ | if (value){ | ||||
mLocationOverlay.enableFollowLocation(); | mLocationOverlay.enableFollowLocation(); | ||||
} else { | } else { | ||||
mLocationOverlay.disableFollowLocation(); | mLocationOverlay.disableFollowLocation(); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Do all the stuff you need to do on the gui, when parameter is changed to value | * Do all the stuff you need to do on the gui, when parameter is changed to value | ||||
* @param following value | * @param following value | ||||
*/ | */ | ||||
protected void updateGUIForLocationFollowing(boolean following){ | protected void updateGUIForLocationFollowing(boolean following){ | ||||
if (following) | if (following) | ||||
btFollowMe.setImageResource(R.drawable.ic_follow_me_on); | btFollowMe.setImageResource(R.drawable.ic_follow_me_on); | ||||
else | else | ||||
btFollowMe.setImageResource(R.drawable.ic_follow_me); | btFollowMe.setImageResource(R.drawable.ic_follow_me); | ||||
} | } | ||||
/** | |||||
* Start the location overlay. Enable only when | |||||
* a) we know we have the permission | |||||
* b) the location map is set | |||||
*/ | |||||
private void startLocationOverlay(boolean enableLocation){ | |||||
if(getActivity()== null) throw new IllegalStateException("Cannot enable LocationOverlay now"); | |||||
// Location Overlay | |||||
// from OpenBikeSharing (THANK GOD) | |||||
Log.d(DEBUG_TAG, "Starting position overlay"); | |||||
GpsMyLocationProvider imlp = new GpsMyLocationProvider(getActivity().getBaseContext()); | |||||
imlp.setLocationUpdateMinDistance(5); | |||||
imlp.setLocationUpdateMinTime(2000); | |||||
this.mLocationOverlay = new LocationOverlay(imlp,map, locationCallbacks); | |||||
if (enableLocation) mLocationOverlay.enableMyLocation(); | |||||
mLocationOverlay.setOptionsMenuEnabled(true); | |||||
map.getOverlays().add(this.mLocationOverlay); | |||||
} | |||||
public void startMap(Bundle incoming, Bundle savedInstanceState) { | public void startMap(Bundle incoming, Bundle savedInstanceState) { | ||||
//Check that we're attached | //Check that we're attached | ||||
GeneralActivity activity = getActivity() instanceof GeneralActivity ? (GeneralActivity) getActivity() : null; | GeneralActivity activity = getActivity() instanceof GeneralActivity ? (GeneralActivity) getActivity() : null; | ||||
if(getContext()==null|| activity==null){ | if(getContext()==null|| activity==null){ | ||||
//we are not attached | //we are not attached | ||||
Log.e(DEBUG_TAG, "Calling startMap when not attached"); | Log.e(DEBUG_TAG, "Calling startMap when not attached"); | ||||
return; | return; | ||||
}else{ | }else{ | ||||
Show All 14 Lines | public void startMap(Bundle incoming, Bundle savedInstanceState) { | ||||
} | } | ||||
shownStops = new HashSet<>(); | shownStops = new HashSet<>(); | ||||
// move the map on the marker position or on a default view point: Turin, Piazza Castello | // move the map on the marker position or on a default view point: Turin, Piazza Castello | ||||
// and set the start zoom | // and set the start zoom | ||||
IMapController mapController = map.getController(); | IMapController mapController = map.getController(); | ||||
GeoPoint startPoint = null; | GeoPoint startPoint = null; | ||||
boolean havePositionPermission = true; | // set the center point | ||||
if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { | |||||
activity.askForPermissionIfNeeded(Manifest.permission.ACCESS_FINE_LOCATION, PERMISSION_REQUEST_POSITION); | |||||
havePositionPermission = false; | |||||
} | |||||
// Location Overlay | |||||
// from OpenBikeSharing (THANK GOD) | |||||
GpsMyLocationProvider imlp = new GpsMyLocationProvider(activity.getBaseContext()); | |||||
imlp.setLocationUpdateMinDistance(5); | |||||
imlp.setLocationUpdateMinTime(2000); | |||||
this.mLocationOverlay = new LocationOverlay(imlp,map, locationCallbacks); | |||||
mLocationOverlay.enableMyLocation(); | |||||
mLocationOverlay.setOptionsMenuEnabled(true); | |||||
if (marker != null) { | if (marker != null) { | ||||
startPoint = marker; | startPoint = marker; | ||||
mapController.setZoom(POSITION_FOUND_ZOOM); | mapController.setZoom(POSITION_FOUND_ZOOM); | ||||
switchLocationFollowing(false); | setLocationFollowing(false); | ||||
} else if (savedInstanceState != null) { | } else if (savedInstanceState != null) { | ||||
mapController.setZoom(savedInstanceState.getDouble(MAP_CURRENT_ZOOM_KEY)); | mapController.setZoom(savedInstanceState.getDouble(MAP_CURRENT_ZOOM_KEY)); | ||||
mapController.setCenter(new GeoPoint(savedInstanceState.getDouble(MAP_CENTER_LAT_KEY), | mapController.setCenter(new GeoPoint(savedInstanceState.getDouble(MAP_CENTER_LAT_KEY), | ||||
savedInstanceState.getDouble(MAP_CENTER_LON_KEY))); | savedInstanceState.getDouble(MAP_CENTER_LON_KEY))); | ||||
Log.d(DEBUG_TAG, "Location following from savedInstanceState: "+savedInstanceState.getBoolean(FOLLOWING_LOCAT_KEY)); | Log.d(DEBUG_TAG, "Location following from savedInstanceState: "+savedInstanceState.getBoolean(FOLLOWING_LOCAT_KEY)); | ||||
switchLocationFollowing(savedInstanceState.getBoolean(FOLLOWING_LOCAT_KEY)); | setLocationFollowing(savedInstanceState.getBoolean(FOLLOWING_LOCAT_KEY)); | ||||
} else { | } else { | ||||
Log.d(DEBUG_TAG, "No position found from intent or saved state"); | Log.d(DEBUG_TAG, "No position found from intent or saved state"); | ||||
boolean found = false; | boolean found = false; | ||||
LocationManager locationManager = | LocationManager locationManager = | ||||
(LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE); | (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE); | ||||
if (locationManager != null) { | //check for permission | ||||
if (locationManager != null && Permissions.locationPermissionGranted(activity)) { | |||||
@SuppressLint("MissingPermission") | |||||
Location userLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); | Location userLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); | ||||
if (userLocation != null) { | if (userLocation != null) { | ||||
mapController.setZoom(POSITION_FOUND_ZOOM); | mapController.setZoom(POSITION_FOUND_ZOOM); | ||||
startPoint = new GeoPoint(userLocation); | startPoint = new GeoPoint(userLocation); | ||||
found = true; | found = true; | ||||
switchLocationFollowing(true); | setLocationFollowing(true); | ||||
} | } | ||||
} else if(!Permissions.locationPermissionGranted(activity)){ | |||||
if(shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)){ | |||||
//TODO: show dialog for permission rationale | |||||
Toast.makeText(activity, R.string.enable_position_message_map, Toast.LENGTH_SHORT).show(); | |||||
} | |||||
positionRequestLauncher.launch(Permissions.LOCATION_PERMISSIONS); | |||||
} | } | ||||
if(!found){ | if(!found){ | ||||
startPoint = new GeoPoint(DEFAULT_CENTER_LAT, DEFAULT_CENTER_LON); | startPoint = new GeoPoint(DEFAULT_CENTER_LAT, DEFAULT_CENTER_LON); | ||||
mapController.setZoom(16.0); | mapController.setZoom(17.0); | ||||
switchLocationFollowing(false); | setLocationFollowing(false); | ||||
} | } | ||||
} | } | ||||
startLocationOverlay(Permissions.locationPermissionGranted(activity)); | |||||
// set the minimum zoom level | // set the minimum zoom level | ||||
map.setMinZoomLevel(15.0); | map.setMinZoomLevel(15.0); | ||||
//add contingency check (shouldn't happen..., but) | //add contingency check (shouldn't happen..., but) | ||||
if (startPoint != null) { | if (startPoint != null) { | ||||
mapController.setCenter(startPoint); | mapController.setCenter(startPoint); | ||||
} | } | ||||
map.getOverlays().add(this.mLocationOverlay); | |||||
//add stops overlay | //add stops overlay | ||||
map.getOverlays().add(this.stopsFolderOverlay); | map.getOverlays().add(this.stopsFolderOverlay); | ||||
Log.d(DEBUG_TAG, "Requesting stops load"); | Log.d(DEBUG_TAG, "Requesting stops load"); | ||||
// This is not necessary, by setting the center we already move | // This is not necessary, by setting the center we already move | ||||
// the map and we trigger a stop request | // the map and we trigger a stop request | ||||
//requestStopsToShow(); | //requestStopsToShow(); | ||||
if (marker != null) { | if (marker != null) { | ||||
▲ Show 20 Lines • Show All 152 Lines • Show Last 20 Lines |
Public contents are in Creative Commons Attribution-ShareAlike 4.0 (CC-BY-SA) or GNU Free Documentation License (at your option) unless otherwise noted. · Contact / Register