#5013: Android Camera Fragmentation: Why Apps See Different Lenses

OnePlus hides fisheye lenses from third-party apps. Here's how Android's camera API actually works and what you can do about it.

Featuring
Listen
0:00
0:00
Episode Details
Episode ID
MWP-5195
Published
Duration
28:25
Audio
Direct link
Pipeline
V5.2
TTS Engine
chatterbox-regular
Script Writing Agent
deepseek-v4-pro

AI-Generated Content: This podcast is created using AI personas. Please verify any important information independently.

Android's multi-camera API was supposed to solve fragmentation. Introduced in Android 9 (API 28), the logical versus physical camera model gave developers a standard way to discover and access every lens on a device. A single "logical camera" represents the rear-facing array, and underneath it sit "physical cameras" — the ultrawide, telephoto, and main sensor. Call getPhysicalCameraIds on the logical camera, and you should find everything.

The problem is that Google's Compatibility Definition Document only "strongly recommends" manufacturers expose all physical cameras. OnePlus took that recommendation as optional. On OxygenOS 10, all cameras were accessible. OxygenOS 11 restricted auxiliary access to a single package name — "snapcam." OxygenOS 12 removed even that, wiping out third-party access entirely on devices like the OnePlus 9 series. Celso Azevedo, who maintains the GCam port archive, stopped recommending OnePlus in August 2023 over these "artificial limitations."

There's a workaround: the zoom ratio bridge. Instead of directly opening the ultrawide camera ID, an app can set CONTROL_ZOOM_RATIO to 0.6x — below 1.0 — and the HAL handles switching to the ultrawide internally. ChatGPT likely uses this approach. But it only works if the manufacturer implemented the extended zoom range in their HAL. On restricted devices, the zoom ratio range might only cover the main sensor's digital zoom, and the fisheye never engages.

For developers building camera-dependent apps, the pragmatic path starts with CameraX. Check CameraInfo.isLogicalMultiCameraSupported first. If true, enumerate physical cameras and build a lens switcher using setPhysicalCameraId. If false, fall back to zoom ratio controls and let the HAL handle lens selection automatically. This approach works on compliant devices without requiring per-device camera ID databases — the unsustainable maintenance burden that forced Moment to abandon their Android camera app in 2020.

Downloads

Episode Audio

Download the full episode as an MP3 file

Download MP3
Transcript (TXT)

Plain text transcript file

Transcript (PDF)

Formatted PDF with styling

#5013: Android Camera Fragmentation: Why Apps See Different Lenses

Corn
Daniel's been building out his home inventory system — snapping parts, reading serial numbers, feeding everything into a database. And he keeps hitting the same wall. He'll be in Image Meter trying to capture a full room measurement, and the fisheye camera just isn't there. Switch over to ChatGPT, same phone, same room, and suddenly he's got zoom controls that work. Same OnePlus Nord 3, completely different camera behavior.
Corn
His question is basically this: what's actually going on under the hood that makes one app see the fisheye and another app act like it doesn't exist? He's noticed the pattern — manufacturer camera apps get everything, third-party apps get whatever the phone decides to give them — and he wants to understand the mechanics well enough to build better camera support into his own inventory system.
Herman
The thing that makes this worth a full episode is that the answer isn't "the API can't do it." The API can. Android 9 introduced a whole multi-camera framework specifically designed to expose every physical lens on the device. The problem is everything that happened after Google published the documentation.
Corn
Which is where OnePlus comes in.
Herman
OnePlus is a big part of it, yeah. But it's broader than that. The architecture itself has this built-in tension. Let me start with what the API actually describes, because once you see what Google intended, the gap between that and what Daniel's experiencing becomes the whole story.
Corn
Go.
Herman
Android 9 — API 28 — introduced the logical versus physical camera model. Before that, if your phone had three rear cameras, the API might expose them as three separate camera IDs, or it might only show you one. There was no standard. Google's fix was to say: here's a single "logical camera" that represents the whole rear-facing array, and underneath it are "physical cameras" — the actual ultrawide, the telephoto, the main sensor. Developers call CameraManager.getCameraIdList, they see the logical camera. Then they call getPhysicalCameraIds on that logical camera to discover what's actually behind it.
Corn
So in theory, Daniel's Nord 3 should report a logical camera wrapping the fisheye and the main sensor, and any app that bothers to ask should find both.
Herman
In theory. The Compatibility Definition Document strongly recommends manufacturers expose a logical camera for all physical cameras facing the same direction. Strongly recommends. Not requires. And that word — "recommends" — is where half the fragmentation lives.
Corn
Because OnePlus looked at "strongly recommends" and said no thank you.
Herman
Worse than that. They said yes, then no, then yes but only if your app is named the right thing, then no again. Let me trace the actual timeline. On OxygenOS 10, all cameras were accessible through the standard API. OxygenOS11 restricted auxiliary camera access to a single package name — "snapcam." If your app wasn't literally named snapcam, the HAL wouldn't show you the ultrawide. OxygenOS12 removed even that. On the OnePlus9 series, the Android12 update wiped out all auxiliary camera access for third-party apps entirely. Cameras that were visible one day were gone the next.
Corn
That's not a bug. That's a feature request from the camera app team.
Herman
I think you're right, and I think that's the part most coverage misses. People treat this as OEMs being sloppy or not getting around to implementing the multi-camera API properly. But OnePlus actively broke working functionality across multiple OS versions. Celso Azevedo — he maintains the big GCam port archive — stopped recommending OnePlus entirely in August2023 over exactly this. His words were "artificial limitations." Not bugs. Limitations.
Corn
So Daniel's Nord3 lands somewhere in the aftermath of all this. He's got a fisheye camera that physically exists, and the OnePlus camera app can use it just fine.
Herman
Right. And the question is what mechanism lets ChatGPT access zoom but not the fisheye directly, while Image Meter gets neither. The answer, I'm fairly sure, is the zoom ratio bridge.
Corn
Explain that.
Herman
So there are two completely different ways to access the ultrawide on Android. One is the direct route — you enumerate physical camera IDs, find the one with the ultrawide focal length, and open it explicitly. That's what Image Meter would need to do to offer a fisheye toggle. The second route is indirect. You open the logical camera, and instead of switching camera IDs, you set a parameter called CONTROL_ZOOM_RATIO. On devices where the HAL implements this properly, setting the zoom ratio to0.6x — below1.0 — triggers automatic switching to the ultrawide physical camera. The app never asks for the ultrawide. It just says "give me0.6x zoom" and the HAL does the rest.
Corn
And ChatGPT is doing the second one.
Herman
Almost certainly. Eddy Talvala, who's a camera engineer at Google, confirmed on StackOverflow that zoom ratio-based switching is the recommended bridge for multi-camera access without managing camera IDs. It's simpler for the developer and it works on devices where the HAL supports it. ChatGPT has the engineering resources to implement per-device zoom ratio ranges, query the available range from CameraCharacteristics, and present a zoom slider that the HAL interprets as physical camera switches.
Corn
While Image Meter is probably doing the simplest thing that works for most phones — open the default back camera and start capturing. No physical camera enumeration, no zoom ratio fiddling.
Herman
And "simplest thing that works" is not a criticism of Image Meter. It's a small team. They're building a measurement app, not a camera app. They likely use CameraX with DEFAULT_BACK_CAMERA, which binds to whatever the system considers the primary rear sensor. On a compliant device, that logical camera would wrap everything and zoom ratio would just work. On Daniel's Nord3, the logical camera probably only exposes the main sensor and a limited zoom range, and the fisheye is hidden entirely from the camera ID list.
Corn
So the API is theoretically capable, the zoom ratio workaround exists, but whether it works on any given phone depends on whether the OEM's HAL implementation bothers to support the extended zoom range that would trigger the switch.
Herman
And that's the second half of the fragmentation problem. Even if you go the zoom ratio route — which is Google's recommended approach — you're still at the mercy of whether the manufacturer implemented it. The CONTROL_ZOOM_RATIO_RANGE on a compliant device should span from the ultrawide's field of view through the telephoto's. On a restricted device, it might only cover the main sensor's digital zoom range. The app requests0.6x, the HAL says "best I can do is1.0x," and the fisheye never engages.
Corn
What about the hardware support level? I know Camera2 defines these tiers — LEGACY, LIMITED, FULL, all the way up to LEVEL_3.
Herman
Five levels, yeah. LEGACY is basically the old Camera API wrapped in a Camera2 interface — you get snapshot capture and not much else. LIMITED adds some manual controls. FULL gives you everything: manual sensor control, RAW capture, YUV reprocessing. LEVEL_3 adds YUV reprocessing and RAW with burst capture. EXTERNAL is for USB cameras.
Corn
Where does the Nord3 likely sit?
Herman
Probably LIMITED or FULL. Most mid-range devices ship at LIMITED — enough to pass compatibility tests, not enough to expose every feature. But here's the thing: even a FULL device can hide physical cameras. The hardware support level tells you what operations are available on the cameras that are exposed. It says nothing about whether all physical cameras are exposed in the first place.
Corn
So you could have a FULL device that only shows you one camera.
Herman
And that's exactly what people report on OnePlus devices. StackOverflow has a thread from March2024 where a developer found that their OnePlus8 reported fewer cameras through Camera2 than a third-party app called Protake could access. Same phone, same API level, but Protake found an extra lens that the developer's own Camera2 enumeration couldn't see.
Corn
Which means Protake has some kind of whitelisting or device-specific knowledge that the standard API doesn't provide.
Herman
That's the working theory. Protake likely maintains a per-device database of camera IDs discovered through testing. They've probably mapped out exactly which camera ID corresponds to which physical lens on dozens of OnePlus variants, including ones that don't appear in the standard camera ID list. They then use that mapping to open cameras by ID directly, bypassing the logical camera abstraction entirely.
Corn
That's an enormous maintenance burden.
Herman
It's why Moment abandoned their Android camera app in2020. They sent an email to users saying they didn't have the engineering bandwidth to keep up with device fragmentation. Every new phone, every OS update, could break the camera mapping. For a small team, it's unsustainable. For an app like Protake that's specifically a camera app, it's their whole value proposition — so they invest in it.
Corn
And for Daniel's home inventory system, maintaining a per-device camera ID database is completely out of scope.
Herman
But that doesn't mean he's stuck. There's a pragmatic middle path that gets him most of the way there without going insane. Start with CameraX — it's the recommended library, it handles lifecycle management, and it abstracts away a lot of the Camera2 boilerplate. Bind Preview, ImageCapture, and ImageAnalysis use cases to a ProcessCameraProvider. Use CameraSelector.Builder.requireLensFacing with LENS_FACING_BACK as the baseline.
Corn
That gets him the default back camera, same as Image Meter.
Herman
Right. Then the first check: call CameraInfo.isLogicalMultiCameraSupported. If that returns true, the device is at least claiming to support the multi-camera model. From there, getPhysicalCameraInfos to enumerate what's actually available. If the fisheye shows up — great, build a lens switcher UI using setPhysicalCameraId, which CameraX1.4.0 added.
Corn
And if it doesn't show up?
Herman
That's the fallback path. Query CONTROL_ZOOM_RATIO_RANGE from CameraCharacteristics. If the range goes below1.0 — say, down to0.6x — then the HAL supports zoom-based switching to the ultrawide even if it won't expose the physical camera ID. Implement a zoom slider or preset buttons that set the zoom ratio, and let the HAL handle the switching internally. The user doesn't need to know which physical lens is active. They just see a wider or tighter field of view.
Corn
Which is actually better for a home inventory system anyway. Daniel's photographing parts and reading numbers — he doesn't need to think about which lens is which. He just needs the widest possible shot when he's in a tight space.
Herman
The HAL's automatic switching based on zoom ratio might actually produce better results than manual lens selection, because the HAL can factor in lighting conditions and focus distance when deciding which physical camera to use. The developer specifies the desired field of view, and the system figures out the best hardware to deliver it.
Corn
There's a nice bonus here too — distortion correction. Fisheye lenses have significant barrel distortion, which is fine for artistic shots but terrible for measuring dimensions or reading text. The Camera2 API has a DISTORTION_CORRECTION_AVAILABLE_MODES property. If the device supports it, you can enable DISTORTION_CORRECTION_MODE_HIGH_QUALITY on still captures.
Herman
That's a good catch. For an inventory system where you're photographing labels and serial numbers, correcting lens distortion is useful — it makes OCR more reliable, measurements more accurate. And it's something the HAL can do automatically when you're shooting through the logical camera with zoom ratio switching, because the HAL knows which physical camera is active and can apply the appropriate correction profile.
Corn
Let me pull on a thread you mentioned earlier. The Protake situation — one app can see a lens that another app can't on the same device. You said whitelisting. What's actually happening at the HAL level?
Herman
The HAL checks the calling package name. It's that simple. When an app requests the camera ID list, the HAL implementation — which is provided by the OEM, not by Google — can filter the results based on who's asking. If the package name matches a known list, you get the full set. If it doesn't, you get the restricted set.
Corn
And the known list is... what, OnePlus's own camera app and maybe a few partners?
Herman
On OxygenOS 11 it was literally just "snapcam." One string. GCam ports exploited this by setting their package name to match, and for a while that worked. Then OnePlus patched it. The Protake situation suggests there's still some kind of allowlist on newer versions, but the criteria aren't public.
Corn
So the HAL is sitting there with full knowledge of every physical camera, and it's making a deliberate decision about who gets to see what.
Herman
Oscar Wahltinez from Google said this pretty candidly back in 2018 when the multi-camera API launched. He wrote that phone manufacturers "sometimes made use of private or hidden APIs or received special treatment from the driver implementation that other applications did not have privileged access to." That was Google's diplomatic way of saying: the OEM camera app doesn't play by the same rules, and we're trying to fix that.
Corn
Seven years later and the fix is still... partial.
Herman
The fix works on phones where the OEM wants it to work. Pixel devices expose everything. Samsung's flagships are pretty good about it — the S23 Ultra shows all its lenses through the standard API. OnePlus has been uniquely aggressive in the other direction.
Corn
What about the root-level workarounds? Daniel's mentioned rooting before.
Herman
There's a Magisk module called camera-id-visibility-patch that modifies the camera service to expose hidden physical cameras system-wide. It patches libcameraservice to bypass the permission checks that restrict auxiliary cameras. On custom ROMs like BlissRoms, there's a similar hack that makes "system cameras" available to all apps.
Corn
Which works, but now you're maintaining a rooted device and staying ahead of Play Integrity updates just to use your own hardware.
Herman
And for a home inventory system that Daniel wants to actually ship and maybe have other people use, telling users to root their phones and install a Magisk module is not a deployment strategy.
Corn
No. So the practical recommendation is CameraX, check for logical multi-camera support, fall back to zoom ratio, and accept that on some devices the fisheye simply won't be available through any standard API.
Herman
And document it. Tell the user "your device restricts access to the ultrawide camera — use the zoom slider to get the widest available field of view." It's not satisfying, but it's honest and it works on the devices that matter.
Corn
The broader thing here — and I think this is what Daniel's really poking at — is that this isn't a technical limitation. The API exists. The HAL knows about the cameras. The restriction is a policy decision made by the OEM, enforced in software, and the user paid for hardware they can't fully use unless they happen to open the right app.
Herman
And the incentive structure reinforces it. OnePlus's camera app is a differentiator. It's one of the things they tout in marketing — "look at our camera capabilities." If every third-party app could access the same hardware with the same quality, the OEM camera app loses some of its reason to exist. There's no Google Play Services metric that penalizes OEMs for hiding cameras. The compatibility tests don't check for it. So the default is: expose the minimum needed to pass certification, keep everything else for yourself.
Corn
That's the part that should make developers nervous about building camera-heavy features on Android. You can do everything right — use the recommended library, follow the best practices, query the API correctly — and still have your app look worse than the stock camera app through no fault of your own.
Herman
And users blame the app. They don't know about HAL restrictions or logical camera models. They just see that the stock camera app has a fisheye mode and your app doesn't, and they assume you're a worse developer.
Corn
Which loops back to Daniel's inventory system. He's building something where the camera is a utility, not the product. The last thing he needs is users thinking his app is broken because their phone's HAL won't expose a lens.
Herman
The zoom ratio approach sidesteps a lot of that. The user sees a zoom slider. They drag it wider, the field of view expands. They don't need to know whether the HAL switched to the ultrawide or just digitally zoomed out on the main sensor. The experience is what matters.
Corn
And if the zoom ratio range doesn't go wide enough?
Herman
Then you're capped at whatever the main sensor can deliver. On the Nord3, the main sensor is probably around a twenty-four millimeter equivalent. For photographing a whole room for measurement purposes, that might not be wide enough. In that case, the user's only option is to capture with the stock camera app and import the image — which is exactly the workflow Daniel's trying to avoid.
Corn
So the API gives you a spectrum. On one end, full access — enumerate physical cameras, switch between them, apply distortion correction, the works. On the other end, you get one camera and a limited zoom range. Where your app lands depends on which phone it's running on, and there's nothing the developer can do to move the needle without root.
Herman
That's the reality. And it's worth saying: this isn't going to change soon. The OnePlus12 is the first OnePlus device on Google's CameraX supported devices list, which is a good sign. It supports vendor extensions for bokeh and night mode in third-party apps. But the Nord3 isn't on that list. The Nord series historically hasn't gotten the same camera API treatment as the flagships.
Corn
So Daniel's Nord3 is probably running a HAL that's closer to the OxygenOS12 behavior than the OnePlus12 behavior.
Herman
Likely. And even if OnePlus improves things on future devices, the installed base of phones with restricted HALs isn't going anywhere. Developers building camera features today have to target the phones people actually have, not the ones that might ship with better API support next year.
Corn
One thing we haven't touched — the front-facing camera on the Nord3. Daniel mentioned it in passing. Is that a separate set of restrictions?
Herman
Front-facing cameras are usually simpler because there's typically only one sensor. No multi-camera array to manage. But the same API applies — CameraX with LENS_FACING_FRONT, or Camera2 with the front camera ID. The restrictions are less of an issue because there's nothing to hide. One front camera, one camera ID, done.
Corn
The fragmentation is specifically a rear-camera problem, where multiple physical lenses create the opportunity for OEMs to play favorites.
Herman
Right. And it's going to get more interesting as AI-driven camera features become more common. ChatGPT's visual context feature — the thing Daniel's using to identify transistors — depends on being able to capture detailed images. If the API restricts which lenses are available, the AI gets worse input, and the feature looks worse. At some point, the pressure to expose full camera capabilities might come from the AI companies themselves.
Corn
"Our model needs the telephoto to work properly, please stop hiding it."
Herman
Whether that pressure actually moves OEMs is an open question. But it's a new stakeholder in the conversation that didn't exist when the multi-camera API was designed.

Hilbert: I tested camera HALs for a year. This would've been... seventy-seven, seventy-eight. Company made phones you'd recognize the name of but wouldn't buy. My job was running the CTS camera tests — the compatibility test suite — and then running a second suite that wasn't part of CTS.
Corn
A second suite?

Hilbert: Internal. We had a list of fifty third-party apps — GCam ports, OpenCamera, a few obscure ones — and we'd run through every camera mode on every app and log what broke. The HAL team would get the report. The camera app team would get a different report. The two reports never agreed on which cameras were available.
Herman
Because the HAL team was exposing them and the camera app team was hiding them.

Hilbert: The HAL team shipped a driver that passed certification. All physical cameras enumerated, all required features present. Then the camera app team wrote their app against private vendor extensions that gave them better noise reduction, faster autofocus, access to a depth map the HAL didn't advertise. Their app won awards. The HAL passed CTS. And the third-party test suite — the one I ran — showed half the cameras invisible to anything that wasn't the stock app. Nobody's performance review mentioned the third-party test suite.
Corn
The organizational structure guarantees the outcome.

Hilbert: Two teams, two sets of metrics, and the one that matters for third-party apps belongs to neither of them. The HAL team isn't measured on whether GCam works. The camera app team isn't measured on whether the API is fair. And the one device I remember clearly — this was a mid-range thing, dual rear cameras — the ultrawide was fully exposed in the HAL. I could see it in the dumpsys output. But there was a runtime check in the camera service that filtered it out based on the calling package name. A deliberate if-statement. Somebody wrote that.
Herman
Do you remember what the condition was?

Hilbert: Whitelist. About a dozen package names, all of them either the OEM's own apps or partners with contracts. The comment in the code said "auxiliary camera access restricted to authorized clients." I took a photo of the screen with my own phone. Still have it somewhere.
Corn
That's not neglect. That's architecture.

Hilbert: The thing I wonder about with this zoom ratio approach you were describing — if the HAL is switching cameras automatically based on the zoom level, does the app get any indication which physical camera is active? Or does it just get frames and hope?
Herman
It can query the active physical camera from the capture result metadata, but most apps don't. The whole point of the logical camera abstraction is that the app shouldn't need to care.

Hilbert: If I wanted to know whether my ultrawide was actually being used or whether the HAL was just digitally zooming the main sensor and calling it good, I'd need to dig through metadata that most apps don't surface.
Herman
That's right. And on a restricted device, you might get digital zoom on the main sensor even at0.6x, because the HAL's zoom ratio range doesn't extend low enough to trigger the physical switch. The app requests ultrawide, the HAL delivers a cropped main sensor image, and the user never knows the difference except that the field of view is narrower than expected.

Hilbert: The zoom ratio thing is a polite fiction on some phones.
Herman
On some phones, yes. It works beautifully on Pixels and recent Samsungs. On restricted OnePlus devices, it's... variable.

Hilbert: I've still got four of those test devices in a cupboard. Mid-rangers from the era. Every one of them has cameras the API won't show you. I keep meaning to root them and see what's actually there.
Corn
A museum of hidden hardware.

Hilbert: A museum of decisions somebody got paid to make.
Corn
Where does that leave someone like Daniel, building a home inventory system that needs reliable camera access across whatever device his users bring?
Herman
The honest answer is: you build for the best case, you handle the worst case gracefully, and you document the gap. Start with CameraX and the logical camera model. If the device exposes physical cameras, great — give the user a lens switcher. If it doesn't, fall back to zoom ratio and provide the widest available field of view. If even that is restricted, capture at the default field of view and suggest the user try the stock camera app for wide shots.
Corn
Which is exactly the workflow Daniel's trying to eliminate, but on some devices it's the only option that works.
Herman
That's not a failure of the developer. It's a failure of the ecosystem that the developer can't fix from application code.
Corn
The misconception I keep seeing is that there's some separate "fisheye camera API" on Android, or that the ultrawide is a special category of hardware that needs special treatment. It's not. It's just another physical camera — same Camera2 framework, same CameraX pipeline, same enumeration process as the main sensor. The only thing special about it is that some OEMs have decided you shouldn't be able to see it.
Herman
The flip side of that is the assumption that CameraX solves everything. It simplifies development enormously, but if the underlying HAL is hiding cameras, CameraX won't magically reveal them. The abstraction is only as good as the implementation beneath it.
Corn
The open question — and I think this is where the pressure might actually come from — is whether the CameraX supported devices list expands to include mid-range phones like the Nord series. Google's been pushing hard on camera quality as an ecosystem feature. If AI-powered apps like ChatGPT are driving demand for better camera access, and those apps run on mid-range phones too, the business case for restricting camera access starts to erode.
Herman
I'm not holding my breath. The Nord 3 shipped with a restricted HAL, and OnePlus hasn't shown much interest in revisiting camera API support on devices that are already in users' hands. The OnePlus 12 getting CameraX vendor extension support is a good sign for future flagships, but it doesn't help anyone holding a Nord today.
Corn
Daniel's home inventory system, though — that's the kind of use case where the zoom ratio workaround shines. He's not doing artistic photography. He needs a wide field of view for room measurements and a tight zoom for component identification. The HAL's automatic switching based on zoom ratio gives him exactly that, without him needing to build a lens selection UI or maintain a device database. Sometimes the best camera is the one the HAL picks for you.
Herman
For the cases where the HAL doesn't cooperate, the fallback is straightforward: capture at the default field of view, and if the user needs wider, they know where the stock camera app is. It's not elegant, but it's honest about what the platform actually provides.
Corn
Thanks to Hilbert Flumingtop for producing, and for the cupboard full of test devices we're all now curious about.
Herman
This has been My Weird Prompts. You can find every episode at my weird prompts dot com, or email us at show at my weird prompts dot com.
Corn
We'll be back soon.

This episode was generated with AI assistance. Hosts Herman and Corn are AI personalities.