androidgpsandroid-permissionsandroid-locationandroid-14

Android 14 - ACCESS_FINE_LOCATION never asked nor granted


my Manifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus"/>
    <uses-feature android:name="android.hardware.location.gps" />

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application
    ....
        <service
            android:name=".service.LocationService"
            android:enabled="true"
            android:exported="false"
            android:foregroundServiceType="location"
            android:stopWithTask="true"/>
    </application>

</manifest>

Then my code for requesting permissions in my Main activity is as follows:

 ActivityResultLauncher<String[]> permissionRequest =
        registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), result -> {
            boolean hasAllPermissions = true;
            for (Boolean value : result.values()) {
                hasAllPermissions = hasAllPermissions && value;
            }
            if (hasAllPermissions){
                startLocationService();
            }
            else {
                needsPermissionsDialog.show();
            }
        });

    private void checkPermissions() {
        permissionRequest.launch(new String[]{
                Manifest.permission.INTERNET,
                Manifest.permission.ACCESS_NETWORK_STATE,
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.POST_NOTIFICATIONS,
                Manifest.permission.CAMERA,
                Manifest.permission.ACCESS_BACKGROUND_LOCATION,
                Manifest.permission.FOREGROUND_SERVICE,
                Manifest.permission.FOREGROUND_SERVICE_LOCATION
        });
    }
    private void startLocationService(){
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            if (locationService == null) {
                Intent locationServiceIntent = new Intent(MainActivity.this, LocationService.class);
                startForegroundService(locationServiceIntent);
                bindService(locationServiceIntent, locationServiceConnection, 0);
            }
        }
        else {
            Toast.makeText(this, "Missing location permission", Toast.LENGTH_SHORT).show();
        }
    }

The checkPermissions() function is called after a return from the app login screen (what is a simple pin code unlocking screen). I have also tried put the call into the onCreate() and onStart() methods as the first step, but made no difference. The behavior is all the same, all the time. Never been able to grant FINE_LOCATION persmissions

 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
      
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == LOGIN_ACTIVITY_REQUEST) {
            if (resultCode == RESULT_OK) {
                checkPermissions();
                ...

On older android it works 100% with no problems, the service is started, I can bind to it, and get location updates. On Android 14 however ActivityResultContracts.RequestMultiplePermissions() result has false for the ACCESS_FINE_LOCATION permission. When I turn off the permission in the (android) settings for the app, it asks for the permission (see image) but it only grants it for the ACCESS_BACKGROUND_LOCATION, and the ACCESS_FINE_LOCATION result still remains false.

If I remove the ACCESS_BACKGROUND_LOCATION from the manifest, the Location permission option in the (android) settings for the app is gone. If remove it from the permissionRequest.launch() list, I do not get any prompt to allow location access.

It also does not matter If I add/replace FINE with ACCESS_COARSE_LOCATION anywhere (list or manifest). It also always gets false as a result.

All other permission requesting dialogs work fine.

The problem was replicated on 2 Xiaomi and 1 Pixel device, so it is not even device specific.

enter image description here

P.S. I know this is my 3rd question in this topic, but this is also my 3rd implementation, And still no result.


Solution

  • Try to implement the way google suggests :

    First request for COARSE and FINE location permission once that is granted then only request for ACCESS_BACKGROUND_LOCATION. That is only allow by navigating to permission setting of app.

    public static void requestPermissions(Activity activity) {
        // Request foreground permissions first
        String[] foregroundPermissions = new String[]{
                Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.ACCESS_FINE_LOCATION
        };
    
        ActivityCompat.requestPermissions(activity, foregroundPermissions, REQUEST_FOREGROUND_PERMISSIONS);
    }
    
    private static final int REQUEST_FOREGROUND_PERMISSIONS = 1;
    
    public static void onRequestPermissionsResult(Activity activity, int requestCode, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, requestCode, grantResults);
        if (requestCode == REQUEST_FOREGROUND_PERMISSIONS) {
            if (hasPermissions(activity, foregroundPermissions)) {
                // Permissions granted, check for Android version and request background permission if needed
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    String[] backgroundPermission = new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION};
                    ActivityCompat.requestPermissions(activity, backgroundPermission, REQUEST_BACKGROUND_PERMISSION);
                } else {
                    showBackgroundLocationControls(activity);
                }
            } else {
                Toast.makeText(activity, "Location permission denied", Toast.LENGTH_SHORT).show();
            }
        } else if (requestCode == REQUEST_BACKGROUND_PERMISSION) {
            if (hasPermissions(activity, new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION})) {
                // Implement your logic to show BackgroundLocationControls here
            } else {
                Toast.makeText(activity, "Background location permission denied", Toast.LENGTH_SHORT).show();
            }
        }
    }
    
    private static boolean hasPermissions(Activity activity, String[] permissions) {
        for (String permission : permissions) {
            if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }
    

    Please read this post completely and try to implement the same way and this link.

    enter image description here

    Note: The Google Play Store has a location policy concerning device location, restricting background location access to apps that need it for their core functionality and meet related policy requirements.

    ACCESS_BACKGROUND_LOCATION popup :

    enter image description here

    In attribution from - https://www.paget96projects.com/guides/android-app-background-location-permission-and-play-store#google_vignette


    If you still face any problem refer to this package.

    https://github.com/android/platform-samples/tree/main/samples/location/src/main/java/com/example/platform/location/permission