I have a service class that continuously runs in background to fetch location updates. Everything works as expected but when I disable the permission from the settings, the app crashes. I couldn't figure out why the app is crashing when I disable the location permission from the settings. Below is what I get in logcat.
FATAL EXCEPTION: GoogleApiHandler
Process: com.android.myapp, PID: 7703
java.lang.SecurityException: Client must have ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to perform any location operations.
at android.os.Parcel.readException(Parcel.java:1683)
at android.os.Parcel.readException(Parcel.java:1636)
at com.google.android.gms.internal.zzeu.zza(Unknown Source)
at com.google.android.gms.internal.zzcfa.zzif(Unknown Source)
at com.google.android.gms.internal.zzcfd.getLastLocation(Unknown Source)
at com.google.android.gms.internal.zzcfk.getLastLocation(Unknown Source)
at com.google.android.gms.location.zzg.zza(Unknown Source)
at com.google.android.gms.common.api.internal.zze.zza(Unknown Source)
at com.google.android.gms.common.api.internal.zzbo.zzb(Unknown Source)
at com.google.android.gms.common.api.internal.zzbo.zzaiw(Unknown Source)
at com.google.android.gms.common.api.internal.zzbo.onConnected(Unknown Source)
at com.google.android.gms.common.internal.zzac.onConnected(Unknown Source)
at com.google.android.gms.common.internal.zzn.zzakr(Unknown Source)
at com.google.android.gms.common.internal.zze.zzw(Unknown Source)
at com.google.android.gms.common.internal.zzi.zzaks(Unknown Source)
at com.google.android.gms.common.internal.zzh.handleMessage(Unknown Source)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.os.HandlerThread.run(HandlerThread.java:61)
Here is my Service class. This always runs in the background.
public class LocationService extends Service {
...
...
...
@Override
public void onCreate() {
try {
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
onNewLocation(locationResult.getLastLocation());
}
};
createLocationRequest();
getLastLocation();
requestLocationUpdates();
}catch(Exception e){
e.printStackTrace();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Service started");
return START_STICKY;
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
Log.i(TAG, "Service destroy");
Toast.makeText(getApplicationContext(), "Service Destroy", Toast.LENGTH_SHORT).show();
}
/**
* Makes a request for location updates. Note that in this sample we merely log the
* {@link SecurityException}.
*/
public void requestLocationUpdates() {
Log.i(TAG, "Requesting location updates");
Utils.setRequestingLocationUpdates(this, true);
try {
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
} catch (SecurityException unlikely) {
Utils.setRequestingLocationUpdates(this, false);
Log.e(TAG, "Lost location permission. Could not request updates. " + unlikely);
}
}
/**
* Removes location updates. Note that in this sample we merely log the
* {@link SecurityException}.
*/
public void removeLocationUpdates() {
Log.i(TAG, "Removing location updates");
try {
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
Utils.setRequestingLocationUpdates(this, false);
stopSelf();
} catch (SecurityException unlikely) {
Utils.setRequestingLocationUpdates(this, true);
Log.e(TAG, "Lost location permission. Could not remove updates. " + unlikely);
}
}
private void getLastLocation() {
try {
mFusedLocationClient.getLastLocation()
.addOnCompleteListener(task -> {
if (task.isSuccessful() && task.getResult() != null) {
mLocation = task.getResult();
} else {
Log.w(TAG, "Failed to get location.");
}
});
} catch (SecurityException unlikely) {
Log.e(TAG, "Lost location permission." + unlikely);
}
}
private void onNewLocation(Location location) {
Log.i(TAG, "New location: " + location);
mLocation = location;
// Doing some operations using location data.
mPreviousLocation = mLocation;
System.gc();
}
/**
* Sets the location request parameters.
*/
private void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest
.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
@Override
public void onTaskRemoved(Intent rootIntent) {
Log.i(TAG, "Service Task Removed");
Toast.makeText(getApplicationContext(), "Service Task Removed", Toast.LENGTH_SHORT).show();
startService(new Intent(getApplicationContext(), LocationService.class));
super.onTaskRemoved(rootIntent);
}
}
I am checking location permission in my activity class and starting the service once the user accepts the permission. There is no issue with that and I am even getting location updates from background service. Meanwhile when I try to disable the permission from settings the app crashes. Here is my MainActivity class where I am checking the location permission.
public class MainActivity extends AppCompatActivity{
@Override
protected void onResume() {
super.onResume();
checkAndEnableGps();
}
private void checkAndEnableGps() {
try {
new RxPermissions(this)
.request(Manifest.permission.ACCESS_FINE_LOCATION)
.subscribe(granted -> {
if (granted) {
if (!Utils.isServiceRunning(this, LocationService.class)) {
startService(new Intent(this, LocationService.class));
}
showSettingDialog();
}
});
}catch (Exception e){
e.printStackTrace();
}
}
}