Android Request ACCESS_MEDIA_LOCATION Permission

January 13, 2020

You would usually need READ_EXTERNAL_STORAGE as well, so this sample code shows how to get both permissions.

NOTE: Refer to Get Photo Gps Location With Android 10 Scoped Storage.

Edit AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest ...>

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

    ...
</manifest>

Edit Module:app build.gradle.

compileSdkVersion 29
defaultConfig {
    ...

    targetSdkVersion 29

    ...
}

Fragment

class TestPermissionFragment : Fragment() {

    companion object {
        private const val REQUEST_STORAGE_PERMISSION = 1
        private const val REQUEST_MEDIA_LOCATION_PERMISSION = 2
    }


    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.test_permission, container, false)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)


        if (hasStoragePermission()) {
            if (hasMediaLocationPermission()) {
                findImagesWithGpsInGallery(context!!.contentResolver)
            }                                }
            else {
                requestMediaLocationPermission()
            }
        }
        else {
            requestStoragePermission()
        }
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        // super.onRequestPermissionsResult(requestCode, permissions, grantResults)

        when(requestCode) {
            REQUEST_STORAGE_PERMISSION -> {
                if (grantResults.isNotEmpty() && grantResults[0] == PERMISSION_GRANTED) {
                    findAlbumsInPhotoGallery(context!!.contentResolver)
                }
                else {
                    val showRational =
                        ActivityCompat.shouldShowRequestPermissionRationale(
                            activity!!,
                            Manifest.permission.READ_EXTERNAL_STORAGE
                        )

                    if (showRational) {
                        Timber.d("Storage permission denied")
                    }
                    else {
                        Intent(ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:${activity!!.packageName}")).apply {
                            addCategory(Intent.CATEGORY_DEFAULT)
                            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                        }.also { intent ->
                            startActivity(intent)
                        }
                    }
                }
            }
            REQUEST_MEDIA_LOCATION_PERMISSION -> {
                if (grantResults.isNotEmpty() && grantResults[0] == PERMISSION_GRANTED) {
                    viewModel.initGalleryMediaQquery(contentResolver)
                    initGalleryList()
                }
                else {
                    val showRational =
                        ActivityCompat.shouldShowRequestPermissionRationale(
                            activity!!,
                            Manifest.permission.ACCESS_MEDIA_LOCATION
                        )

                    if (showRational) {
                        viewModel.toastMessageEvent.value = Event(TextResourceString("Media Location permission denied"))
                    }
                    else {
                        Intent(ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:${activity!!.packageName}")).apply {
                            addCategory(Intent.CATEGORY_DEFAULT)
                            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                        }.also { intent ->
                            startActivity(intent)
                        }
                    }
                }
            }
        }
    }

    private fun hasStoragePermission() = ContextCompat.checkSelfPermission(
        context!!,
        Manifest.permission.READ_EXTERNAL_STORAGE
    ) == PERMISSION_GRANTED

    private fun requestStoragePermission() {
        if (!hasStoragePermission()) {
            val permissions = arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE)
            ActivityCompat.requestPermissions(activity!!, permissions, REQUEST_STORAGE_PERMISSION)
        }
    }

    private fun hasMediaLocationPermission(): Boolean {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            // this condition is not true for below Android Q
            ContextCompat.checkSelfPermission(
                context!!,
                Manifest.permission.ACCESS_MEDIA_LOCATION
            ) == PERMISSION_GRANTED
        }
        else true

    }

    private fun requestMediaLocationPermission() {
        if (!hasMediaLocationPermission()) {
            val permissions = arrayOf(Manifest.permission.ACCESS_MEDIA_LOCATION)
            ActivityCompat.requestPermissions(activity!!, permissions,
                REQUEST_MEDIA_LOCATION_PERMISSION
            )
        }
    }

    private fun findImagesWithGpsInGallery(contentResolver: ContentResolver) {
        // run code which require READ_EXTERNAL_STORAGE and REQUEST_MEDIA_LOCATION_PERMISSION permission

    }
}

NOTE: This is probably a better way to request 2 permissions in one function call, but the above work and I prefer the separation in code (in case I want to implement storage permission as mandatory while media location permission as optional)

NOTE: Android 10 prompt for user approval when requesting READ_EXTERNAL_STORAGE permission, but not UI is shown when requesting REQUEST_MEDIA_LOCATION_PERMISSION (as if auto approval as long as the request is made). I tested on a real Android 10 device and Android 10 emulator.

This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.