DEV Community

Elozino Ovedhe
Elozino Ovedhe

Posted on

Build a Flashlight in Jetpack Compose

Today we will discuss how to build a flashlight in Jetpack Compose.

Step-by-step Guide

  1. Setting up dependency
  2. Setting up Manifest
  3. Code Explanation
  4. Code Implementation

Setting up dependencies
We will be utilising Google's new API for permission requests in our app as it provides a more elegant way of requesting permission in our apps. Since it is a work in progress, there are some known limitations like not being able to check if the user is requesting the app for the first time etc. For more info, check this out

Now, in your build.gradle.kts or build.gradle file add the dependency

 // Dependency to request hardware permission
 implementation ("com.google.accompanist:accompanist-permissions:0.32.0")
Enter fullscreen mode Exit fullscreen mode

Setting up Manifest
In your AndroidManifest.xml file, add the code below inside your application tag

 <uses-feature
   android:name="android.hardware.camera"
   android:required="false" />
 <uses-permission android:name="android.permission.CAMERA" />
Enter fullscreen mode Exit fullscreen mode

Code Explanation

fun toggleFlashLight(cameraManager: CameraManager, cameraId: String, isFlashOn: Boolean) {
    try {
        cameraManager.setTorchMode(cameraId, isFlashOn)
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

fun handlePermissionDenied(context: Context) {
    Toast.makeText(context, "Please grant camera permission", Toast.LENGTH_LONG).show()
}

fun handlePermissionRationale(context: Context) {
    Toast.makeText(context, "Camera permission is needed", Toast.LENGTH_LONG).show()
}
Enter fullscreen mode Exit fullscreen mode
@OptIn(ExperimentalPermissionsApi::class)
fun handleLogic(
    cameraPermissionState: PermissionState,
    context: Context,
    cameraManager: CameraManager,
    cameraId: String,
    isFlashOn: Boolean,
    updateState: (Boolean) -> Unit,
) {
    if (cameraPermissionState.status.isGranted) {
        val newState = !isFlashOn
        updateState(newState)
        toggleFlashLight(cameraManager, cameraId, newState)
    } else if (cameraPermissionState.status.shouldShowRationale) {
        handlePermissionRationale(context)
        cameraPermissionState.launchPermissionRequest()
    } else {
        handlePermissionDenied(context)
        cameraPermissionState.launchPermissionRequest()
    }
}
Enter fullscreen mode Exit fullscreen mode

Code Implementation

import android.Manifest
import android.content.Context
import android.hardware.camera2.CameraManager
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ButtonDefaults
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.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.kotlin_articles.ui.theme.KotlinarticlesTheme
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.PermissionState
import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState
import com.google.accompanist.permissions.shouldShowRationale


class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            KotlinarticlesTheme {
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                    Greeting(
                        modifier = Modifier.padding(innerPadding)
                    )
                }
            }
        }
    }
}

@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun Greeting(modifier: Modifier = Modifier) {
    val context: Context = LocalContext.current
    val cameraPermissionState = rememberPermissionState(permission = Manifest.permission.CAMERA)
    var isFlashOn: Boolean by rememberSaveable {
        mutableStateOf(false)
    }
    val cameraManager: CameraManager = remember {
        context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
    }
    val cameraId: String = rememberSaveable {
        try {
            cameraManager.cameraIdList[0]
        } catch (e: Exception) {
            "0"
        }
    }

    Column(
        modifier = Modifier
            .fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center,
    ) {
        Button(
            modifier = Modifier.height(50.dp),
            onClick = {
                handleLogic(
                    cameraPermissionState,
                    context,
                    cameraManager,
                    cameraId,
                    isFlashOn
                ) { isFlashOn = it }
            },
        ) {
            Text(
                text = "Turn flashlight ${if (isFlashOn) "Off" else "On"} !",
                fontSize = 16.sp,
                textAlign = TextAlign.Center
            )
        }
    }
}

fun toggleFlashLight(cameraManager: CameraManager, cameraId: String, isFlashOn: Boolean) {
    try {
        cameraManager.setTorchMode(cameraId, isFlashOn)
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

fun handlePermissionDenied(context: Context) {
    Toast.makeText(context, "Please grant camera permission", Toast.LENGTH_LONG).show()
}

fun handlePermissionRationale(context: Context) {
    Toast.makeText(context, "Camera permission is needed", Toast.LENGTH_LONG).show()
}

@OptIn(ExperimentalPermissionsApi::class)
fun handleLogic(
    cameraPermissionState: PermissionState,
    context: Context,
    cameraManager: CameraManager,
    cameraId: String,
    isFlashOn: Boolean,
    updateState: (Boolean) -> Unit,
) {
    if (cameraPermissionState.status.isGranted) {
        val newState = !isFlashOn
        updateState(newState)
        toggleFlashLight(cameraManager, cameraId, newState)
    } else if (cameraPermissionState.status.shouldShowRationale) {
        handlePermissionRationale(context)
        cameraPermissionState.launchPermissionRequest()
    } else {
        handlePermissionDenied(context)
        cameraPermissionState.launchPermissionRequest()
    }
}

Enter fullscreen mode Exit fullscreen mode

Happy coding!!!

You can check out the repo

Top comments (0)