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>
Your app seems to be using background location. Whether or not you need it is a different matter.
If your app can provide its functionality while requiring the user to have the app open, then you don’t need the permission.
Background location access is when you need to know the user’s location when the app is in the background.
If you are following the user’s route and don’t expect them to have your app in the foreground, then you do need it.
Your motivation would be exactly why you need it and how it benefits the user - if you are tracking routes as the main purpose of your app, then that is the benefit to the user.
The restriction is intended to keep users secure and not to hamper legitimate functionality. Many apps have a good reason to need background location, but you need to be clear on how you’re using it.