The Problem
You want to record video on Android with the screen off. You open the Camera2 API documentation, set up a CameraDevice, create a CaptureSession, and start a repeating request. It works great — until the screen turns off and everything stops.
The camera gets released. Your capture session closes. Your recording is gone.
This is one of the most common frustrations Android developers face when building camera apps that need to run in the background. The OS aggressively reclaims camera resources when the screen turns off, and the default behavior of most camera implementations does not account for this.
Why It Happens
Android's power management system is designed to conserve battery. When the screen turns off, the system enters a low-power state and begins releasing resources. The camera is one of the first things to go because it's power-hungry hardware.
Additionally, starting with Android 10, background camera access became more restricted. Apps that are not in the foreground cannot access the camera at all — the system will throw a CameraAccessException.
The Solution: Foreground Service + Wake Lock
The key to keeping the camera alive with the screen off is a combination of two things:
A foreground service — This keeps your app in a foreground state even when the UI is not visible. Android requires you to show a persistent notification, which is actually useful for camera recording apps (you want the user to know recording is active).
A partial wake lock — This prevents the CPU from sleeping, which keeps your camera capture pipeline running.
Here is the basic structure:
class CameraService : Service() {
private lateinit var wakeLock: PowerManager.WakeLock
private var cameraDevice: CameraDevice? = null
override fun onCreate() {
super.onCreate()
val powerManager = getSystemService(POWER_SERVICE) as PowerManager
wakeLock = powerManager.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK,
"MyApp::CameraWakeLock"
)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val notification = createNotification()
startForeground(NOTIFICATION_ID, notification)
wakeLock.acquire()
openCamera()
return START_STICKY
}
override fun onDestroy() {
wakeLock.release()
closeCamera()
super.onDestroy()
}
}
Camera2 API Setup Inside the Service
The camera setup inside the service follows the standard Camera2 pattern, but with a few important differences:
Use a SurfaceTexture instead of a preview surface. Since there is no visible preview (the screen is off), you cannot use a SurfaceView or TextureView. Instead, create a SurfaceTexture programmatically:
val surfaceTexture = SurfaceTexture(0)
surfaceTexture.setDefaultBufferSize(width, height)
val surface = Surface(surfaceTexture)
For recording, use MediaRecorder or MediaCodec. MediaRecorder is simpler for file-based recording. MediaCodec gives you more control for streaming scenarios.
val mediaRecorder = MediaRecorder().apply {
setAudioSource(MediaRecorder.AudioSource.MIC)
setVideoSource(MediaRecorder.VideoSource.SURFACE)
setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
setOutputFile(outputPath)
setVideoEncoder(MediaRecorder.VideoEncoder.H264)
setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
setVideoSize(width, height)
setVideoFrameRate(30)
prepare()
}
Create the capture session with both surfaces:
cameraDevice?.createCaptureSession(
listOf(recorderSurface, previewSurface),
object : CameraCaptureSession.StateCallback() {
override fun onConfigured(session: CameraCaptureSession) {
val request = cameraDevice!!.createCaptureRequest(
CameraDevice.TEMPLATE_RECORD
).apply {
addTarget(recorderSurface)
}
session.setRepeatingRequest(request.build(), null, null)
mediaRecorder.start()
}
override fun onConfigureFailed(session: CameraCaptureSession) {
// Handle failure
}
},
backgroundHandler
)
Manufacturer-Specific Gotchas
This is where things get messy. Different Android manufacturers handle background camera access differently:
Samsung devices may kill foreground services after extended periods. You need to handle service restart and camera reconnection gracefully.
Xiaomi/MIUI has aggressive battery optimization that can kill foreground services. Users may need to manually whitelist your app in battery settings.
Huawei/EMUI has similar aggressive battery management. The app needs to be added to the "protected apps" list.
OnePlus/OxygenOS generally works well with foreground services but may throttle camera frame rates in the background.
The solution is to provide clear instructions in your app for users on these devices, and to handle camera disconnection and reconnection robustly.
Handling Camera Disconnection
Even with a foreground service and wake lock, the camera can be disconnected by the system or by another app claiming camera access. You need to handle this in your CameraDevice.StateCallback:
override fun onDisconnected(camera: CameraDevice) {
// Camera was taken by another app or the system
// Attempt to reopen after a short delay
handler.postDelayed({
openCamera()
}, 1000)
}
override fun onError(camera: CameraDevice, error: Int) {
// Handle specific error codes
when (error) {
CameraDevice.StateCallback.ERROR_CAMERA_IN_USE -> {
// Another app has the camera, retry later
}
CameraDevice.StateCallback.ERROR_CAMERA_DEVICE -> {
// Camera hardware error, may need device restart
}
}
}
Permissions and Manifest Setup
Your manifest needs several permissions and the foreground service declaration:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" />
<service
android:name=".CameraService"
android:foregroundServiceType="camera"
android:exported="false" />
The foregroundServiceType="camera" is required starting with Android 14 (API 34). Without it, the system will not grant camera access to your foreground service.
Battery Considerations
Screen-off recording dramatically reduces battery consumption compared to screen-on recording. In my testing:
- Screen on recording: ~30-40% per hour
- Screen off recording: ~8-12% per hour
- Screen off + airplane mode: ~6-8% per hour
The biggest power savings come from turning off the display. Additional savings come from disabling radios (WiFi, cellular, Bluetooth) if your use case allows it.
What I Built With This
I used this approach to build Background Camera RemoteStream, an Android app that records video with the screen completely off and includes remote control via an embedded web server. The app is free on Google Play for basic recording.
If you are building something similar, feel free to ask questions in the comments. The Camera2 API has a lot of edge cases, especially around background operation.
Top comments (0)