Changeset View
Changeset View
Standalone View
Standalone View
src/it/reyboz/bustorino/middleware/AppLocationManager.java
Show All 11 Lines | BusTO (middleware) | ||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
GNU General Public License for more details. | GNU General Public License for more details. | ||||
You should have received a copy of the GNU General Public License | You should have received a copy of the GNU General Public License | ||||
along with this program. If not, see <http://www.gnu.org/licenses/>. | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
*/ | */ | ||||
package it.reyboz.bustorino.middleware; | package it.reyboz.bustorino.middleware; | ||||
import android.Manifest; | |||||
import android.content.Context; | import android.content.Context; | ||||
import android.content.pm.PackageManager; | |||||
import android.location.Criteria; | |||||
import android.location.Location; | import android.location.Location; | ||||
import android.location.LocationListener; | import android.location.LocationListener; | ||||
import android.location.LocationManager; | import android.location.LocationManager; | ||||
import android.location.LocationProvider; | import android.location.LocationProvider; | ||||
import android.os.Bundle; | import android.os.Bundle; | ||||
import android.util.Log; | import android.util.Log; | ||||
import android.widget.Toast; | import android.widget.Toast; | ||||
import androidx.core.content.ContextCompat; | |||||
import it.reyboz.bustorino.util.LocationCriteria; | import it.reyboz.bustorino.util.LocationCriteria; | ||||
import it.reyboz.bustorino.util.Permissions; | |||||
import java.lang.ref.WeakReference; | import java.lang.ref.WeakReference; | ||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.ListIterator; | import java.util.ListIterator; | ||||
/** | /** | ||||
* Singleton class used to access location. Possibly extended with other location sources. | * Singleton class used to access location. Possibly extended with other location sources. | ||||
*/ | */ | ||||
public class AppLocationManager implements LocationListener { | public class AppLocationManager implements LocationListener { | ||||
public static final int LOCATION_GPS_AVAILABLE = 22; | public static final int LOCATION_GPS_AVAILABLE = 22; | ||||
public static final int LOCATION_UNAVAILABLE = -22; | public static final int LOCATION_UNAVAILABLE = -22; | ||||
private Context con; | private final Context appContext; | ||||
private LocationManager locMan; | private final LocationManager locMan; | ||||
public static final String DEBUG_TAG = "BUSTO LocAdapter"; | public static final String DEBUG_TAG = "BUSTO LocAdapter"; | ||||
private final String BUNDLE_LOCATION = "location"; | private final String BUNDLE_LOCATION = "location"; | ||||
private static AppLocationManager instance; | private static AppLocationManager instance; | ||||
private int oldGPSLocStatus = LOCATION_UNAVAILABLE; | private int oldGPSLocStatus = LOCATION_UNAVAILABLE; | ||||
private int minimum_time_milli = -1; | private int minimum_time_milli = -1; | ||||
private ArrayList<WeakReference<LocationRequester>> requestersRef = new ArrayList<>(); | private boolean isLocationPermissionGiven = false; | ||||
private final ArrayList<WeakReference<LocationRequester>> requestersRef = new ArrayList<>(); | |||||
private AppLocationManager(Context con) { | private AppLocationManager(Context context) { | ||||
this.con = con.getApplicationContext(); | this.appContext = context.getApplicationContext(); | ||||
locMan = (LocationManager) con.getSystemService(Context.LOCATION_SERVICE); | locMan = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); | ||||
isLocationPermissionGiven = checkLocationPermission(context); | |||||
} | } | ||||
public static AppLocationManager getInstance(Context con) { | public static AppLocationManager getInstance(Context con) { | ||||
if(instance==null) instance = new AppLocationManager(con.getApplicationContext()); | if(instance==null) instance = new AppLocationManager(con); | ||||
return instance; | return instance; | ||||
} | } | ||||
public static boolean checkLocationPermission(Context context){ | |||||
return ContextCompat.checkSelfPermission(context, | |||||
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED; | |||||
} | |||||
private void requestGPSPositionUpdates(){ | private void requestGPSPositionUpdates() throws SecurityException{ | ||||
final int timeinterval = (minimum_time_milli>0 && minimum_time_milli<Integer.MAX_VALUE)? minimum_time_milli : 2000; | final int timeinterval = (minimum_time_milli>0 && minimum_time_milli<Integer.MAX_VALUE)? minimum_time_milli : 2000; | ||||
try { | |||||
locMan.removeUpdates(this); | locMan.removeUpdates(this); | ||||
locMan.requestLocationUpdates(LocationManager.GPS_PROVIDER, timeinterval, 5, this); | locMan.requestLocationUpdates(LocationManager.GPS_PROVIDER, timeinterval, 5, this); | ||||
} catch (SecurityException exc){ | |||||
exc.printStackTrace(); | |||||
Toast.makeText(con,"Cannot access GPS location",Toast.LENGTH_SHORT).show(); | |||||
} | |||||
} | } | ||||
private void cleanAndUpdateRequesters(){ | private void cleanAndUpdateRequesters(){ | ||||
minimum_time_milli = Integer.MAX_VALUE; | minimum_time_milli = Integer.MAX_VALUE; | ||||
ListIterator<WeakReference<LocationRequester>> iter = requestersRef.listIterator(); | ListIterator<WeakReference<LocationRequester>> iter = requestersRef.listIterator(); | ||||
while(iter.hasNext()){ | while(iter.hasNext()){ | ||||
final LocationRequester cReq = iter.next().get(); | final LocationRequester cReq = iter.next().get(); | ||||
if(cReq==null) iter.remove(); | if(cReq==null) iter.remove(); | ||||
else { | else { | ||||
minimum_time_milli = Math.min(cReq.getLocationCriteria().getTimeInterval(),minimum_time_milli); | minimum_time_milli = Math.min(cReq.getLocationCriteria().getTimeInterval(),minimum_time_milli); | ||||
} | } | ||||
} | } | ||||
Log.d(DEBUG_TAG,"Updated requesters, got "+requestersRef.size()+" listeners to update every "+minimum_time_milli+" ms at least"); | Log.d(DEBUG_TAG,"Updated requesters, got "+requestersRef.size()+" listeners to update every "+minimum_time_milli+" ms at least"); | ||||
} | } | ||||
public void addLocationRequestFor(LocationRequester req){ | public void addLocationRequestFor(LocationRequester req){ | ||||
boolean present = false; | boolean present = false; | ||||
minimum_time_milli = Integer.MAX_VALUE; | minimum_time_milli = Integer.MAX_VALUE; | ||||
int countNull = 0; | |||||
ListIterator<WeakReference<LocationRequester>> iter = requestersRef.listIterator(); | ListIterator<WeakReference<LocationRequester>> iter = requestersRef.listIterator(); | ||||
while(iter.hasNext()){ | while(iter.hasNext()){ | ||||
final LocationRequester cReq = iter.next().get(); | final LocationRequester cReq = iter.next().get(); | ||||
if(cReq==null) iter.remove(); | if(cReq==null) { | ||||
else if(cReq.equals(req)){ | countNull++; | ||||
iter.remove(); | |||||
} else if(cReq.equals(req)){ | |||||
present = true; | present = true; | ||||
minimum_time_milli = Math.min(cReq.getLocationCriteria().getTimeInterval(),minimum_time_milli); | minimum_time_milli = Math.min(cReq.getLocationCriteria().getTimeInterval(),minimum_time_milli); | ||||
} | } | ||||
} | } | ||||
Log.d(DEBUG_TAG, countNull+" listeners have been removed because null"); | |||||
if(!present) { | if(!present) { | ||||
WeakReference<LocationRequester> newref = new WeakReference<>(req); | WeakReference<LocationRequester> newref = new WeakReference<>(req); | ||||
requestersRef.add(newref); | requestersRef.add(newref); | ||||
minimum_time_milli = Math.min(req.getLocationCriteria().getTimeInterval(),minimum_time_milli); | minimum_time_milli = Math.min(req.getLocationCriteria().getTimeInterval(),minimum_time_milli); | ||||
Log.d(DEBUG_TAG,"Added new stop requester, instance of "+req.getClass().getSimpleName()); | Log.d(DEBUG_TAG,"Added new stop requester, instance of "+req.getClass().getSimpleName()); | ||||
} | } | ||||
if(requestersRef.size()>0){ | if(requestersRef.size()>0){ | ||||
Log.d(DEBUG_TAG,"Requesting position updates"); | Log.d(DEBUG_TAG,"Requesting location updates"); | ||||
requestGPSPositionUpdates(); | requestGPSPositionUpdates(); | ||||
} | } | ||||
} | } | ||||
public void removeLocationRequestFor(LocationRequester req){ | public void removeLocationRequestFor(LocationRequester req){ | ||||
minimum_time_milli = Integer.MAX_VALUE; | minimum_time_milli = Integer.MAX_VALUE; | ||||
ListIterator<WeakReference<LocationRequester>> iter = requestersRef.listIterator(); | ListIterator<WeakReference<LocationRequester>> iter = requestersRef.listIterator(); | ||||
Show All 13 Lines | public class AppLocationManager implements LocationListener { | ||||
private void sendLocationStatusToAll(int status){ | private void sendLocationStatusToAll(int status){ | ||||
ListIterator<WeakReference<LocationRequester>> iter = requestersRef.listIterator(); | ListIterator<WeakReference<LocationRequester>> iter = requestersRef.listIterator(); | ||||
while(iter.hasNext()){ | while(iter.hasNext()){ | ||||
final LocationRequester cReq = iter.next().get(); | final LocationRequester cReq = iter.next().get(); | ||||
if(cReq==null) iter.remove(); | if(cReq==null) iter.remove(); | ||||
else cReq.onLocationStatusChanged(status); | else cReq.onLocationStatusChanged(status); | ||||
} | } | ||||
} | } | ||||
public boolean isRequesterRegistered(LocationRequester requester){ | |||||
for(WeakReference<LocationRequester> regRef: requestersRef){ | |||||
if(regRef.get()!=null && regRef.get() ==requester) return true; | |||||
} | |||||
return false; | |||||
} | |||||
@Override | @Override | ||||
public void onLocationChanged(Location location) { | public void onLocationChanged(Location location) { | ||||
Log.d(DEBUG_TAG,"found location:\nlat: "+location.getLatitude()+" lon: "+location.getLongitude()+"\naccuracy: "+location.getAccuracy()); | Log.d(DEBUG_TAG,"found location:\nlat: "+location.getLatitude()+" lon: "+location.getLongitude()+"\naccuracy: "+location.getAccuracy()); | ||||
ListIterator<WeakReference<LocationRequester>> iter = requestersRef.listIterator(); | ListIterator<WeakReference<LocationRequester>> iter = requestersRef.listIterator(); | ||||
int new_min_interval = Integer.MAX_VALUE; | int new_min_interval = Integer.MAX_VALUE; | ||||
while(iter.hasNext()){ | while(iter.hasNext()){ | ||||
final LocationRequester requester = iter.next().get(); | final LocationRequester requester = iter.next().get(); | ||||
Show All 26 Lines | public void onStatusChanged(String provider, int status, Bundle extras) { | ||||
if(oldGPSLocStatus !=status){ | if(oldGPSLocStatus !=status){ | ||||
if(status == LocationProvider.OUT_OF_SERVICE || status == LocationProvider.TEMPORARILY_UNAVAILABLE) { | if(status == LocationProvider.OUT_OF_SERVICE || status == LocationProvider.TEMPORARILY_UNAVAILABLE) { | ||||
sendLocationStatusToAll(LOCATION_UNAVAILABLE); | sendLocationStatusToAll(LOCATION_UNAVAILABLE); | ||||
}else if(status == LocationProvider.AVAILABLE){ | }else if(status == LocationProvider.AVAILABLE){ | ||||
sendLocationStatusToAll(LOCATION_GPS_AVAILABLE); | sendLocationStatusToAll(LOCATION_GPS_AVAILABLE); | ||||
} | } | ||||
oldGPSLocStatus = status; | oldGPSLocStatus = status; | ||||
} | } | ||||
Log.d(DEBUG_TAG, "Provider: "+provider+" status: "+status); | Log.d(DEBUG_TAG, "Provider status changed: "+provider+" status: "+status); | ||||
} | } | ||||
@Override | @Override | ||||
public void onProviderEnabled(String provider) { | public void onProviderEnabled(String provider) { | ||||
cleanAndUpdateRequesters(); | |||||
requestGPSPositionUpdates(); | requestGPSPositionUpdates(); | ||||
Log.d(DEBUG_TAG, "Provider: "+provider+" enabled"); | Log.d(DEBUG_TAG, "Provider: "+provider+" enabled"); | ||||
for(WeakReference<LocationRequester> req: requestersRef){ | |||||
if(req.get()==null) continue; | |||||
req.get().onLocationProviderAvailable(); | |||||
} | |||||
} | } | ||||
@Override | @Override | ||||
public void onProviderDisabled(String provider) { | public void onProviderDisabled(String provider) { | ||||
locMan.removeUpdates(this); | cleanAndUpdateRequesters(); | ||||
for(WeakReference<LocationRequester> req: requestersRef){ | |||||
if(req.get()==null) continue; | |||||
req.get().onLocationDisabled(); | |||||
} | |||||
//locMan.removeUpdates(this); | |||||
Log.d(DEBUG_TAG, "Provider: "+provider+" disabled"); | Log.d(DEBUG_TAG, "Provider: "+provider+" disabled"); | ||||
} | } | ||||
public boolean anyLocationProviderMatchesCriteria(Criteria cr) { | |||||
return Permissions.anyLocationProviderMatchesCriteria(locMan, cr, true); | |||||
} | |||||
/** | /** | ||||
* Interface to be implemented to get the location request | * Interface to be implemented to get the location request | ||||
*/ | */ | ||||
public interface LocationRequester{ | public interface LocationRequester{ | ||||
/** | /** | ||||
* Do something with the newly obtained location | * Do something with the newly obtained location | ||||
* @param loc the obtained location | * @param loc the obtained location | ||||
*/ | */ | ||||
void onLocationChanged(Location loc); | void onLocationChanged(Location loc); | ||||
/** | /** | ||||
* Inform the requester that the GPS status has changed | * Inform the requester that the GPS status has changed | ||||
* @param status new status | * @param status new status | ||||
*/ | */ | ||||
void onLocationStatusChanged(int status); | void onLocationStatusChanged(int status); | ||||
/** | /** | ||||
* We have a location provider available | |||||
*/ | |||||
void onLocationProviderAvailable(); | |||||
/** | |||||
* Called when location is disabled | |||||
*/ | |||||
void onLocationDisabled(); | |||||
/** | |||||
* Give the last time of update the requester has | * Give the last time of update the requester has | ||||
* Set it to -1 in order to receive each new location | * Set it to -1 in order to receive each new location | ||||
* @return the time for update in milliseconds since epoch | * @return the time for update in milliseconds since epoch | ||||
*/ | */ | ||||
long getLastUpdateTimeMillis(); | long getLastUpdateTimeMillis(); | ||||
/** | /** | ||||
* Get the specifications for the location | * Get the specifications for the location | ||||
* @return fully parsed LocationCriteria | * @return fully parsed LocationCriteria | ||||
*/ | */ | ||||
LocationCriteria getLocationCriteria(); | LocationCriteria getLocationCriteria(); | ||||
} | } | ||||
} | } |
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