From 3097cc730572ef57e710e6cb501e0486402afba2 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 9 Sep 2026 21:17:53 +0000
Subject: [PATCH] fix(android): handle location permission races and optional
camera
---
.../workflows/f6-1-apply-android-lint-fix.yml | 75 -------------------
android-app/app/src/main/AndroidManifest.xml | 1 +
.../com/korexlabs/dhinspeccion/ui/DhApp.kt | 18 +++--
.../korexlabs/dhinspeccion/ui/F3VisitRoot.kt | 22 +++---
.../dhinspeccion/ui/FieldFindingScreen.kt | 18 +++--
.../dhinspeccion/ui/MobileActsScreen.kt | 20 +++--
6 files changed, 48 insertions(+), 106 deletions(-)
delete mode 100644 .github/workflows/f6-1-apply-android-lint-fix.yml
diff --git a/.github/workflows/f6-1-apply-android-lint-fix.yml b/.github/workflows/f6-1-apply-android-lint-fix.yml
deleted file mode 100644
index 229e3fc..0000000
--- a/.github/workflows/f6-1-apply-android-lint-fix.yml
+++ /dev/null
@@ -1,75 +0,0 @@
-name: F6.1 apply Android lint fix
-
-on:
- push:
- branches:
- - 'release/f6-1-presentation-ready'
- paths:
- - '.github/workflows/f6-1-apply-android-lint-fix.yml'
-
-permissions:
- contents: write
-
-jobs:
- apply:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- with:
- ref: release/f6-1-presentation-ready
- fetch-depth: 0
-
- - name: Apply targeted runtime fixes
- run: |
- python - <<'PY'
- from pathlib import Path
-
- replacements = {
- 'android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/DhApp.kt': (
- ''' val source = CancellationTokenSource()\n val client = LocationServices.getFusedLocationProviderClient(context)\n client.getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, source.token)\n .addOnSuccessListener { location ->\n if (!continuation.isActive) return@addOnSuccessListener\n if (location == null) continuation.resumeWithException(IllegalStateException("No se pudo obtener una ubicación GPS actual."))\n else continuation.resume(GeoSnapshot(location.latitude, location.longitude, location.accuracy.toDouble()))\n }\n .addOnFailureListener { if (continuation.isActive) continuation.resumeWithException(it) }\n continuation.invokeOnCancellation { source.cancel() }''',
- ''' val source = CancellationTokenSource()\n val client = LocationServices.getFusedLocationProviderClient(context)\n try {\n client.getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, source.token)\n .addOnSuccessListener { location ->\n if (!continuation.isActive) return@addOnSuccessListener\n if (location == null) continuation.resumeWithException(IllegalStateException("No se pudo obtener una ubicación GPS actual."))\n else continuation.resume(GeoSnapshot(location.latitude, location.longitude, location.accuracy.toDouble()))\n }\n .addOnFailureListener { if (continuation.isActive) continuation.resumeWithException(it) }\n } catch (error: SecurityException) {\n if (continuation.isActive) continuation.resumeWithException(error)\n }\n continuation.invokeOnCancellation { source.cancel() }''',
- ),
- 'android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/F3VisitRoot.kt': (
- ''' val source = CancellationTokenSource()\n val client = LocationServices.getFusedLocationProviderClient(context)\n client.getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, source.token)\n .addOnSuccessListener { location ->\n if (!continuation.isActive) return@addOnSuccessListener\n if (location == null) {\n continuation.resumeWithException(IllegalStateException("No se pudo obtener una ubicación GPS actual."))\n } else {\n continuation.resume(F3GeoSnapshot(location.latitude, location.longitude, location.accuracy.toDouble()))\n }\n }\n .addOnFailureListener { if (continuation.isActive) continuation.resumeWithException(it) }\n continuation.invokeOnCancellation { source.cancel() }''',
- ''' val source = CancellationTokenSource()\n val client = LocationServices.getFusedLocationProviderClient(context)\n try {\n client.getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, source.token)\n .addOnSuccessListener { location ->\n if (!continuation.isActive) return@addOnSuccessListener\n if (location == null) {\n continuation.resumeWithException(IllegalStateException("No se pudo obtener una ubicación GPS actual."))\n } else {\n continuation.resume(F3GeoSnapshot(location.latitude, location.longitude, location.accuracy.toDouble()))\n }\n }\n .addOnFailureListener { if (continuation.isActive) continuation.resumeWithException(it) }\n } catch (error: SecurityException) {\n if (continuation.isActive) continuation.resumeWithException(error)\n }\n continuation.invokeOnCancellation { source.cancel() }''',
- ),
- 'android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/FieldFindingScreen.kt': (
- ''' val source = CancellationTokenSource()\n val client = LocationServices.getFusedLocationProviderClient(context)\n client.getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, source.token)\n .addOnSuccessListener { location ->\n if (!continuation.isActive) return@addOnSuccessListener\n if (location == null) continuation.resumeWithException(IllegalStateException("No se pudo obtener una ubicación GPS actual."))\n else continuation.resume(FindingGeoSnapshot(location.latitude, location.longitude, location.accuracy.toDouble()))\n }\n .addOnFailureListener { if (continuation.isActive) continuation.resumeWithException(it) }\n continuation.invokeOnCancellation { source.cancel() }''',
- ''' val source = CancellationTokenSource()\n val client = LocationServices.getFusedLocationProviderClient(context)\n try {\n client.getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, source.token)\n .addOnSuccessListener { location ->\n if (!continuation.isActive) return@addOnSuccessListener\n if (location == null) continuation.resumeWithException(IllegalStateException("No se pudo obtener una ubicación GPS actual."))\n else continuation.resume(FindingGeoSnapshot(location.latitude, location.longitude, location.accuracy.toDouble()))\n }\n .addOnFailureListener { if (continuation.isActive) continuation.resumeWithException(it) }\n } catch (error: SecurityException) {\n if (continuation.isActive) continuation.resumeWithException(error)\n }\n continuation.invokeOnCancellation { source.cancel() }''',
- ),
- 'android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/MobileActsScreen.kt': (
- ''' val source = CancellationTokenSource()\n LocationServices.getFusedLocationProviderClient(context)\n .getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, source.token)\n .addOnSuccessListener { location ->\n if (!continuation.isActive) return@addOnSuccessListener\n if (location == null) continuation.resumeWithException(IllegalStateException("Ubicación no disponible"))\n else continuation.resume(ActSignatureGeo(location.latitude, location.longitude, location.accuracy.toDouble()))\n }\n .addOnFailureListener { if (continuation.isActive) continuation.resumeWithException(it) }\n continuation.invokeOnCancellation { source.cancel() }''',
- ''' val source = CancellationTokenSource()\n try {\n LocationServices.getFusedLocationProviderClient(context)\n .getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, source.token)\n .addOnSuccessListener { location ->\n if (!continuation.isActive) return@addOnSuccessListener\n if (location == null) continuation.resumeWithException(IllegalStateException("Ubicación no disponible"))\n else continuation.resume(ActSignatureGeo(location.latitude, location.longitude, location.accuracy.toDouble()))\n }\n .addOnFailureListener { if (continuation.isActive) continuation.resumeWithException(it) }\n } catch (error: SecurityException) {\n if (continuation.isActive) continuation.resumeWithException(error)\n }\n continuation.invokeOnCancellation { source.cancel() }''',
- ),
- }
-
- for file_name, (before, after) in replacements.items():
- path = Path(file_name)
- text = path.read_text()
- count = text.count(before)
- if count != 1:
- raise SystemExit(f'{file_name}: expected exactly one GPS block, found {count}')
- path.write_text(text.replace(before, after))
-
- manifest = Path('android-app/app/src/main/AndroidManifest.xml')
- text = manifest.read_text()
- before = ' \n'
- after = before + ' \n'
- if text.count(before) != 1:
- raise SystemExit('AndroidManifest.xml: CAMERA permission block not unique')
- if 'android.hardware.camera' not in text:
- manifest.write_text(text.replace(before, after))
-
- # Self-delete so this one-shot workflow never ships in the release branch.
- Path('.github/workflows/f6-1-apply-android-lint-fix.yml').unlink()
- PY
-
- - name: Commit targeted fixes
- run: |
- set -Eeuo pipefail
- git config user.name 'github-actions[bot]'
- git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
- git add android-app .github/workflows/f6-1-apply-android-lint-fix.yml
- git diff --cached --check
- git commit -m 'fix(android): handle location permission races and optional camera'
- git push origin HEAD:release/f6-1-presentation-ready
diff --git a/android-app/app/src/main/AndroidManifest.xml b/android-app/app/src/main/AndroidManifest.xml
index 73bfee0..9b26cae 100644
--- a/android-app/app/src/main/AndroidManifest.xml
+++ b/android-app/app/src/main/AndroidManifest.xml
@@ -3,6 +3,7 @@
+
diff --git a/android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/DhApp.kt b/android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/DhApp.kt
index 424be1e..7cc4bd8 100644
--- a/android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/DhApp.kt
+++ b/android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/DhApp.kt
@@ -547,13 +547,17 @@ private suspend fun currentGeo(context: Context): GeoSnapshot = suspendCancellab
}
val source = CancellationTokenSource()
val client = LocationServices.getFusedLocationProviderClient(context)
- client.getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, source.token)
- .addOnSuccessListener { location ->
- if (!continuation.isActive) return@addOnSuccessListener
- if (location == null) continuation.resumeWithException(IllegalStateException("No se pudo obtener una ubicación GPS actual."))
- else continuation.resume(GeoSnapshot(location.latitude, location.longitude, location.accuracy.toDouble()))
- }
- .addOnFailureListener { if (continuation.isActive) continuation.resumeWithException(it) }
+ try {
+ client.getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, source.token)
+ .addOnSuccessListener { location ->
+ if (!continuation.isActive) return@addOnSuccessListener
+ if (location == null) continuation.resumeWithException(IllegalStateException("No se pudo obtener una ubicación GPS actual."))
+ else continuation.resume(GeoSnapshot(location.latitude, location.longitude, location.accuracy.toDouble()))
+ }
+ .addOnFailureListener { if (continuation.isActive) continuation.resumeWithException(it) }
+ } catch (error: SecurityException) {
+ if (continuation.isActive) continuation.resumeWithException(error)
+ }
continuation.invokeOnCancellation { source.cancel() }
}
diff --git a/android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/F3VisitRoot.kt b/android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/F3VisitRoot.kt
index 2ca8670..7c28d8d 100644
--- a/android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/F3VisitRoot.kt
+++ b/android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/F3VisitRoot.kt
@@ -727,16 +727,20 @@ private suspend fun currentF3Geo(context: Context): F3GeoSnapshot = suspendCance
}
val source = CancellationTokenSource()
val client = LocationServices.getFusedLocationProviderClient(context)
- client.getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, source.token)
- .addOnSuccessListener { location ->
- if (!continuation.isActive) return@addOnSuccessListener
- if (location == null) {
- continuation.resumeWithException(IllegalStateException("No se pudo obtener una ubicación GPS actual."))
- } else {
- continuation.resume(F3GeoSnapshot(location.latitude, location.longitude, location.accuracy.toDouble()))
+ try {
+ client.getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, source.token)
+ .addOnSuccessListener { location ->
+ if (!continuation.isActive) return@addOnSuccessListener
+ if (location == null) {
+ continuation.resumeWithException(IllegalStateException("No se pudo obtener una ubicación GPS actual."))
+ } else {
+ continuation.resume(F3GeoSnapshot(location.latitude, location.longitude, location.accuracy.toDouble()))
+ }
}
- }
- .addOnFailureListener { if (continuation.isActive) continuation.resumeWithException(it) }
+ .addOnFailureListener { if (continuation.isActive) continuation.resumeWithException(it) }
+ } catch (error: SecurityException) {
+ if (continuation.isActive) continuation.resumeWithException(error)
+ }
continuation.invokeOnCancellation { source.cancel() }
}
diff --git a/android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/FieldFindingScreen.kt b/android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/FieldFindingScreen.kt
index acc6c63..9b4b882 100644
--- a/android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/FieldFindingScreen.kt
+++ b/android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/FieldFindingScreen.kt
@@ -389,13 +389,17 @@ private suspend fun currentFindingGeo(context: Context): FindingGeoSnapshot = su
}
val source = CancellationTokenSource()
val client = LocationServices.getFusedLocationProviderClient(context)
- client.getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, source.token)
- .addOnSuccessListener { location ->
- if (!continuation.isActive) return@addOnSuccessListener
- if (location == null) continuation.resumeWithException(IllegalStateException("No se pudo obtener una ubicación GPS actual."))
- else continuation.resume(FindingGeoSnapshot(location.latitude, location.longitude, location.accuracy.toDouble()))
- }
- .addOnFailureListener { if (continuation.isActive) continuation.resumeWithException(it) }
+ try {
+ client.getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, source.token)
+ .addOnSuccessListener { location ->
+ if (!continuation.isActive) return@addOnSuccessListener
+ if (location == null) continuation.resumeWithException(IllegalStateException("No se pudo obtener una ubicación GPS actual."))
+ else continuation.resume(FindingGeoSnapshot(location.latitude, location.longitude, location.accuracy.toDouble()))
+ }
+ .addOnFailureListener { if (continuation.isActive) continuation.resumeWithException(it) }
+ } catch (error: SecurityException) {
+ if (continuation.isActive) continuation.resumeWithException(error)
+ }
continuation.invokeOnCancellation { source.cancel() }
}
diff --git a/android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/MobileActsScreen.kt b/android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/MobileActsScreen.kt
index 2f2d3d9..d1d0749 100644
--- a/android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/MobileActsScreen.kt
+++ b/android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/MobileActsScreen.kt
@@ -431,13 +431,17 @@ private suspend fun currentActSignatureGeo(context: Context): ActSignatureGeo =
return@suspendCancellableCoroutine
}
val source = CancellationTokenSource()
- LocationServices.getFusedLocationProviderClient(context)
- .getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, source.token)
- .addOnSuccessListener { location ->
- if (!continuation.isActive) return@addOnSuccessListener
- if (location == null) continuation.resumeWithException(IllegalStateException("Ubicación no disponible"))
- else continuation.resume(ActSignatureGeo(location.latitude, location.longitude, location.accuracy.toDouble()))
- }
- .addOnFailureListener { if (continuation.isActive) continuation.resumeWithException(it) }
+ try {
+ LocationServices.getFusedLocationProviderClient(context)
+ .getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, source.token)
+ .addOnSuccessListener { location ->
+ if (!continuation.isActive) return@addOnSuccessListener
+ if (location == null) continuation.resumeWithException(IllegalStateException("Ubicación no disponible"))
+ else continuation.resume(ActSignatureGeo(location.latitude, location.longitude, location.accuracy.toDouble()))
+ }
+ .addOnFailureListener { if (continuation.isActive) continuation.resumeWithException(it) }
+ } catch (error: SecurityException) {
+ if (continuation.isActive) continuation.resumeWithException(error)
+ }
continuation.invokeOnCancellation { source.cancel() }
}