Request Background Location like a Pro

As we have advanced to android 11 accessing location in the background is becoming more and more complicated since android 9. All of this is happening because of google's updated policy which lets users have more control over these sensitive permissions. Now before requesting this sensitive permission, we as developers have to show a disclosure prompt regarding How and Why the app is using background location to maintain transparency with the users. Here we will request background location permission for Android 9(and below),10,11(and above).



Let's get started...!!!



Android 9 and below: 


Request background location is nothing special for Android 9 and below, it works no different than location permission ie(ACCESS_FINE_LOCAITON or ACCESS_COARSE_LOCATION) by allowing any of this permission your app will be eligible to access the location in the background. This can easily be enabled or disabled by a simple ON/OFF switch present in app permission.



static int REQUEST_PERMISSION_CODE = 122;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
layout = findViewById(R.id.mainLayout);
checkLocationRequest();
}
private void checkLocationRequest() {
if (android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
Log.d(TAG, "checkLocationRequest: android P or less");
requestPermission();
}
}
private void requestPermission(){
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION},REQUEST_PERMISSION_CODE); //Request Permisison code
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_PERMISSION_CODE){
// should show request permission rationale return true when permission is denied but
// returns false when permission in permanently denied
if (android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.P ) {
if (!shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)){
Log.d(TAG, "onRequestPermissionsResult: rationale");
showDialog();
}
else if ( grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_DENIED) {
Log.d(TAG, "onRequestPermissionsResult: Permission denied");
showSnackBar();
}else{
Toast.makeText(context, "Android P or less Permisison Granted", Toast.LENGTH_SHORT).show();
}
}
}
private void showDialog(){
AlertDialog alertDialog = new AlertDialog.Builder(MainActivity.this).create();
alertDialog.setTitle("Important");
alertDialog.setMessage("Put the Reason, why you need this permisison");
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, "OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
checkLocationRequest();
}
});
alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
showSnackBar();
}
});
alertDialog.show();
}
private void showSnackBar(){
Snackbar snackbar = Snackbar.make(layout, "Put the reason, WHY?",Snackbar.LENGTH_INDEFINITE)
.setAction("Retry", new View.OnClickListener() {
@Override
public void onClick(View view) {
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_PERMISSION_CODE);
}
});
snackbar.show();
}
view raw permission.java hosted with ❤ by GitHub

When you will run the app it will pop-up like this: 



Android 10: 

For target Sdk 29 (android 10) things are a little different this time. For earlier versions, there wasn't any explicit permission to "Request Location in Background" but now for android 10 and above, we have to add this permission in Manifest.
<uses-permission android:name=”android.permission.ACCESS_BACKGROUND_LOCATION”/>

As ACCESS_BACKGROUND_LOCATION was introduced in this version. Now we have to request this permission at the same time with ACCESS_FINE_LOCATION permission.



static int REQUEST_PERMISSION_CODE = 122;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
layout = findViewById(R.id.mainLayout);
checkLocationRequest();
}
//Here requesting fine location and background location permission in a single array.
private void checkLocationRequest() {
if (android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
Log.d(TAG, "checkLocationRequest: android 10");
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION},REQUEST_PERMISSION_CODE);
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_PERMISSION_CODE){
Log.d(TAG, "onRequestPermissionsResult: rationale"+shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_BACKGROUND_LOCATION));
/**
when user selects "Allow only while using the app" means background location permission is denied
but fine location granted and shouldShowRequestPermissionRationale will return true.
when user selects "Allow all the time" means background locaiton permission is granted
*/
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q){
if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_BACKGROUND_LOCATION)){
Log.d(TAG, "onRequestPermissionsResult: rationale");
showDialog(); //this code is present in above code snippet
} else if ( grantResults.length > 0 && grantResults[1] == PackageManager.PERMISSION_DENIED) {
Log.d(TAG, "onRequestPermissionsResult: Permission denied");
showSnackBar(); //this code is present in above code snippet
}else{
Toast.makeText(context, "Android Q Granted", Toast.LENGTH_SHORT).show();
}
}
}
}
view raw permission.java hosted with ❤ by GitHub

When we run this code, location pop-up will look like this 




This dialog looks different from target Sdk less than 29(android 9). Let's worry not and try to understand what is happening here.

  • "Allow all the time" is the option to enable Background location.
  • "Allow only while using the app" it is a simple location permisison, where app can access the location till it is in Foreground.


Finally....!!!!

Android 11 and above


Earlier (android 10) we have requested "ACCESS_FINE_LOCATION" and "ACCESS_BACKGROUND_LOCATION" in a single string array but for Android 11 process has been changed. Even if we try to ask the background location permission along with fine location in a same string array, the system will reject it.



Now what to do..??

Well the solution is simple "Request the Background Location Permission when Fine Location Permission Granted" but...

There is a little change, we cannot not directly request this permission. Now we have to show an explicit dialog box explaining why we need this background location.

As per google's updated policy this permission is sensitive and user should have control over it instead the app.

Note: If we don't show the dialog explaining why this background location then Google will reject the app while uploading on Play Store.


static int REQUEST_PERMISSION_CODE = 122;
private void checkLocationRequest() {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
Log.d(TAG, "checkLocationRequest: android R and above");
requestPermission();
}
}
private void requestPermission(){
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION},REQUEST_PERMISSION_CODE); //Request Permisison code
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_PERMISSION_CODE){
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R){
if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)){
Log.d(TAG, "onRequestPermissionsResult: rationale");
showDialog();
} else if ( grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_DENIED) {
Log.d(TAG, "onRequestPermissionsResult: Permission denied");
showSnackBar();
}else if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
// Permission Granted
if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_BACKGROUND_LOCATION)){
showAndroid11Dialog();
}
}
}
}
}
private void showAndroid11Dialog(){
AlertDialog alertDialog = new AlertDialog.Builder(SplashScreen.this).create();
alertDialog.setTitle("Allow all the time");
alertDialog.setMessage("EXPLAING WHY NEED BACKGROUND LOCATION");
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, "OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// This will take user to app permission screen
requestPermissions(new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION}, REQUEST_PERMISSION_CODE);
}
});
alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
showSnackBar();
}
});
alertDialog.show();
}

In the above code, we first asked location permission, If it has been granted then we showed an alert dialog and on the "OK" button press we will request for background location permission and the app will take the user to app permission screen from where user will select "Allow all the time" option.

Note: There should also be a cancel button to close the dialog.


 

This time there is no "Allow all the time" option present in permisison dialog.

Hope this will help you to Request Background Location Permission for all the android version.




Wait...!!!


A bonus information is yet to discuss.




Android 11 has a new setting for app permissions, the system resets the sensitive permissions if it isn't used for few months. If your app follows the best practices to handle permission requests then there is no need to change anything in the app. Whenever the user starts the app and permissions are denied then permission pop-up will invoke automatically.

 



that's all....



HAPPY CODING :)




Comments