Camera
Camera2 is hard for a reason: it exposes the actual hardware pipeline. CameraX exists to wrap the common cases without hiding that pipeline completely.
The camera is the most complex peripheral on a phone, and Android's camera API reflects that. Camera1 pretended the camera was a point-and-shoot. Camera2 exposes the pipeline. CameraX tries to give you the useful parts of Camera2 without making you reimplement autofocus.
TL;DR#
- Camera1 was a simple, synchronous API. It is deprecated.
- Camera2 (API 21) models capture as requests and results: you describe what you want, the hardware does it, and it tells you what actually happened.
- The camera HAL is where device capabilities live. Two phones on the same Android version can expose different features entirely.
- CameraX is a Jetpack library that provides use cases (preview, capture, analysis) with device compatibility handled for you.
- The permission is
CAMERA, dangerous since API 23; the camera indicator and global toggle arrived in the API 31 privacy wave.
Mental model#
Think of a professional camera with a director and a technician.
Camera1 is asking the technician to "take a photo" and hoping. Camera2 is handing the technician a shot list: exposure, focus mode, flash, which outputs to fill. The technician executes it and returns a report saying what settings were actually used — because the camera may have decided differently.
CameraX is a production company that turns your intent ("show a preview and let the user take a photo") into a shot list for whichever technician is on set.
Where the analogy breaks#
A shot list is executed once. Camera2 is a continuous loop: a repeating request keeps the preview alive, and each iteration returns a result. The API is a stream of requests and results, not a single transaction.
The big picture#
Text description of this diagram
A six-stage loop. The app builds a CaptureRequest naming the target surfaces and settings. The camera service brokers access and enforces permissions. The vendor camera HAL turns the request into register writes for this sensor and ISP. The sensor integrates light and the ISP processes the image into several scaled outputs. Each output is a Surface backed by a BufferQueue: preview, still capture and video can all be targets of one request. The HAL returns a CaptureResult describing the settings and state actually achieved, which is how autofocus and auto-exposure are converged.
The loop is the important part. Camera2 does not have a takePicture() that returns a bitmap. It has
a request queue and a result stream, and you drive it.
Deep dive#
Camera1: the synchronous era#
android.hardware.Camera gave you setPreviewDisplay, startPreview, takePicture. It was easy to
use and impossible to use well: no control over per-frame settings, no way to get several outputs at
once, and a preview that was a separate, lower-quality path from the still capture.
It is deprecated and should not be used for new code. It survives because a lot of old code exists.
Camera2: requests and results#
A CaptureRequest describes one capture:
- the target surfaces (preview, still, video, analysis),
- the sensor settings (exposure time, sensitivity),
- the control modes (autofocus, auto-exposure, auto-white-balance),
- the output settings (format, size).
A CaptureResult describes what the hardware did: the actual exposure, the focus state, the
timestamp, the applied settings. Reading results is how you implement "tap to focus" — you set a focus
region, then wait for the result to report focus locked.
There are three request modes:
- Single request for a still capture.
- Repeating request for a preview, replaced when settings change.
- Burst for a sequence.
The HAL is the real API#
The camera HAL defines more than a dozen interfaces: the device, the capture request, the result, the
metadata, the stream configuration. A device's capability set is reported through
CameraCharacteristics — but the values come from the HAL, so they are only as complete as the vendor
made them.1
This is why two phones on the same Android version can behave differently:
- One supports 4K video from the front camera, another does not.
- One exposes logical multi-camera, another exposes each lens separately.
- One supports RAW capture, another reports the capability but produces corrupt files.
The platform defines the contract; the vendor implements it; the CDD sets a floor. Everything above the floor is optional.
CameraX: use cases instead of pipelines#
CameraX rephrases the problem in terms of use cases:
- Preview: show the viewfinder.
- ImageCapture: take a photo.
- ImageAnalysis: get frames for processing (barcode scanning, ML).
- VideoCapture: record video.
You bind use cases to a lifecycle, and CameraX negotiates the stream combination, handles rotation, and applies device-specific quirks. That is the value: the quirks are the hard part, and they are maintained in the library rather than in every app.2
The trade-off is control. CameraX exposes extensions and some manual controls, but if you need per-frame sensor settings you will drop to Camera2.
Extensions and multi-camera#
Two features deserve a mention because they are where modern camera quality lives:
Camera extensions expose OEM image processing — night mode, bokeh, HDR — through a standard API. The OEM implements the extension in its HAL; the app asks for it by mode. This is how a third-party camera app can use the same night-mode processing as the built-in one, at least in principle.
Logical multi-camera lets one camera device represent several physical lenses, so the app can request a zoom level and let the device choose which lens to use. Without it, an app would have to switch cameras itself and handle the exposure jump.
Both are capability-dependent. An app must query and fall back.
Permissions, indicators and the privacy toggle#
CAMERA is a dangerous permission, required since API 23 at runtime. Beyond the permission:
- API 30 added a global camera toggle and restricted background access.
- API 31 added the camera indicator — a system-drawn dot or icon whenever the camera is in use.
- API 34 requires foreground service types when a service uses the camera.
The pattern is the same as location and microphone: holding the permission is necessary but not sufficient, and the user can always see that the hardware is active.
Why Camera2 is "harder" — and whether that is a flaw#
Camera2 is harder because it is honest. It exposes:
- the fact that capture is asynchronous,
- the fact that settings are requests, not commands,
- the fact that outputs are buffers with backpressure,
- the fact that hardware capabilities vary.
Camera1 hid all four and produced apps that worked on one device and not another. Camera2 makes the device differences visible, which is unpleasant but correct. CameraX is the pragmatic middle: it hides the differences that can be hidden and exposes the ones that cannot.
A request that converges: tap-to-focus#
The request/result loop is easiest to understand through a feature every camera app has.
A tap produces a metering rectangle, mapped from screen coordinates to sensor coordinates. The app
builds a request with CONTROL_AF_MODE_AUTO and the new CONTROL_AF_REGIONS, and submits it as a
repeating request. Then it waits — not for the image, but for the result — until
CONTROL_AF_STATE reports a locked state.
That loop is the pattern for every manual control:
- express the desired state in a request,
- keep the request repeating,
- read the result to learn the achieved state,
- update the UI from the result, not from the request.
An app that draws a "focused" indicator as soon as it sends the request is lying to the user for somewhere between 100 and 800 milliseconds.
Sessions, and sharing the camera#
On Android 10 and later, a camera can be opened by more than one app through a camera session configuration: one app is the primary client and others can share a stream in limited ways. The practical rules are still simple:
- Camera access is exclusive by default, and the second app gets an error or a reduced stream.
- The system enforces the camera-in-use policy, so a background app cannot silently hold the device.
- The indicator tells the user something is using it, which is the visible half of the same rule.
The design is a compromise between "one app owns the camera" — which is simple and matches the hardware — and "video calls and camera apps should coexist" — which requires sharing.
How it evolved#
| API | Version | What changed |
|---|---|---|
| 1 | 1.0 |
|
| 4 | 1.6 Donut |
|
| 5 | 2.0 Eclair |
|
| 8 | 2.2 Froyo |
|
| 9 | 2.3 Gingerbread |
|
| 11 | 3.0 Honeycomb |
|
| 13 | 3.2 Honeycomb |
|
| 14 | 4.0 Ice Cream Sandwich |
|
| 16 | 4.1 Jelly Bean |
|
| 17 | 4.2 Jelly Bean |
|
| 18 | 4.3 Jelly Bean |
|
| 19 | 4.4 KitKat |
|
| 20 | 4.4W KitKat (Wear) |
|
| 21 | 5.0 Lollipop |
|
| 22 | 5.1 Lollipop |
|
| 23 | 6.0 Marshmallow |
|
| 24 | 7.0 Nougat |
|
| 26 | 8.0 Oreo |
|
| 27 | 8.1 Oreo |
|
| 28 | 9 Pie |
|
| 29 | 10 |
|
| 30 | 11 |
|
| 31 | 12 |
|
| 32 | 12L |
|
| 33 | 13 Tiramisu |
|
| 34 | 14 Upside Down Cake |
|
| 35 | 15 Vanilla Ice Cream |
|
| 36 | 16 Baklava |
|
| 37 | 17 Cinnamon Bun |
|
Under the hood#
- the camera service: access control and stream brokering
- the Camera2 API
- the camera HAL contract
- the native camera client and the binder plumbing
Curiosity corner#
- A "48 MP" camera rarely produces 48 MP photos. It bins pixels to improve low light and outputs a smaller image by default; the full-resolution mode is a separate, slower capture.
- The front camera is often the same sensor as the rear ultrawide. Logical multi-camera can expose one physical sensor through two logical devices.
- Camera2's
CaptureResultis the only honest source of truth. Reading back the request you sent tells you what you asked for, not what the hardware did.
Try it#
adb shell dumpsys media.camera | head -60
adb shell cmd media.camera get-num-cameras
adb shell dumpsys media.camera -h
Example output
Camera 0:
Facing: BACK
Supported hardware level: LEVEL_3
Stream combinations: 3
Max JPEG size: 4000x3000
Camera 1:
Facing: FRONT
Supported hardware level: LIMITEDThe hardware level in that output is the single most useful capability: LEGACY means Camera1
semantics, LIMITED and FULL mean increasing Camera2 support, and LEVEL_3 adds advanced features.
Check yourself#
Check yourself
What are the four stages the media framework separates?
Sources#
Sources
Every version number, API level, class name and date on this page is traced to one of these. Pages are re-verified against them; last_verified above says when.
- docsCamera overviewsource.android.comaccessed 2026-10-27↩
- docsCameraX overviewdeveloper.android.comaccessed 2026-10-27↩
- docsManifest.permission | API referencedeveloper.android.comaccessed 2026-10-27↩
- docsBehavior changes: Apps targeting Android 12developer.android.comaccessed 2026-10-27↩
- docsBehavior changes: Apps targeting Android 13 or higherdeveloper.android.comaccessed 2026-10-27↩