DEV Community

Elozino Ovedhe
Elozino Ovedhe

Posted on

1

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

Sentry mobile image

App store rankings love fast apps - mobile vitals can help you get there

Slow startup times, UI hangs, and frozen frames frustrate users—but they’re also fixable. Mobile Vitals help you measure and understand these performance issues so you can optimize your app’s speed and responsiveness. Learn how to use them to reduce friction and improve user experience.

Read full post →

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay