I am developing a transit wand application that captures bus routes and passenger stops and then records them. Do I need to use background location permission? I am requesting location updates in a Service and using the Fused Location Provider for this purpose. In MainActivity (request-permission)
private void askForForegroundLocationPermission(Runnable backgroundPermission) {
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
Manifest.permission.ACCESS_FINE_LOCATION) ||
ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
Manifest.permission.ACCESS_COARSE_LOCATION)) {
new AlertDialog.Builder(this)
.setTitle("Permission Needed!")
.setMessage("Location Permission Needed!")
.setPositiveButton("OK", (dialog, which) ->
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
},
FOREGROUND_LOCATION_PERMISSION_CODE))
.setNegativeButton("CANCEL", null)
.create().show();
} else {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
},
FOREGROUND_LOCATION_PERMISSION_CODE);
}
} else {
if (backgroundPermission != null) {
backgroundPermission.run();
}
}
}
@RequiresApi(api = Build.VERSION_CODES.Q)
private void askForBackgroundLocationPermission() {
if (ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.ACCESS_BACKGROUND_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
Manifest.permission.ACCESS_BACKGROUND_LOCATION)) {
new AlertDialog.Builder(this)
.setTitle("Permission Needed!")
.setMessage("Background Location Permission Needed!")
.setPositiveButton("OK", (dialog, which) ->
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION},
BACKGROUND_LOCATION_PERMISSION_CODE))
.setNegativeButton("CANCEL", null)
.create().show();
} else {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{
Manifest.permission.ACCESS_BACKGROUND_LOCATION},
BACKGROUND_LOCATION_PERMISSION_CODE);
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == FOREGROUND_LOCATION_PERMISSION_CODE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED &&
grantResults[1] == PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
askForBackgroundLocationPermission();
}
}
}
}
CaptureService - parts responsible for handling location checks.
@SuppressLint("MissingPermission")
public void getCurrentLocation(OnSuccessListener<Location> successListener, OnFailureListener failureListener) {
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
fusedLocationProviderClient.getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, cancellationTokenSource.getToken())
.addOnSuccessListener(successListener)
.addOnFailureListener(failureListener);
}
public void onLocationChanged(Location location) {
Log.i("LOCATION", "onLocationChanged");
///POINTS RECORDED EVERY 5 METERS
if (currentCapture != null && location.getAccuracy() < 15 * 2) {
RoutePoint rp = new RoutePoint();
rp.location = location;
rp.time = SystemClock.elapsedRealtime();
currentCapture.points.add(rp);
if (lastLocation != null) {
currentCapture.distance += distanceFromLocation(lastLocation, location);
if (iCaptureActivity != null) {
iCaptureActivity.updateDistance();
}
}
lastLocation = location;
if (iCaptureActivity != null) {
iCaptureActivity.updateGpsStatus();
}
} else {
Log.e("Unable to update Location", "Unable to update Location");
}
}
@SuppressLint("MissingPermission")
public void startLocationTracking() {
fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper())
.addOnSuccessListener(aVoid -> Log.i("Location", "All Ok"))
.addOnFailureListener(e -> Log.e("Location", "Error", e));
}
public void stopLocationTracking() {
fusedLocationProviderClient.removeLocationUpdates(locationCallback);
}
public void initLocation() {
Log.w("CaptureService", "initLocation");
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
locationRequest = new LocationRequest.Builder(10 * 1000L)
.setMinUpdateDistanceMeters(5) /// change later to 5
.setWaitForAccurateLocation(true)
.setPriority(Priority.PRIORITY_HIGH_ACCURACY)
.build();
locationCallback = new LocationCallback() {
@Override
public void onLocationResult(@NonNull LocationResult locationResult) {
super.onLocationResult(locationResult);
CaptureService.this.onLocationChanged(locationResult.getLastLocation());
Log.w("initLocation Event", String.valueOf(locationResult.getLastLocation()));
}
};
}
public String getGpsStatus() {
String status = "";
if(lastLocation != null)
status = "GPS +/-" + Math.round(lastLocation.getAccuracy()) + "m";
else
status = "GPS Pending";
return status;
}
Google is very demanding regarding this permission, and I need to explain why I need to use it. What benefits does it provide for my app if I use it? Or can fine location access do this job by default, for instance, if the screen is locked or the application is not open but running alongside other apps? Please explain this in more detail
<service android:name=".services.CaptureService"
android:foregroundServiceType="location"
android:enabled="true">
</service>