Repository navigation
Releases: reclaimchennai/chennai-gps-camera
Release list
v1.48.0 — the phone's own camera: real zoom, focus and the wide lens
Camera
- Photos use the phone's own camera: real zoom, tap-to-focus that sets focus and brightness where you tap, focus/exposure lock, and full-resolution photos with no shutter delay. Bursts keep every photo, and the save animation keeps pace with the shutter.
- Wide lens (0.6×) on phones that offer it to apps — seamless where the camera zooms across lenses, a quick switch where the ultra-wide is a separate camera (many Motorolas). Pinch for anything in between, e.g. 0.8×. Video mode uses the same lens factors.
- Photo ↔ video switching holds the last frame instead of flashing black.
- If the phone camera misbehaves on a phone, the app falls back to the old camera; Settings → Advanced → "Camera for photos" switches by hand.
Address
- Choose the address by hand (Settings → Advanced): tap the card to pick the building, office or shop within 50 m, search, or type it. Remembered for that spot; the card says the address was chosen by the photographer.
- The card names the actual neighbourhood rather than the zone or taluk, and no longer shows Google grid codes ("26RM+6F4") as the address. Railway/metro stations are named on photos taken at them.
Also
- Long video recordings are saved as they record; if the app is killed (reported on Motorola), the video is recovered on the next launch.
- Turn the phone and shoot: landscape photos get a landscape card.
- The simple card is the default again.
- The same social handle on several platforms is printed once, with the logos side by side.
- The photo map's heatmap follows pinch-zoom smoothly.
v1.47.1 (pre-release)
Pre-release for testing — fixes from testing v1.47.0 on a Galaxy S25. Not yet on the website or Play Store.
- Burst: the save animation now keeps pace with the shutter instead of playing on after the last photo.
- Social handles: the same handle on several platforms is printed once, with the platforms' logos side by side; different handles stay separate.
- Photo ↔ video: switching no longer flashes black — the last frame stays, softly blurred, while the camera changes over, then the live picture fades in.
- Address chooser: the close button no longer overlaps the list; the sheet shows what each source found (your phone's geocoder, OpenStreetMap, Google Places), and roads/trails are no longer offered as buildings.
- Autofocus unchanged: continuous by default, moved only by your tap or the lock.
Everything from v1.47.0 is included.
v1.47.0 (pre-release)
Pre-release for testing — not yet on the website or Play Store.
Camera
- Photos now use the phone's own camera (CameraX): real zoom, tap-to-focus that sets focus and brightness where you tap, focus/exposure lock, and full-resolution photos with no shutter delay.
- Wide lens (0.6×) on phones that offer it to apps — seamless where the camera zooms across lenses, a quick switch where the ultra-wide is a separate camera (many Motorolas). Pinch for anything in between, e.g. 0.8×.
- Video mode uses the exact lens factors from the phone camera, so its .6× opens the real ultra-wide.
- If the phone camera misbehaves, the app falls back to the old camera; Settings → Advanced → "Camera for photos" switches by hand. Settings → Camera capabilities lists what your phone exposes.
Address
- Choose the address by hand (Settings → Advanced): tap the card to pick the building, office or shop within 50 m, search, or type it. Remembered for that spot; the card says the address was chosen by the photographer.
- Cards no longer show Google grid codes (“26RM+6F4, …”) as the address.
- The card names the actual neighbourhood rather than the zone or taluk; railway/metro stations are named on photos taken at them.
Reliability
- Long video recordings are saved as they record — if the app is killed (reported on Motorola), the video is recovered on the next launch.
- Turn the phone and shoot: landscape photos get a landscape card.
- The simple card is the default again.
v1.46.0 — the fix was wrong, so everything the fix decides was wrong
Five things, one of which is a correctness bug worth reading about.
A photo could name the wrong police station
Ward, zone and police station are resolved from your coordinate by the app's own bundled polygons — no geocoder involved. So when a card taken outside Chetpet station read Ward 99 / G3 Kilpauk PS, it was not a geocoding mistake. The coordinate itself was in Kilpauk.
Measured against the shipped packs, attribution turns over fast:
| distance | becomes | |
|---|---|---|
| Chennai | 250 m | ward 108 / G7 Chetpet PS → 099 / G3 Kilpauk PS |
| Chennai | 300 m | K4 Anna Nagar → K5 Peravallur |
| Bengaluru | 300 m | Cubbon Park PS → Vidhana Soudha PS |
| Tambaram | 50 m | ward 064 → 048 |
The app ran a second, coarse watchPosition — the OS network/cell provider — as a fast first fix, and let it take over on age alone: ten seconds without GPS and a cell-tower estimate became the fix, reported as "ok". Riding through a city that happens constantly. Those estimates are routinely ±500–2000 m, which is several wards, and because every row derives from the same wrong point they all agree with each other. Nothing in the finished photo gives it away.
Now:
- a coarse fix may only replace a good one when it is genuinely better — its stated accuracy against how far the last GPS fix could have drifted since;
- "ok" means "good enough to name a place" (≤100 m), not "a number arrived", and the viewfinder warns you before the shutter;
- any photo taken on a coarse fix carries the disclosure itself, in every card language and on the street sign: "Location approximate — ward may be wrong (±850 m)".
The address cache also went from ~110 m cells to ~11 m. The first point to land in a cell answered for all of it for a month, and 110 m is not a rounding error when the boundary that matters is 50 m away.
The shutter is fast again
v1.45.0 moved ImageCapture.takePhoto() to the front of the capture path to stop the preview-quality dial capping photo resolution. It fixed that and broke the thing the app is for: takePhoto() asks the camera for a fresh still, which on Android means reconfiguring the session and running autofocus and exposure convergence first.
| before | after | |
|---|---|---|
| frame grab | 42.2 ms | 2.4 ms |
| whole blocking unit | — | 6.6 ms |
| burst of 10 taps | 5 saved | 10 saved |
Bursts were losing half of everything, silently: one shot in flight plus four remembered, so ten taps saved five. That bound is now 24, and if it is ever reached it says so out loud.
Full-sensor stills survive as a setting in Advanced that states what they cost. Off by default — a missed frame cannot be recovered by any amount of resolution.
The card is readable on any photo
The blue jurisdiction rows measured 1.77:1 against a dark scene, where 4.5:1 is the readable threshold. At the opacity slider's floor the whole card fell to 1.19:1 — invisible.
A translucent panel is not a background: at 55% the ink is read against a blend of the panel and whatever street was behind it. The panel now reads the pixels it is about to cover and works out the least opacity that keeps every ink legible over that scene. Your slider became a floor — honoured when it is already legible, raised when it is not, never lowered.
Also fixed: the mock-location disclosure was amber on white at 1.67:1, so the one row that exists to stop a spoofed photo passing as genuine was the least readable thing on the card. New Auto theme picks dark or light per photo.
Flash: off, automatic, always on
The platform exposes a steady lamp, not a shutter-synced flash, so the modes control when it is lit — pulsing it per shot would put several hundred milliseconds back between taps.
Automatic measures the sensor's own effort (ISO, exposure time) rather than the preview's pixels, because a preview is auto-exposed and a pitch-dark room and an overcast afternoon both arrive as mid-grey. A phone that reports neither does nothing in Automatic rather than firing blindly; Settings → Advanced → Diagnostics says which signal it had.
Selection band and delete
New icons drawn for this app, the band styled as a board with the street sign's doubled rule, and Delete set apart by a rule and a well as well as by colour — colour reaches no red-green colourblind user.
The confirmation was also telling you something false. It said photos would be "removed permanently from this device". They are not: deleting drops the app's own record, and the JPEG saved to your phone's gallery is untouched. It now says so.
Contrast, shutter latency, location honesty, accessibility and flash logic each have a check that runs on every build (npm run check:contrast, check:shutter, check:location, check:a11y, check:flash). Each was verified to fail when the bug it guards is put back.
Install the APK below, or add the repo in Obtainium for automatic updates.
v1.45.0 — sharp photos without turning quality up
Why the app's watermark was soft and the browser's was not
In the app, at 1× zoom, the saved photo was the preview frame. And the preview is deliberately capped — 1080p, or 720p on an entry phone — to keep the viewfinder smooth. So one setting was quietly doing two jobs: preview smoothness and photo resolution.
The browser never took that shortcut. That is why the web app is sharp at every setting and never lags: there, Capture quality only means "how heavy is the preview", and the photo always comes off the sensor.
Photos now come from the sensor first, with the preview frame as the fallback it should always have been. On a device that supports it, Automatic now gives you a smooth preview and a full-resolution photo — so you should not need Max at all.
Please do not leave Capture quality on Max if you have an older phone. It makes the preview stream heavy, which is the lag you saw.
Check what your phone actually does
Settings → Advanced → Diagnostics now reports:
last photo: 4000×3000 from the sensor
or
last photo: 1080×1920 from the preview frame
If it says sensor, this release fixed it and you can put Capture quality back to Automatic. If it says preview frame, this change did nothing on that device — Android's WebView has historically not offered the sensor path — and the real fix is a native capture path, which is a larger change worth deciding on evidence rather than assumption.
The Capture quality hint now mentions photos too. It previously described only the preview and video, which is why none of this was discoverable.
Not fixed
The report that Max also makes the watermark weirdly large on older phones. The card scales linearly with the image's short side, so it should stay a constant fraction of any photo — I could not reproduce or explain it, and would rather name it than guess.
versionCode 121 · signing key unchanged.
v1.44.2 — your own map data titles the card, whatever the provider
Third attempt at the "Velachery" report, and this one also tells you why if it is still wrong.
The path that was still unguarded
v1.44.0 only checked the address in Automatic mode, on the reasoning that a provider you pinned by hand should be honoured. But System (Android) is one of those options — and Android's own geocoder is exactly the one saying "Velachery". If your Address provider is set to System, the check never ran.
Every mode now applies the same rule: an answer our boundary data cannot corroborate can still supply the street line, but it never titles the card. Pinning a provider still means no other is consulted — it just does not let a doubtful name become the heading.
Settings → Advanced → Address diagnostics
A new row showing exactly what happened on your device:
- which provider answered
- whether it agreed with our map data
- what our own data says about that spot
- whether the title was suppressed
If you still see a wrong heading, screenshot that row. It states the cause; a photo of the watermark only states the symptom.
"Velachery" is real upstream data — another GPS camera app printed the same street line at that spot in 2024. This release does not make that string disappear. It stops it being the claim your photo leads with: the heading now comes from the municipality resolved from our own polygons.
versionCode 120 · signing key unchanged — installs over any 1.41.0+.
v1.44.1 — the Velachery fix, actually applied
v1.44.0 added the check. This makes it reach your phone.
Why 1.44.0 did not fix it
The app looks in its address cache before asking any geocoder, and returns straight away on a hit. That spot had been photographed before, so "Velachery" was already cached with a 30-day life — and the new check never saw it. The browser was correct because it is a separate app with a separate cache.
Cached answers are now re-checked the same as any fresh one, and the cache has been retired wholesale so nothing written under the old rules survives. A cached correct answer still costs no request.
And when there is no better answer
"Velachery" is not a glitch this app can argue its way out of — another GPS camera app photographed the same spot in 2024 and printed the same street line. It is what the upstream address data says, and offline there may be no second opinion.
So when nothing corroborates, the street line is kept — a rough address beats none — but it is no longer allowed to title the card. The heading falls back to the municipality resolved from our own boundary data. Your card will now read Maraimalainagar, with the disputed street line below it where it belongs. That holds even with no signal.
Also fixed
A regression from 1.44.0: with the new check, a second geocoder gets consulted after a doubtful first answer — and offline that request throws, which discarded the answer already in hand and left the photo with no address at all. Each provider is now isolated so one failing cannot lose another's result.
versionCode 119 · signing key unchanged — installs straight over any 1.41.0+.
v1.44.0 — clean place names, and addresses checked against our own data
Both fixes from a card photographed at Maraimalainagar.
"Maraimalai_Nagar" and friends are gone
That underscore came from the pack builder, not the source data: its recasing step treated _ as a letter, so BODI_TALUK became Bodi_taluk instead of Bodi Taluk. Fixed at the source and swept across every pack — 217 values in 7 packs:
- 116 underscores in station, place, block and city names
- doubled spaces in Bengaluru, Delhi, Mumbai and Chennai names
K9.Thiru .Vi.Ka. Nagar→K9.Thiru.Vi.Ka. Nagar- six multipart ward ids (
011_1is ward 011 drawn as two polygons — it printed as "Ward 11 1")
Verified as 217 text changes and zero structural changes: identical feature counts, geometry untouched.
npm run check:packs now fails the build on any of it, so it cannot come back.
The same place no longer gives two different addresses
The browser said "Sattamangalam"; the Android app said "Velachery" — a Chennai neighbourhood 25 km away — and used it as the card title. Android's own geocoder produced that, and it is tried first because it is free and works offline.
The app now checks every geocoder answer against its own offline jurisdiction data before accepting it. The packs are the reason this app exists; they are authoritative, and an outside geocoder that names nowhere we resolved does not get to title your card. If an answer doesn't corroborate, the next provider gets a turn — and if none do, you still get an address. So this can only improve on what came before, and never leaves a photo without one.
A correct answer is still accepted instantly with no network call, so nothing got slower.
Honest limit: this is corroboration, not proof. Where our data knows only a municipality name and every provider names only a street and a state, nothing corroborates and the first answer stands. Catching that needs a stronger check — rejecting a place name our own maps can locate somewhere else — which is a follow-up.
versionCode 118 · signing key unchanged — installs straight over 1.41.0+.
Every pack version changed so installs re-read them. Inside the app that is a local file, not a download.
v1.43.0 — share, albums and tagging from the selection band
All from testing feedback on v1.42.0.
Selection band
Hold a photo, then Share · Add to album · Tag · Delete. The band scrolls sideways, so labels never get squeezed.
Sharing a selection tells the truth about place
Captioning five photos from five different streets with one street's address would be a false claim about the other four. So:
- All from the same spot (within 120 m) → the usual full context: address, DIGIPIN, corporation, ward, zone, both police stations, and the maps link.
- From different places → the caption says only how many and when, plus a line noting they were taken at different places. No address, no coordinates, no maps link.
- A photo with no location makes the batch count as mixed — an unknown place can't be claimed to match the others.
This is about the caption. Each photo keeps its own burned-in card and its own EXIF — how you share a photo doesn't change what the photo itself records.
One share sheet for the whole selection, not one per photo.
Albums
Real named collections, separate from tags — an album is something you put photos in, a tag describes what a photo is. Albums get their own filter chips, are searchable, and are included in your backup automatically.
Fixed: double-tap wouldn't zoom out
Reported: double-tap zoomed in, but double-tapping again did nothing. The viewer had stopped recognising taps entirely once a photo was zoomed — which also broke tap-to-hide-the-controls. Both work now; pinch still handles fine control.
Backup & restore
Moved to Settings → Advanced, and rebuilt to look like the rest of Settings instead of three paragraphs of prose. It no longer claims to be "watching" your photo folder — it never was. New photos are added as you take them; recovery is only needed after a reinstall, or for photos copied from another device.
versionCode 116 · signing key unchanged — installs straight over v1.41.0 or v1.42.0.
v1.42.0 — one-tap folder scan, no photo permission
Settings → Backup & restore → Choose your GPS Camera folder.
Pick DCIM › GPS Camera once. From then on, Scan for new photos rebuilds your gallery from the files already on your phone — after a reinstall, or any time the app's copy and your gallery drift apart.
It does not ask for photo permission
The obvious way to do this is READ_MEDIA_IMAGES — access to your entire photo library, plus a Google Play declaration. This app does not do that. It uses Android's Storage Access Framework, so you grant access to that one folder and nothing else, permanently.
The permission list in this APK is unchanged from v1.41.0. You can check it yourself: aapt dump permissions.
Scans are cheap, because of the filenames
Every photo is named IMG_20260807_183241_gpscam.jpg. The scan reads the names first, so a photo you already have is recognised without opening the file. A folder of 2,000 photos with nothing new does no file reading at all — only genuinely new photos are read, four at a time so memory stays flat.
That filename is now also used as a fallback when a photo's EXIF has been stripped (messaging apps often do this), so it still lands at the right moment in your timeline.
Deleted photos stay deleted
A photo you delete in the app is still in your device gallery, so a scan would have imported it straight back. It no longer does — deletions are remembered and skipped by every future scan and import.
Web app
Browsers have no folder grant, so the web version keeps the multi-select picker. Same rebuild logic underneath.
versionCode 115 · minSdk 24 · targetSdk 36. Signing key unchanged from v1.40.1 — installs straight over v1.40.1 or v1.41.0, no uninstall.