How to Make a Flashlight App in Android Studio
The best first Android project. Complete working code for a torch app, with runtime permissions, lifecycle handling and the device quirks that break it.
A flashlight app is the right first Android project. It is small enough to finish in an evening, but it still teaches the four things every Android app needs: layouts, permissions, hardware access and lifecycle.
All the code is here. Copy it, run it, then change it.
What you need
- Android Studio — any recent version
- A real phone. The emulator has no flash, so the app will look broken there. Use a phone with USB debugging on.
- No prior experience. Everything is explained.
Step 1: Create the project
File → New → New Project → Empty Views Activity.
- Name: Flashlight
- Package name:
com.yourname.flashlight— must be unique on the Play Store - Language: Java or Kotlin, both are below
- Minimum SDK: API 24 (Android 7.0), which covers almost every phone in use
The first build downloads a lot through Gradle. Leave it alone until it finishes.
Step 2: Ask for the camera permission
The torch is part of the camera hardware, so the app needs camera permission even though it never takes a photo.
Open AndroidManifest.xml and add these two lines above <application>:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.flash" android:required="true" />
uses-feature with required="true" tells the Play Store to hide the app from devices with no flash. Without it, people on tablets install it, it does nothing, and you get one-star reviews.
Step 3: Build the layout
Replace res/layout/activity_main.xml with this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:background="#111827">
<TextView
android:id="@+id/statusText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Torch is off"
android:textColor="#9CA3AF"
android:textSize="18sp"
android:layout_marginBottom="32dp" />
<Button
android:id="@+id/toggleButton"
android:layout_width="200dp"
android:layout_height="200dp"
android:text="TURN ON"
android:textSize="20sp"
android:textStyle="bold" />
</LinearLayout>
One big button in the middle. That is the whole interface, and for this app that is correct — a torch should be one tap, not a menu.
Step 4: The code
This is the part that matters. We use CameraManager.setTorchMode(), which is the modern API and works on Android 6.0 and above.
Java
package com.yourname.flashlight;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraManager;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
public class MainActivity extends AppCompatActivity {
private CameraManager cameraManager;
private String cameraId;
private boolean isOn = false;
private Button toggleButton;
private TextView statusText;
private static final int CAMERA_REQUEST = 100;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toggleButton = findViewById(R.id.toggleButton);
statusText = findViewById(R.id.statusText);
cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
// Find the camera that actually has a flash — usually the back one,
// but never assume it is camera 0.
try {
for (String id : cameraManager.getCameraIdList()) {
Boolean hasFlash = cameraManager.getCameraCharacteristics(id)
.get(android.hardware.camera2.CameraCharacteristics.FLASH_INFO_AVAILABLE);
if (Boolean.TRUE.equals(hasFlash)) { cameraId = id; break; }
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
if (cameraId == null) {
statusText.setText("This device has no flash");
toggleButton.setEnabled(false);
return;
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CAMERA}, CAMERA_REQUEST);
}
toggleButton.setOnClickListener(v -> toggleTorch());
}
private void toggleTorch() {
try {
isOn = !isOn;
cameraManager.setTorchMode(cameraId, isOn);
toggleButton.setText(isOn ? "TURN OFF" : "TURN ON");
statusText.setText(isOn ? "Torch is on" : "Torch is off");
} catch (CameraAccessException e) {
Toast.makeText(this, "Could not access the torch", Toast.LENGTH_SHORT).show();
isOn = false;
}
}
@Override
protected void onPause() {
super.onPause();
// Leaving the torch on in the background drains the battery and
// can overheat the LED. Always switch it off.
if (isOn) { toggleTorch(); }
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == CAMERA_REQUEST
&& (grantResults.length == 0 || grantResults[0] != PackageManager.PERMISSION_GRANTED)) {
Toast.makeText(this, "Camera permission is needed for the torch",
Toast.LENGTH_LONG).show();
toggleButton.setEnabled(false);
}
}
}
Kotlin
package com.yourname.flashlight
import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraManager
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
class MainActivity : AppCompatActivity() {
private lateinit var cameraManager: CameraManager
private var cameraId: String? = null
private var isOn = false
private lateinit var toggleButton: Button
private lateinit var statusText: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
toggleButton = findViewById(R.id.toggleButton)
statusText = findViewById(R.id.statusText)
cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager
cameraId = cameraManager.cameraIdList.firstOrNull { id ->
cameraManager.getCameraCharacteristics(id)
.get(CameraCharacteristics.FLASH_INFO_AVAILABLE) == true
}
if (cameraId == null) {
statusText.text = "This device has no flash"
toggleButton.isEnabled = false
return
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), 100)
}
toggleButton.setOnClickListener { toggleTorch() }
}
private fun toggleTorch() {
try {
isOn = !isOn
cameraManager.setTorchMode(cameraId!!, isOn)
toggleButton.text = if (isOn) "TURN OFF" else "TURN ON"
statusText.text = if (isOn) "Torch is on" else "Torch is off"
} catch (e: Exception) {
Toast.makeText(this, "Could not access the torch", Toast.LENGTH_SHORT).show()
isOn = false
}
}
override fun onPause() {
super.onPause()
if (isOn) toggleTorch()
}
}
Three things in that code worth understanding
These are the parts that separate a working app from a tutorial copy.
Never assume camera 0 has the flash
Most tutorials hardcode cameraId = "0". On phones with several rear cameras, or where the front camera is listed first, that crashes or silently does nothing. The loop above asks each camera whether it has a flash and uses the one that does.
Turn the torch off in onPause()
If the user switches apps with the torch on, it stays on. The battery drains, the LED gets hot, and the user blames your app. Three lines in onPause() prevent it.
Handle a refused permission
If the user says no to the camera prompt, the app must not crash. It should say what it needs and disable the button. Reviewers on the Play Store test exactly this.
Step 5: Run it
Connect a real phone with USB debugging on and press Run. Allow the camera permission when asked, then press the button.
Test all four of these before you call it finished:
- Torch turns on and off
- Press home with it on — it should switch off
- Refuse the permission — the app should explain, not crash
- Rotate the phone — it should not crash
Common problems
Nothing happens when I press the button
You are probably on the emulator, which has no flash. Use a real device.
The app crashes on launch
Usually a hardcoded camera ID. Use the loop above. Check Logcat in Android Studio for the exact line.
"CameraAccessException"
Another app is holding the camera. Close the camera app and try again. This also happens if your own app opened the camera and never released it.
The torch stays on after closing the app
The onPause() handler is missing.
It works on my phone but not on another
Different camera layouts. The detection loop handles most of this. A few older Samsung and Xiaomi models need the legacy Camera.Parameters API, but those are now rare.
Ideas to take it further
Once it works, these are good next steps and each teaches something new:
- SOS mode — flash a repeating pattern with a
Handler - Screen light — a white full-screen mode for devices with no flash
- A widget — toggle from the home screen without opening the app
- Shake to toggle — introduces the accelerometer
- Strobe with adjustable speed — a SeekBar plus a background thread
Publishing it
Two honest notes before you put this on the Play Store.
First, the store is full of torch apps, and most are older than yours with thousands of reviews. Do not expect downloads from a plain one.
Second, keep the permissions minimal. Torch apps have a bad reputation because many ask for contacts, location and storage they do not need. Google reviews camera-permission apps carefully. Asking only for what you use gets you approved faster.
Where to go next
- Add AdMob ads to your app
- Turn a website into an Android app
- Build a chat app — a much bigger project