"Allow all the time" location prompt not coming in Android SDK 29
Asked Answered
R

8

21

I can't get the "Allow all the time" prompt for location in SDK 29. I already set these permissions in the manifest:

<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

and requesting the user to allow these permissions at run time. But it only returns the "When the app is open" and "Deny" choices.

Any thoughts about how to show it in SDK 29.

Rhymester answered 20/5, 2020 at 9:12 Comment(2)
Please post the code in answer. How did you solve the allow all the time issue.Monda
@DevendraSingh Have you seen the accepted answer below? Or ask a new question by posting the code that you have tried so far?Rhymester
O
20

In order to access the location in background on device running Android 10 (API level 29) or higher, you also need to use below permission in the manifest file

 <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

please refer the below link for more information

https://developer.android.com/training/location/permissions?hl=fr

Ontologism answered 20/5, 2020 at 9:41 Comment(5)
I have added that permission request in the manifest and I still do not get the "Allow all the time" option, just "Allow only while using the app" option. I have another app with the same set of permissions and this one gets both! DO I need to request the background location from the user as well?Weighting
Yes, @BrianReinhold. Just add Manifest.permission.ACCESS_BACKGROUND_LOCATION to your permission array when calling ActivityCompat.requestPermissions()Tarryn
@BrianReinhold Yes you need to ask that permissionRhymester
Added the line in the manifest AND I am requesting the permission. Nothing!Kelley
What is the target SDK version?Rhymester
F
7

Add permission ACCESS_BACKGROUND_LOCATION in the manifest. It is required to show always allow option on android 10 and higher.

See the second point in https://developer.android.com/training/location/background#evaluate

Fairleigh answered 20/5, 2020 at 9:30 Comment(1)
I have added the ACCESS_BACKGROUND_LOCATION still allow all the time not showing.Monda
W
3

I found that adding just the permission in the manifest was not sufficient. I had to provide an option for the user to grant it at start up, just like I need to do for the ACCESS_FINE_LOCATION. Interestingly, when I check if the background permission is already granted in the app, it never gives false. But if I don't check, I dont get the "Allow all the time" option. This is on an Android Pixel 2 version 10

Its only necessary in the 10+ versions of Android. Requesting both permissions gives the user the choice in the dialog box ... of course the user may not select 'All the time'. There is nothing one can do about that!

I am a little embarrassed to add my code because I know it sucks. Someone else could surely improve it. I could not find a way to avoid cycling through the permissions twice.

/**
 * This method lists all the permissions needed and gives reasons for each of them in a single
 * dialog. When the user presses ok, Android will popup separate dialogs for each permission
 * that is needed. In the case of location, the "Allow all the time" gives background permission
 * "Allow only while the app is running gives just the location permission while in foreground.
 * @return false if permissions are to be requested, true if they have already been granted.
 *
 * In Android 11 Build 30 things are a lot different. One has to ask for location first, approve
 * the 'while the app is running' option and then upon return in the Activity result, ask for
 * the background. Thus the new variable 'secondPassR' to handle this case. After the background
 * one comes back to the Activity result and then one can go into the main activity.
 */
static boolean secondPassR = false;
private static final int REQUEST_CODE_MULTIPLE_PERMISSIONS = 57;
private boolean requestPermissions(Activity activity)
{
    Log.v(TAG, "requestPermissions() called");
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
    {
        final List<String> permissionsList = new ArrayList<>();
        final List<String> reasonList = new ArrayList<>();

        if(!addPermission(permissionsList, Manifest.permission.ACCESS_FINE_LOCATION, activity))
        {
            reasonList.add("LOCATION PERMISSION: Needs needs to be granted for the Bluetooth " +
                    " LE scanner to discover devices!\n\n");
        }
        if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) && (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) || secondPassR)
        {
            if (!addPermission(permissionsList, Manifest.permission.ACCESS_BACKGROUND_LOCATION, activity))
            {
                reasonList.add("BACKGROUND PERMISSION: Needs to be granted for the Bluetooth " +
                        "LE Scanner to run in the background.\n\n");
            }
        }
        if (permissionsList.size() > 0)
        {
            if (reasonList.size() > 0)
            {
                // Need Rationale
                StringBuilder message = new StringBuilder(reasonList.get(0));
                for (int i = 1; i < reasonList.size(); i++)
                {
                    message.append(" ").append(reasonList.get(i));
                }
                final androidx.appcompat.app.AlertDialog.Builder builder =
                        new androidx.appcompat.app.AlertDialog.Builder(new ContextThemeWrapper(activity, R.style.Theme_AppCompat_Light));
                builder.setTitle("Demo needs the following permissions:");
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                {
                    builder.setMessage(Html.fromHtml(message.toString(), Html.FROM_HTML_MODE_LEGACY));
                }
                else
                {
                    builder.setMessage(Html.fromHtml(message.toString()));
                }
                builder.setPositiveButton(android.R.string.ok, null);
                builder.setOnDismissListener(dialog -> {
                    Log.v(TAG, "Requesting permissions");
                    activity.requestPermissions(permissionsList.toArray(new String[0]),  // newer Java recommended
                            REQUEST_CODE_MULTIPLE_PERMISSIONS);
                });
                builder.show();
                return false;
            }
            activity.requestPermissions(permissionsList.toArray(new String[0]),   // newer Java recommended
                    REQUEST_CODE_MULTIPLE_PERMISSIONS);
        }
        else
        {
            return true;
        }
    }
    else
    {
        return true;
    }
    return false;
}

@TargetApi(23)
private boolean addPermission(List<String> permissionsList, String permission, Activity activity)
{
    Log.v(TAG,
            "addPermission() called with: " + "permissionsList = " +
                    "[" + permissionsList + "], permission = [" + permission + "]");
    if (ActivityCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED)
    {
        permissionsList.add(permission);
        // Check for Rationale Option
        return activity.shouldShowRequestPermissionRationale(permission);
    }
    return true;
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
{
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    String permission = "";
    Log.v(TAG,
            "onRequestPermissionsResult() called with: " + "requestCode = [" + requestCode +
                    "], permissions = [" + Arrays.toString(permissions) + "]," +
                    " grantResults = [" + Arrays.toString(grantResults) + "]");
    if (requestCode == REQUEST_CODE_MULTIPLE_PERMISSIONS)
    {
        for (int i = 0; i < permissions.length; i++)
        {
            switch (permissions[i])
            {
                case Manifest.permission.ACCESS_FINE_LOCATION:
                    if (grantResults[i] == PackageManager.PERMISSION_GRANTED)
                    {
                        Log.d(TAG, "H@H: onRequestPermissionsResult: FINE LOCATION PERMISSION");
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
                        {
                            Log.d(TAG, "H@H: Now requesting BACKGROUND PERMISSION for version 11+");
                            secondPassR = true;
                            requestPermissions(thisActivity);
                            return;
                        }
                    }
                    break;
                case Manifest.permission.ACCESS_BACKGROUND_LOCATION:
                    if (grantResults[i] == PackageManager.PERMISSION_GRANTED)
                    {
                        Log.d(TAG, "H@H: onRequestPermissionsResult: BACKGROUND PERMISSION");
                    }
                    break;
            }
        }
    }
    Log.d(TAG, "Starting primary activity");
    secondPassR = false;
    startActivityForResult(new Intent(context, PchaDemoPhg_Activity.class), EXIT_QUIT);
}

private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener)
{
    new AlertDialog.Builder(this)
            .setMessage(message)
            .setCancelable(false)
            .setPositiveButton("OK", okListener)
            .create()
            .show();
}

============== UPDATE ANDROID 12 AND ActivityResultLauncher =======

With Android 12 a new set of permissions appear and we no longer have to ask for location permissions to use a BTLE scanner. THey also have a new way to handle activity results and that is the ActivityResultLauncher, and one of the built in features is for runtime permissions. Below is what I now use to request Bluetooth scanner and background permissions from ANdroid 6+. I use the single-permission launcher to place an explanation dialog before each request. The user experience is far better than what I used to have. (I include my string resources.)

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.text.Html;
import android.util.Log;

import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.core.app.ActivityCompat;

import java.util.ArrayList;
import java.util.List;


/*
    resource strings used:
    <string name="permissions_connect_12">&lt;p&gt;This app needs permission to connect to Bluetooth devices&lt;/p&gt; </string>
    <string name="permissions_scan_12">&lt;p&gt;To search for Bluetooth devices this app needs permission to use the BLE scanner.&lt;/p&gt; </string>
    <string name="permissions_overlay_11">READ CAREFULLY! Setting permissions in Android 11+ is much more complicated!\n\n
        This app wants to popup a dialog when it discovers a PHD that it can work with.\n\n
        It needs Window-Overlay permissions to do that. Android will start a Settings system activity where it will list all the installed applications.\n\n
        You will need to scroll down to Health@Home PHG and tap it. That will bring you to the original pre-11 Settings system overlay permission activity.
        Give the permission and use the back arrow to exit. You will need use the back arrow once more to return to Health@Home.</string>
    <string name="permissions_location">&lt;p&gt;&lt;font color=\"#007700\"&gt;&lt;b&gt;LOCATION PERMISSION:&lt;/b&gt;&lt;/font&gt; Needs to be granted in order for this app to use the Bluetooth LE scanner.
        The scanner is needed to discover BLE health devices and know what they are.&lt;/p&gt;
        &lt;p&gt;&lt;font color=\"red\"&gt;&lt;b&gt;This app does NOT use location information or expose location information!&lt;/b&gt;&lt;/font&gt;
        Without this permission you will only be able to work with SPP and HDP devices.&lt;/p&gt;</string>
    <string name="permissions_background">&lt;p&gt;BACKGROUND PERMISSION: Needs to be granted for the Bluetooth LE Scanner to run in the background
        to support re-connection without user intervention.&lt;/p&gt;
        &lt;p&gt;Please select \'Allow all the time\'.&lt;/p&gt;</string>
 */
public class PermissionsActivity extends AppCompatActivity
{
    private final static String TAG = PermissionsActivity.class.getName();

    private final static boolean isVersionS_Plus = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S); // 31
    private final static boolean isVersionM_Plus = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M); // 23 (Marshmallow)
    private final static boolean isVersionN_Plus = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N);
    private static final boolean isVersionO_Plus = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O);
    private static final boolean isVersionR = (Build.VERSION.SDK_INT == Build.VERSION_CODES.R); // 30
    private static final boolean isVersionR_Plus = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R); // 30
    private static final boolean isVersionOtoR = ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)  // 26
            && (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R));  // 30


    private final List<String> permissionsList = new ArrayList<>();
    private final List<String> reasonList = new ArrayList<>();
    private int index = 0;  // Keeps track of what permission is being requested
    private int indexMax;   // The maximum number of permissions being asked for (set below)

    ActivityResultLauncher<String> activityResultLauncher =
            registerForActivityResult(new ActivityResultContracts.RequestPermission(), new ActivityResultCallback<Boolean>()
            {
                @Override
                public void onActivityResult(Boolean result)
                {
                    Log.d(TAG, "HH2: Permission " + permissionsList.get(index) + (result ? " granted" : "rejected"));
                    index++;
                    if (index >= indexMax)
                    {
                        handlePermissionSummary();
                    }
                    else
                    {
                        requestPermissions(index);
                    }
                }
            });

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        // too lazy to make a layout; your activity very likely has one!
        if (handlePermissions())
        {
            //setLoginScreen();  // Do what needs to be done after permissions are granted or if they already are granted
        }
    }

    // Method checks to see if the needed permissions are granted and if they are it returns true.
    // If they are not granted the method returns false but starts the process of asking the user to grant the permissions
    @SuppressLint("NewApi")
    private boolean handlePermissions()
    {
        if (isVersionS_Plus)  // Android 12 + (31+)  Completely new runtime permissions for Bluetooth in Android 12
        {                     // At least one no longer has to ask for location permissions for Bluetooth completely
                              // confusing the user.
            // Requesting BLUETOOTH_CONNECT, BLUETOOTH_SCAN, and ACCESS_BACKGROUND_LOCATION. The latter is still needed
            // to use the BTLE scanner in the background.

            // There is a weird bug in Android 12 with respect to the BLUETOOTH_CONNECT and BLUETOOTH_SCAN
            // permissions. If you need both, regardless of what order you ask for them in, you get only one
            // dialog from Android where the user grants the permission. But you have to ask for both permissions
            // (if you need both). See this bug: https://issuetracker.google.com/issues/214434187
            // Thus I skip the application dialog by making it empty for the second permission and just request
            // the permission. That way both permissions get granted.
            if (checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED)
            {
                permissionsList.add(Manifest.permission.BLUETOOTH_CONNECT);
                reasonList.add(getString(R.string.permissions_connect_12));
            }
            if (checkSelfPermission(Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED)
            {
                permissionsList.add(Manifest.permission.BLUETOOTH_SCAN);
                reasonList.add(""); // Work-a-round. If empty, present no dialog explaining the request to the user
                //reasonList.add(getString(R.string.permissions_scan_12));
            }
            if (checkSelfPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED)
            {
                permissionsList.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION);
                reasonList.add(getString(R.string.permissions_background));
            }
            indexMax = 3; // Need three permissions
        }
        else if (isVersionM_Plus)
        {
            // Need location permissions to use the BTLE Scanner. Some versions of Android after 6 require FINE location and
            // some require only coarse and some both. TO minimize headache, I always ask for FINE and place COARSE location
            // in the Manifest file. That gives you use of the BTLE scanner for all pre-12 versions of Android
            if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) // Android 6 +
            {
                permissionsList.add(Manifest.permission.ACCESS_FINE_LOCATION); // Require ACCESS_COARSE_LOCATION in Manifest file as well
                reasonList.add(getString(R.string.permissions_location));
                indexMax = 1;  // Need only one here
            }
            if (isVersionOtoR)  // Android 8 - 11. For these versions need BACKGROUND permission to use the scanner in the background.
            {
                if (checkSelfPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED)
                {
                    permissionsList.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION);
                    reasonList.add(getString(R.string.permissions_background));
                    indexMax = 2;  // Need two permissions here
                }
            }
        }
        // If no permissions are needed, return true.
        if (permissionsList.size() == 0)
        {
            return true;
        }
        // Otherwise, begin the permission request sequence which involves launching permission requests.
        // The process is asynchronous, so the launch returns immediately.
        requestPermissions(index);
        return false;  // returning false indicates that permissions have not been granted and the request process is ongoing
    }

    // THis method pops up an application dialog explaining to the user why the application needs the requested permission.
    // When the user clicks OK, the permission request is launched. Android pops up whatever system action it dreams up to
    // handle the request. Sometimes it is a dialog, and sometimes it is an activity.
    // After the user responds, the result is returned in ActivityResultCallback above. The result is a boolean - true if
    // granted, false if not. Within the callback, the 'index' is checked. If there are more permissions to request,
    // this method is called again. If not, the summary method below is called.
    // It's ugly, but it is the only way I have been able to figure out how to place an explanation dialog before each
    // Android System action for the permission. Using the multiple permission approach I could not get my dialogs to
    // appear before each of the Android actions.
    @SuppressLint("NewApi")
    private void requestPermissions(int index)
    {
        if (reasonList.get(index).isEmpty()) // Work-a-round for Android 12. If explanation is empty then
        {
            // Skip explanation dialog but still request permission. Android pops up no dialog but auto-grants permission.
            activityResultLauncher.launch(permissionsList.get(index));
            return;
        }
        // Popup a dialog explaining why the app needs this permission and perhaps what Android is going to put you
        // through to grant the permission. For example, for BLUETOOTH_CONNECT/SCAN permissions Android pops up a
        // dialog. But for BACKGROUND permissions, Android presents an Activity. Exiting the dialog requires different
        // behavior from the user than exiting an activity.
        final androidx.appcompat.app.AlertDialog.Builder builder =
                new androidx.appcompat.app.AlertDialog.Builder(new ContextThemeWrapper(this, R.style.Theme_AppCompat_Light));
        builder.setTitle("Health@Home needs the following permission:");
        if (isVersionN_Plus)
        {
            builder.setMessage(Html.fromHtml(reasonList.get(index), Html.FROM_HTML_MODE_LEGACY));
        }
        else
        {
            builder.setMessage(Html.fromHtml(reasonList.get(index)));
        }
        builder.setPositiveButton(android.R.string.ok, null);
        builder.setOnDismissListener(dialog ->
        {
            Log.v(TAG, "HH2: Requesting permissions");
            activityResultLauncher.launch(permissionsList.get(index));
        });
        builder.show();
    }

    // THis method just summarizes the results of the permissions.
    @SuppressLint("NewApi")
    private void handlePermissionSummary()
    {
        boolean connectOk = (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED);
        boolean scanOk = (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) == PackageManager.PERMISSION_GRANTED);
        boolean locationOk = (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED);
        boolean backgroundOk = (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED);

        Log.d(TAG, "HH2: BLUETOOTH_CONNECT Permissions are " + connectOk);
        Log.d(TAG, "HH2: BLUETOOTH_SCAN Permissions are " + scanOk);
        Log.d(TAG, "HH2: ACCESS_FINE_LOCATION Permissions are " + locationOk);
        Log.d(TAG, "HH2: ACCESS_BACKGROUND_LOCATION Permissions are " + backgroundOk);

        String message = "";
        if (!connectOk && isVersionS_Plus)
        {
            message = "<p><b>Bluetooth Connect permissions not given.</b> You will be unable to find and connect to Bluetooth Low Energy devices</p>";
        }
        if (!scanOk && isVersionS_Plus)
        {
            message = "<p><b>Bluetooth Scan permissions not given.</b> You will be unable to find and connect to Bluetooth Low Energy devices</p>";
        }
        if (!locationOk && !isVersionS_Plus)
        {
            message = "<p><b>Location permissions not given.</b> You will be unable to find and connect to Bluetooth Low Energy devices</p>";
        }
        if (!backgroundOk && isVersionO_Plus)
        {
            message = message + "<p><b>Background permissions not given.</b> Operations with Bluetooth Low Energy devices will only work " +
                    "while Health@Home PHG is visible on the screen.</p>";
        }
        if (!message.isEmpty())
        {
            message = message + "<p>Remedies:<br>1. Restart Health@Home PHG.<br>2. Set permissions directly in the Android Settings menu<br>" +
                    "3. Uninstall and re-install Health@Home PHG</p>";
            final AlertDialog.Builder builder =
                    new AlertDialog.Builder(new ContextThemeWrapper(this, R.style.Theme_AppCompat_Light));
            builder.setTitle("Health@Home not given certain permissions!");
            if (isVersionN_Plus)
            {
                builder.setMessage(Html.fromHtml(message, Html.FROM_HTML_MODE_LEGACY));
            }
            else
            {
                builder.setMessage(Html.fromHtml(message));
            }
            builder.setPositiveButton(android.R.string.ok, null);
            builder.setOnDismissListener(dialog ->
            {
                Log.d(TAG, "Starting Login");
               // setLoginScreen(); // Do whatever you would do after permissions are handled
            });
            builder.show();
            return;
        }
        Log.d(TAG, "Starting Login");
      //  setLoginScreen(); // Do whatever you would do after permissions are handled
    }
}
Weighting answered 28/6, 2020 at 16:0 Comment(5)
Yes, that we should do to show the user to grant. without that how to can you ask the runtime permissions?Rhymester
How did you solve the issue? I want to show allow all the time to user. How to do that?Monda
@DevendraSingh I had to explicitly ask for ACCESS_BACKGROUND_LOCATION in the code along with the ACCESS_FINE_LOCATION. Then it is part of the Android UI which you have no control over. On Android 10+ Android first pops up the permission for location with three options. The user has to pick 'While using this app'. Then if the user picks that one, the user will get ANOTHER dialog with three MORE options. It is in this last dialog where the 'Allow all the time' shows up. That set of dialogs and their contents is likely to change to become even MORE confusing to the user as the versions go up.Weighting
Can you please post the code? That will help me a lot.Monda
@DevendraSingh I am a little embarrassed to post my code because it sucks. I am sure a good Java programmer would do it much better. In any case, I will add what I have in my 'answer'.Weighting
H
3

To access location in background on device having android API level 29 or higher, you also need to add below permission in the manifest file.

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>

You can keep all three of them or you can also remove either ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION but one of them mandatorily need to be there in Manifest file.

Once you have added these, you need to check in the code at some place if we have access to all of these permissions by below code block. If not, you'll need to request for the permissions by building an array of all of them and with a integer based request code :

if (requireContext().checkSelfPermission(PERMISSION_NAME_1) != PackageManager.PERMISSION_DENIED && requireContext().checkSelfPermission(PERMISSION_NAME_2) != PackageManager.PERMISSION_DENIED ...) {
    requestPermissions(@NonNull String[] permissions, int requestCode)
Hungry answered 8/9, 2020 at 10:20 Comment(1)
Note: This is a hard restricted permission which cannot be held by an app until the installer on record whitelists the permission. For more details see PackageInstaller.SessionParams.setWhitelistedRestrictedPermissions(Set).Pulverulent
Y
1

As @Brian Reinhold said in its answer, putting ACCESS_BACKGROUND_LOCATION in the manifest is not sufficient to make the "Allow all the time". option displayed in the permission popup. What you have to to is to require ACCESS_BACKGROUND_LOCATION permission explicitly in your code, something like:

With EasyPermissions library:

if (!EasyPermissions.hasPermissions(requireContext(), *perms)) {
  val builder = PermissionRequest
                .Builder(this, REQUEST_LOCATION_PERMISSION, *perms)
                .setRationale(getString(R.string.location_disclaimer))
                
                EasyPermissions.requestPermissions(builder.build())
}

companion object {
   var perms = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                arrayOf(
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_BACKGROUND_LOCATION)
   } else {
       arrayOf(Manifest.permission.ACCESS_FINE_LOCATION)
   }
}
Yorgen answered 28/8, 2020 at 10:29 Comment(0)
H
1

as other answer said, you have to use

 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>

But also you have to request manually for this permission for the user allow it. In ionic cordova you can do it like:

const accessFineLocationPermission = await this.permissions.checkPermission(this.permissions.PERMISSION.ACCESS_FINE_LOCATION)
if (accessFineLocationPermission && !accessFineLocationPermission.hasPermission) {
  await this.permissions.requestPermission(this.permissions.PERMISSION.ACCESS_FINE_LOCATION)
}

using the android permission cordova plugin: https://ionicframework.com/docs/native/android-permissions

You have to request the ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION and ACCESS_BACKGROUND_LOCATION.

Harriman answered 13/10, 2020 at 11:57 Comment(0)
R
1

Two type's of Android permissions required for location access:

  1. Foreground permission(Allow only while using the app) for Foreground location
  2. Background permission(Allow all the time) for Background location

If your app request for Background permission, the requests should follows:

  • At first, make request for foreground location access.
  • And then you can request background location access.

Note: It's recommended that, disable user access for background location until your app has foreground location access.

So how to access Background permission:

Step1: Declare these permissions on manifest.

<manifest>
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
</manifest>

Step2: Check runtime permission

   if (ActivityCompat.checkSelfPermission(
            this,
            Manifest.permission.ACCESS_FINE_LOCATION
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        // Request for Foreground permission
        ActivityCompat.requestPermissions(
            this@YourActivity,
            arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
            FINE_LOCATION_REQUEST_CODE
        )
    } else {

        // Request for Background permission
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            ActivityCompat.requestPermissions(
                this@MainActivity,
                arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
                BACKGROUND_REQUEST_CODE
            )
        }
    }
Reinold answered 3/4, 2021 at 14:49 Comment(3)
I tried this but still I'm not getting allow all time. It is showing keep while app in use only.Monda
@DevendraSingh you may want to try my ugly code above . I did not find it straight forward. You may have Android 11 which requires two passes from your activity. Ridiculous.Weighting
That being said make sure your Android Manifest has the permissions as well!Weighting
T
1

I found a solution for this. It seems to me that for some reason, Google doesn't allow you to directly call the ACCESS_BACKGROUND_LOCATION screen where there is the option to "allow all the time".

It's a bit confusing, but you must follow the steps below so that the screen only appears the first time the user asks for permission.

  1. Request foreground and accurate permissions first:
private fun showPermissionForegroundLocation() {
        ActivityCompat.requestPermissions(this,
            arrayOf(
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION,
            ),
            MY_PERMISSIONS_REQUEST_FOREGROUND_LOCATION
        )
}
  1. Add a function to your Activity to wait for the result of this permission and then open the allow screen all the time

@Deprecated("Deprecated in Java")
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        when (requestCode) {
            MY_PERMISSIONS_REQUEST_FOREGROUND_LOCATION -> {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    ActivityCompat.requestPermissions(this,
                        arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
                        MY_PERMISSIONS_REQUEST_BACKGROUND_LOCATION
                    )
                    return
                }
            }
        }
    }

And your screen will appear! Note that this is only possible once. Save this in sharedPreferences, and next time guide the user through ACTION_APPLICATION_DETAILS_SETTINGS, which is not the same thing, but at least it works to give the user direction

enter image description here

Thermosetting answered 12/3 at 15:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.