Search code examples
androidgeolocationandroid-permissions

Android 12 not showing correct permissions request screen


My app requires precise user location because it requires the user to be at specific locations to perform tasks. I have followed the documentation for the proper way to request both ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION together.

class LocationChooserFragment : BottomSheetDialogFragment() {
    // only relevant parts shown

    /**
     * A utility class that holds all the code for requesting location updates,
     * so that we can re-use it in multiple fragments.
     */
    private var locationTracker: LocationTracker? = null

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        // all the other initialization for viewbinding

        tryToGetLocationUpdates()
    }

    private fun tryToGetLocationUpdates() {
        val request = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
            if (permissions[Manifest.permission.ACCESS_FINE_LOCATION] == true && permissions[Manifest.permission.ACCESS_FINE_LOCATION] == true) {
                requestLocationUpdates()
            }
        }

        when {
            ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
            ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED -> {
                Timber.i("Already have required permissions")
                requestLocationUpdates()
            }
            shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION) ||
            shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_COARSE_LOCATION) -> {
                Timber.i("Showing permission rationale dialog")
                // A wrapper to show a dialog that explains what we need permissions for
                alertDialog(
                    title = getString(R.string.permissions),
                    msg = getString(R.string.why_we_need_location),
                    onClick = { yes ->
                        if (yes) {
                            request.launch(arrayOf(
                                Manifest.permission.ACCESS_FINE_LOCATION,
                                Manifest.permission.ACCESS_COARSE_LOCATION
                            ))
                        }
                    }
                )
            }
            else -> {
                Timber.i("Prompting for location permissions")
                request.launch(arrayOf(
                    Manifest.permission.ACCESS_FINE_LOCATION,
                    Manifest.permission.ACCESS_COARSE_LOCATION
                ))
            }
        }
    }

    private fun requestLocationUpdates() {
        if (locationProvider == null) {
            locationProvider = LocationProvider(requireContext())
        }
        locationProvider?.requestLocationUpdates()
    }
}

The problem I have is that my users are not getting prompted to allow precise location.

I expect to see the prompt in Figure 3 from the documentation:

Figure 3

Figure 3. System permissions dialog that appears when your app requests both ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION in a single runtime request.

Instead, I see the prompt in Figure 2 from the documentation:

Figure 2

Figure 2. System permissions dialog that appears when your app requests ACCESS_COARSE_LOCATION only.

Additionally, I expect that when I already have COARSE permission and I request FINE and COARSE permission again, I should see the "Upgrade to Precise permission" dialog, but I don't see any prompt at all.

I have tested this on Pixel 3a (physical device and emulator) as well as received reports from other users on various Pixel and Samsung Galaxy devices that are running Android 12.

The problem was not present when we used compileSdk 30 and targetSdkVersion 30 in build.gradle, but we need to be able to support new features and new versions of Android (and to be able to upgrade to dependencies that only support building with newer SDK versions.

Why is the permission dialog not showing properly?


Solution

  • Comparing my AndroidManifest.xml to the generated file in the built app (using the "Analyze APK" feature in Android Studio), I discovered that the generated APK file had the following entry:

    <uses-permission
        android:name="android.permission.ACCESS_FINE_LOCATION"
        android:maxSdkVersion="30" />
    

    Clearly, the maxSdkVersion is preventing the OS from giving me the permission I need.

    Using grep on the app\build directory, I found app\build\intermediates\manifest_merge_blame_file\appnameDebug\manifest-merger-blame-appname-debug-report.txt, which included these lines:

    17    <uses-permission
    17-->C:\path\to\my\appname\app\src\main\AndroidManifest.xml:12:2-76
    18        android:name="android.permission.ACCESS_FINE_LOCATION"
    18-->C:\path\to\my\appname\app\src\main\AndroidManifest.xml:12:19-73
    19        android:maxSdkVersion="30" />
    19-->[com.github.50ButtonsEach:flic2lib-android:1.3.1] C:\Users\moshe\.gradle\caches\transforms-3\dced3886509296f1029e8245af379a07\transformed\jetified-flic2lib-android-1.3.1\AndroidManifest.xml:17:9-35
    

    It turns out the developers of this library originally used ACCESS_FINE_LOCATION for connecting to nearby Bluetooth devices, and since Android 12 has separate permissions for that, they don't need it anymore so they added a max SDK version.

    I added the tools:remove="android:maxSdkVersion" property to the ACCESS_FINE_LOCATION <uses-permission /> element, and now my permissions work properly.