Permission Handling - Android Studio - Compose

How to handle single & multiple runtime permissions

As we know we need to request Runtime Permissions on Android 6.0 (API level 23 also known as Marshmallow) and above as well as to declare them in the AndroidManifest file.  If we need to use some features like Camera, Location, Contact, etc. we have to handle the runtime permissions. In this Tutorial, we will learn how to Request Single and Multiple Permissions.

Note: I'll add some permissions for example purposes only you may apply the same on permissions you want.


Code

AndroidManfiest.xml

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

    <!--For Single Permission Example-->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <!--For Multiple Permission Example-->
    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.CALL_PHONE"/>

    <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.MyApplication">
        <activity
            android:name=".MainActivityCompose"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>

MainActivity.kt

package com.technifysoft.myapplication

import android.Manifest
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.compose.setContent
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.technifysoft.myapplication.ui.theme.MyApplicationTheme


/**
 * MainActivityCompose is the main activity of the application, responsible for setting up the UI.
 */
class MainActivityCompose : ComponentActivity() {

    /**
     * Called when the activity is first created. This is where you should do all of your normal static set up:
     * create views, bind data to lists, etc. This method also provides you with a Bundle containing the activity's
     * previously frozen state, if there was one.
     */
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyApplicationTheme {

                Scaffold(
                    modifier = Modifier.fillMaxSize(),
                ) { innerPadding ->
                    ReceiptScreen(innerPadding)
                }

            }
        }
    }
}

@Composable
fun ReceiptScreen(innerPadding: PaddingValues) {
    val TAG = "PERMISSIONS_TAG"
    val context = LocalContext.current
    var resultText by remember { mutableStateOf("Result") }

    // Single permission launcher
    val singlePermissionLauncher = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.RequestPermission()
    ) { isGranted ->
        Log.d(TAG, "Single Permission granted: $isGranted")
        if (isGranted) {
            resultText = "Single Permission granted. You can do your tasks..."
        } else {
            Toast.makeText(context, "Permission denied...", Toast.LENGTH_SHORT).show()
        }
    }

    // Multiple permissions launcher
    val multiplePermissionLauncher = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.RequestMultiplePermissions()
    ) { permissions ->
        var allGranted = true
        permissions.entries.forEach { entry ->
            Log.d(TAG, "${entry.key} granted: ${entry.value}")
            allGranted = allGranted && entry.value
        }
        if (allGranted) {
            resultText = "All Permissions granted. You can do your tasks..."
        } else {
            Toast.makeText(context, "All or some permissions denied...", Toast.LENGTH_SHORT).show()
        }
    }

    // UI Layout
    Column(
        modifier = Modifier.fillMaxSize().padding(20.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        // Title
        Text(
            text = "Permission handling",
            style = MaterialTheme.typography.headlineMedium
        )

        Spacer(modifier = Modifier.height(20.dp))

        // Single permission button
        Button(
            onClick = {
                singlePermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
            },
            modifier = Modifier.fillMaxWidth()
        ) {
            Text("Single Permission Request")
        }

        Spacer(modifier = Modifier.height(10.dp))

        // Multiple permissions button
        Button(
            onClick = {
                multiplePermissionLauncher.launch(
                    arrayOf(
                        Manifest.permission.CAMERA,
                        Manifest.permission.RECORD_AUDIO,
                        Manifest.permission.CALL_PHONE
                    )
                )
            },
            modifier = Modifier.fillMaxWidth()
        ) {
            Text("Multiple Permission Request")
        }

        Spacer(modifier = Modifier.height(20.dp))

        // Result text
        Text(text = resultText)
    }
}

/**
 * GreetingPreview is a composable function for previewing the MainUI in Android Studio.
 * It is annotated with @Preview to enable live preview.
 *
 */
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    MyApplicationTheme {
        ReceiptScreen(PaddingValues())
    }
}

Screenshots

Permission Handling - Android Studio - ComposePermission Handling - Android Studio - ComposePermission Handling - Android Studio - Compose


Comments

Popular posts from this blog

Picture In Picture | Android Studio | Kotlin

Manage External Storage Permission | Android Studio | Kotlin

How to add AIDL folder | Android Studio