FIELD NOTE ·
The library said no. The hardware said yes.
How reading the source and interrogating the Solana Seeker camera hardware turned an unsupported feature into a solvable routing problem.
6 min readTRAVIS KEIR
TL;DR: I wanted manual camera controls in my app. The camera library said the feature wasn’t supported. But the Seeker’s own native camera app had them — so the hardware could clearly do it. That gap was the whole story: “not supported” was the library’s limit, not the platform’s. I read the library’s source, wrote a native probe to interrogate the hardware directly, and confirmed it — the manual controls are fully reachable, just not exposed. The lesson: when a library says a feature is off the table, that’s often a software wall, not a hardware one, and the difference is discoverable if you stop reading docs and start experimenting.
I’m building a camera app for the Solana Seeker — a film-photography app, the kind where the feel of shooting matters as much as the shot. Which means I wanted proper manual controls: ISO, shutter speed, white balance. The stuff a real camera gives you.
The app uses react-native-vision-camera — a good library, the serious choice for
camera work in React Native. I went looking for how to set manual ISO.
It’s not there. No prop, no method. Manual ISO, manual shutter, manual white balance — none of them exposed in the library’s JavaScript API. By the letter of the library, my feature wasn’t supported.
Here’s the thing, though. I’d used the Seeker’s native camera app. It has a pro mode. Full manual controls, right there, on the same phone, same sensor. So one of two things was true: either those controls were somehow walled off to third-party developers — locked to the system app — or the library just wasn’t surfacing something the hardware could plainly do.
I refused to believe the first one. I don’t accept that a capability sitting right there in the native app is off-limits to me as a developer. And there was a product reason underneath the stubbornness: I want the user to have the same experience with my camera as they get with their phone’s native one. No operational learning curve. If their phone can do manual mode, my app should feel like it does too. That’s not a nice-to-have — it’s the whole point of the app feeling native instead of bolted-on.
So the “not supported” wasn’t an answer. It was a question I hadn’t finished asking.
Reading the source instead of the docs
Docs tell you what a library intends to expose. They don’t tell you what the platform underneath can actually do. So I stopped reading docs and read the library’s actual source.
It was clarifying, in a slightly deflating way. There, in vision-camera’s Android
code, was RAW capture hardcoded to false — with a literal // TODO: Add RAW capture support sitting next to it. Manual ISO, shutter, white balance: no
plumbing to the JS layer at all. Not disabled for a reason. Just… not wired up yet.
Was I surprised? No. That’s usually how it goes. A capability exists one layer down, and the layer you’re working in just hasn’t reached down to grab it. The wall isn’t made of stone. It’s made of “nobody’s gotten to this yet.”
And crucially, vision-camera runs on CameraX on Android — which has an escape
hatch called Camera2Interop that lets you reach past the high-level API and set
raw Camera2 capture parameters directly. Which is to say: the road to manual
controls existed. The library just hadn’t paved it.
Interrogating the hardware directly
Reading the source told me the library’s limits. It didn’t tell me the hardware’s limits — whether the Seeker’s sensor would actually honor manual controls if I reached them. For that, I couldn’t trust anyone’s docs. I had to ask the device.
So I wrote a small native module — a bit of Kotlin — whose only job was to read the camera’s actual capabilities, at the exact access level any third-party app has. No special privileges. Just: what does this camera tell an ordinary app it can do?
The answer was better than I’d hoped. The main rear camera reported full manual sensor support — ISO from 100 to 11470, shutter from 1/10000th of a second all the way to 16 seconds, non-fixed focus, manual white balance. Not vendor-locked. Not system-app-only. Genuinely reachable Camera2 territory, available to my app.
Then I went further, because reporting a capability and honoring it are different things. I tested the two controls the library does expose, and measured them instead of trusting them. Exposure compensation: I watched the live preview’s luminance actually drop — 31.7 down to 13.7 — measured by pixel analysis, not by the API politely returning success. Tap-to-focus: the tap reached all the way down to the vendor camera hardware layer and physically moved the lens motor. I could see it in the focus logs — the motor stepping to a new position. Not a placeholder. A real, moving piece of glass.
So: the hardware is capable, it’s reachable, and it honors what you send it. The only thing standing between my app and full manual controls is that the library’s JavaScript layer doesn’t expose them — and CameraX gives me a documented way around exactly that.
What I’m doing about it
I’m building the patch. The Camera2Interop path lets me reach the manual controls
the library skipped, and the hardware’s already told me it’ll cooperate. So the
manual ISO, shutter, and white balance I was told weren’t supported are, right now,
becoming supported — for a hackathon, on a deadline, because that’s the fun way to
do it.
The native experience I wanted — where my camera feels like the phone’s own, because it is reaching the same controls the phone’s own camera reaches — is reachable. It was always reachable. It just wasn’t exposed.
Lesson learnt
Sometimes you won’t find the answer in the docs. You have to experiment and find out for yourself.
“Not supported” is one of the most misleading phrases in software, because it collapses two very different things into one sentence: the platform can’t do this, and this library hasn’t wired it up. Those deserve completely different responses. The first is a wall. The second is a to-do list someone else hasn’t finished — and you’re allowed to finish it.
The tell, every time, is a reference implementation that already does the thing. The Seeker’s native camera app had manual mode. That was proof the hardware could. Once you know the capability exists, “the library doesn’t expose it” stops being a dead end and becomes a routing problem — and routing problems have solutions.
Docs describe the paved roads. The capability you want is often just past where the pavement stops. You don’t find that by reading. You find it by driving to the edge, getting out, and having a look.