Skip to main content
Version: v5

Background Location

The entire Activity code is shown, in order to provide context for the permission specific methods.

class MainActivity : AppCompatActivity() {    private var pkgManager: PackageManager? = null    private var shouldRequestBackgroundPermission = false    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_main)        pkgManager = applicationContext.packageManager    }
    fun requestLocationPermission(view: View?) {        val hasPreciseLocation = checkPermissionStatus(Manifest.permission.ACCESS_FINE_LOCATION)        val hasApproximateLocation = checkPermissionStatus(Manifest.permission.ACCESS_COARSE_LOCATION)        if (!hasPreciseLocation && !hasApproximateLocation) {            showLocationDisclosure(false)        }    }
    fun requestBackgroundLocationPermission(view: View?) {        if (isBackgroundLocationPermissionAvailable) {            val hasPreciseLocation = checkPermissionStatus(Manifest.permission.ACCESS_FINE_LOCATION)            val hasApproximateLocation = checkPermissionStatus(Manifest.permission.ACCESS_COARSE_LOCATION)            if (!hasPreciseLocation && !hasApproximateLocation) {                shouldRequestBackgroundPermission = true                showLocationDisclosure(true)            } else {                requestPermissions(Manifest.permission.ACCESS_BACKGROUND_LOCATION)            }        }    }
    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {        if (requestCode == PERMISSIONS_REQUEST_CODE && permissions.isNotEmpty()) {            var permission = permissions[0]            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {                if (isBackgroundLocationPermissionAvailable && shouldRequestBackgroundPermission && isLocationPermission(permission)) {                    requestPermissions(Manifest.permission.ACCESS_BACKGROUND_LOCATION)                }            } else if (grantResults.size > 1 && grantResults[1] == PackageManager.PERMISSION_GRANTED) {                permission = permissions[1]                if (isBackgroundLocationPermissionAvailable && shouldRequestBackgroundPermission && isLocationPermission(permission)) {                    requestPermissions(Manifest.permission.ACCESS_BACKGROUND_LOCATION)                }            }        }    }
    private fun requestPermissions(vararg permissions: String) {        permissions.forEach {            if (checkPermissionStatus(it)) {                return            }        }        val permission = permissions[0]        if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {            showPermissionRationale(rationaleTitleFromPermission(permission), rationaleMessageFromPermission(permission), *permissions)        } else {            ActivityCompat.requestPermissions(this, permissions,                PERMISSIONS_REQUEST_CODE)        }    }
    private fun rationaleTitleFromPermission(permission: String): Int {        return if (!isBackgroundLocationPermissionAvailable) {            R.string.location_title        } else when (permission) {            Manifest.permission.ACCESS_BACKGROUND_LOCATION -> R.string.background_location_title            Manifest.permission.ACCESS_FINE_LOCATION -> R.string.location_title            Manifest.permission.ACCESS_COARSE_LOCATION -> R.string.location_title            else -> R.string.location_title        }    }
    private fun rationaleMessageFromPermission(permission: String): Int {        return if (!isBackgroundLocationPermissionAvailable) {            R.string.location_message        } else when (permission) {            Manifest.permission.ACCESS_BACKGROUND_LOCATION -> R.string.background_location_message            Manifest.permission.ACCESS_FINE_LOCATION -> R.string.location_message            Manifest.permission.ACCESS_COARSE_LOCATION -> R.string.location_message            else -> R.string.location_message        }    }
    private fun showPermissionRationale(titleId: Int, messageId: Int, vararg permissions: String) {        AlertDialog.Builder(this)            .setTitle(titleId)            .setMessage(messageId)            .setNegativeButton(android.R.string.cancel) { dialog, _ -> dialog.dismiss() }            .setPositiveButton(android.R.string.ok) { dialog, _ ->                dialog.dismiss()                ActivityCompat.requestPermissions(this@MainActivity, permissions,                    PERMISSIONS_REQUEST_CODE)            }            .show()    }
    private fun showLocationDisclosure(requestBackground: Boolean) {        val backgroundPermissionOptionLabel = if (isBackgroundPermissionLabelAvailable) pkgManager!!.backgroundPermissionOptionLabel else getString(R.string.background_permission_label)        val alertDialogBuilder = AlertDialog.Builder(this)            .setTitle(R.string.background_location_title)            .setMessage(getString(R.string.location_disclosure_message, backgroundPermissionOptionLabel))            .setNegativeButton(android.R.string.cancel) { dialog, _ ->                shouldRequestBackgroundPermission = false                dialog.cancel()            }            .setPositiveButton(android.R.string.ok) { dialog, _ ->                dialog.dismiss()                shouldRequestBackgroundPermission = requestBackground                requestPermissions(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION)            }        alertDialogBuilder.show()    }
    private fun checkPermissionStatus(permission: String): Boolean {        return !shouldAskForPermissions() || ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED    }
    private fun shouldAskForPermissions(): Boolean {        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M    }
    private fun isLocationPermission(permission: String): Boolean {        return Manifest.permission.ACCESS_FINE_LOCATION == permission || Manifest.permission.ACCESS_COARSE_LOCATION == permission    }
    private val isBackgroundLocationPermissionAvailable: Boolean        get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q    private val isBackgroundPermissionLabelAvailable: Boolean        get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
    companion object {        private const val PERMISSIONS_REQUEST_CODE = 736    }}

Google Play Policy#

If your app uses background location permission, it is also necessary to fulfill a designated form in your Google Play console. Instructions can be found here.

important
If you have any questions or issues with this process, feel free to contact our team and we will provide support.