skip to Main Content

I have a simple app that has just 1 button in the activity and this is my MainActivity.kt file code:

    package ir.alirezapersonal.startup2
    
    import android.Manifest
    import android.content.pm.PackageManager
    import android.os.Build
    import android.os.Bundle
    import android.util.Log
    import androidx.activity.enableEdgeToEdge
    import androidx.annotation.RequiresApi
    import androidx.appcompat.app.AppCompatActivity
    import androidx.core.app.ActivityCompat
    import androidx.core.view.ViewCompat
    import androidx.core.view.WindowInsetsCompat
    import ir.alirezapersonal.startup2.databinding.ActivityMainBinding
    
    class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
            insets
        }

        binding.btnRequestPermissions.setOnClickListener {
            requestPermissions()
        }
    }

    private fun hasWriteExternalStoragePermission() =
        ActivityCompat.checkSelfPermission(this,
            Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED

    private fun hasLocationForegroundPermission() =
        ActivityCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED

    private fun hasLocationBackgroundPermission() =
        ActivityCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED

    private fun requestPermissions() {
        var permissionsToRequest = mutableListOf<String>()
        if(!hasWriteExternalStoragePermission()){
            permissionsToRequest.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
        }
        if(!hasLocationForegroundPermission()){
            permissionsToRequest.add(Manifest.permission.ACCESS_COARSE_LOCATION)
        }
        if (!hasLocationBackgroundPermission()){
            permissionsToRequest.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
        }

        if(permissionsToRequest.isNotEmpty()){
            ActivityCompat.requestPermissions(this, permissionsToRequest.toTypedArray(),0)
        }
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if(requestCode == 0 && grantResults.isNotEmpty()){
            for(i in grantResults.indices){
                if(grantResults[i] == PackageManager.PERMISSION_GRANTED){
                    Log.d("PermissionRequest", "${permissions[i]} granted.")
                } else {
                    Log.d("PermissionRequest", "${permissions[i]} NOT granted.")
                }
            }
        }
    }
}

the problem is that when i click on the button the permission request is not prompted to the user. i have also addded permissions list in my manifest file:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

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

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Startup2"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

i am also tested this app on an android 13 and 14 device but didn’t solve the problem.

what could be the problem?

2

Answers


  1. WRITE_EXTERNAL_STORAGE

    https://developer.android.com/reference/android/Manifest.permission#WRITE_EXTERNAL_STORAGE

    If your app targets Build.VERSION_CODES.R or higher, this permission has no effect.

    If your app is on a device that runs API level 19 or higher, you don’t need to declare this permission to read and write files in your application-specific directories returned by Context.getExternalFilesDir(String) and Context.getExternalCacheDir().


    ACCESS_BACKGROUND_LOCATION

    https://developer.android.com/reference/android/Manifest.permission#ACCESS_BACKGROUND_LOCATION

    Allows an app to access location in the background. If you’re requesting this permission, you must also request either ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION. Requesting this permission by itself doesn’t give you location access.

    Login or Signup to reply.
  2. It looks like you’ve implemented most of the necessary code for requesting permissions, But still you can check below updated example.

    Let’s revise the code to ensure permissions are requested correctly and the permission dialog appears. We’ll provide complete working code to handle permissions for all relevant Android versions.

    Updated MainActivity.kt

    This code handles permissions for Android versions 6.0 (API 23) and above. It includes proper handling for WRITE_EXTERNAL_STORAGE, ACCESS_FINE_LOCATION, and ACCESS_BACKGROUND_LOCATION.

    package ir.alirezapersonal.startup2
    
    import android.Manifest
    import android.content.pm.PackageManager
    import android.os.Build
    import android.os.Bundle
    import android.util.Log
    import androidx.activity.ComponentActivity
    import androidx.activity.result.contract.ActivityResultContracts
    import androidx.core.app.ActivityCompat
    import androidx.core.content.ContextCompat
    import ir.alirezapersonal.startup2.databinding.ActivityMainBinding
    
    class MainActivity : ComponentActivity() {
    
        private lateinit var binding: ActivityMainBinding
    
        private val permissionRequestLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
            permissions.entries.forEach {
                val permission = it.key
                val granted = it.value
                if (granted) {
                    Log.d("PermissionRequest", "$permission granted.")
                } else {
                    Log.d("PermissionRequest", "$permission NOT granted.")
                }
            }
        }
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            binding = ActivityMainBinding.inflate(layoutInflater)
            setContentView(binding.root)
    
            binding.btnRequestPermissions.setOnClickListener {
                requestPermissions()
            }
        }
    
        private fun hasWriteExternalStoragePermission() =
            ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
    
        private fun hasLocationForegroundPermission() =
            ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
    
        private fun hasLocationBackgroundPermission() =
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED
            } else {
                true // Background location permission is not required for devices below Android 10
            }
    
        private fun requestPermissions() {
            val permissionsToRequest = mutableListOf<String>()
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (!hasWriteExternalStoragePermission()) {
                    permissionsToRequest.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                }
                if (!hasLocationForegroundPermission()) {
                    permissionsToRequest.add(Manifest.permission.ACCESS_FINE_LOCATION)
                }
                if (!hasLocationBackgroundPermission()) {
                    permissionsToRequest.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
                }
    
                if (permissionsToRequest.isNotEmpty()) {
                    permissionRequestLauncher.launch(permissionsToRequest.toTypedArray())
                }
            }
        }
    }
    

    Manifest File AndroidManifest.xml

    Ensure that you include all necessary permissions in your manifest

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">
    
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
        <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    
        <application
            android:allowBackup="true"
            android:dataExtractionRules="@xml/data_extraction_rules"
            android:fullBackupContent="@xml/backup_rules"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/Theme.Startup2"
            tools:targetApi="31">
            <activity
                android:name=".MainActivity"
                android:exported="true">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>
    
    • Permission Request: Uses
      ActivityResultContracts.RequestMultiplePermissions() to handle
      permission requests.
    • Permission Check: The methods hasWriteExternalStoragePermission(),
      hasLocationForegroundPermission(), and
      hasLocationBackgroundPermission() check if permissions are granted.
    • Android Version Handling: The code ensures that the permission
      request flow is handled correctly based on Android version. For
      Android 10 and above, it handles background location permissions
      separately.

    For Testing :

    • Ensure you test on both physical devices and emulators with different
      API levels to confirm the permission dialogs are shown correctly.
    • For devices running Android 10 (API 29) and above, ensure that you
      handle background location permissions properly, as it requires
      separate handling compared to foreground permissions.

    Updated

    Additionally if above not work then check below one

    This code includes the corrected requestPermissions function tohandle background location permission correctly, along with the other necessary methods and setup for handling permissions in your MainActivity.

    package ir.alirezapersonal.startup2
    
    import android.Manifest
    import android.content.pm.PackageManager
    import android.os.Bundle
    import android.util.Log
    import androidx.activity.enableEdgeToEdge
    import androidx.appcompat.app.AppCompatActivity
    import androidx.core.app.ActivityCompat
    import androidx.core.view.ViewCompat
    import androidx.core.view.WindowInsetsCompat
    import ir.alirezapersonal.startup2.databinding.ActivityMainBinding
    
    class MainActivity : AppCompatActivity() {
    
        private lateinit var binding: ActivityMainBinding
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            enableEdgeToEdge()
            binding = ActivityMainBinding.inflate(layoutInflater)
            setContentView(binding.root)
            ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
                val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
                v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
                insets
            }
    
            binding.btnRequestPermissions.setOnClickListener {
                requestPermissions()
            }
        }
    
        private fun hasWriteExternalStoragePermission() =
            ActivityCompat.checkSelfPermission(this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
    
        private fun hasLocationForegroundPermission() =
            ActivityCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
    
        private fun hasLocationBackgroundPermission() =
            ActivityCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED
    
        private fun requestPermissions() {
            val permissionsToRequest = mutableListOf<String>()
            if (!hasWriteExternalStoragePermission()) {
                permissionsToRequest.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
            }
            if (!hasLocationForegroundPermission()) {
                permissionsToRequest.add(Manifest.permission.ACCESS_COARSE_LOCATION)
                permissionsToRequest.add(Manifest.permission.ACCESS_FINE_LOCATION)
            }
            if (permissionsToRequest.isNotEmpty()) {
                ActivityCompat.requestPermissions(this, permissionsToRequest.toTypedArray(), 0)
            } else if (!hasLocationBackgroundPermission()) {
                // Request background location separately
                ActivityCompat.requestPermissions(this,
                    arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION), 1)
            }
        }
    
        override fun onRequestPermissionsResult(
            requestCode: Int,
            permissions: Array<out String>,
            grantResults: IntArray
        ) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults)
            if (requestCode == 0 && grantResults.isNotEmpty()) {
                for (i in grantResults.indices) {
                    if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                        Log.d("PermissionRequest", "${permissions[i]} granted.")
                    } else {
                        Log.d("PermissionRequest", "${permissions[i]} NOT granted.")
                    }
                }
            } else if (requestCode == 1 && grantResults.isNotEmpty()) { 
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Log.d("PermissionRequest", "${permissions[0]} granted.")
                } else {
                    Log.d("PermissionRequest", "${permissions[0]} NOT granted.")
                }
            }
        }
    }
    

    This code should cover the permissions correctly for all versions of Android that you’re targeting.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search