feat: completar integracion M530 backend, telemetria y cierre SOS central
This commit is contained in:
parent
41b81c972a
commit
1b130a9ed8
5 changed files with 82 additions and 5 deletions
|
|
@ -1,5 +1,7 @@
|
||||||
package com.bodycamera.twentyfoulabs.data.auth
|
package com.bodycamera.twentyfoulabs.data.auth
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
|
||||||
import com.bodycamera.twentyfoulabs.data.backend.BackendConfig
|
import com.bodycamera.twentyfoulabs.data.backend.BackendConfig
|
||||||
import com.bodycamera.twentyfoulabs.data.backend.DeviceIdentity
|
import com.bodycamera.twentyfoulabs.data.backend.DeviceIdentity
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
|
@ -44,6 +46,18 @@ class AuthApiClient @Inject constructor(
|
||||||
json.decodeFromString<LoginResponse>(response)
|
json.decodeFromString<LoginResponse>(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun refresh(request: RefreshRequest): RefreshResponse =
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
val body = json.encodeToString(request)
|
||||||
|
val response = request(
|
||||||
|
"POST",
|
||||||
|
"/mobile/v1/auth/refresh",
|
||||||
|
body = body
|
||||||
|
)
|
||||||
|
Log.i("AuthApiClient", "AUTH REFRESH OK")
|
||||||
|
json.decodeFromString<RefreshResponse>(response)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun me(token: String): MeResponse =
|
suspend fun me(token: String): MeResponse =
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
val response = request(
|
val response = request(
|
||||||
|
|
@ -173,3 +187,9 @@ class AuthApiException(
|
||||||
val statusCode: Int,
|
val statusCode: Int,
|
||||||
override val message: String
|
override val message: String
|
||||||
) : Exception(message)
|
) : Exception(message)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,11 @@ data class LoginRequest(
|
||||||
@SerialName("device_model") val deviceModel: String? = null
|
@SerialName("device_model") val deviceModel: String? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class RefreshRequest(
|
||||||
|
@SerialName("refresh_token") val refreshToken: String
|
||||||
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class QrLoginRequest(
|
data class QrLoginRequest(
|
||||||
@SerialName("qr_token") val qrToken: String,
|
@SerialName("qr_token") val qrToken: String,
|
||||||
|
|
@ -63,6 +68,15 @@ data class LoginResponse(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class RefreshResponse(
|
||||||
|
@SerialName("access_token") val accessToken: String? = null,
|
||||||
|
@SerialName("refresh_token") val refreshToken: String? = null,
|
||||||
|
@SerialName("token_type") val tokenType: String? = null,
|
||||||
|
@SerialName("expires_in") val expiresIn: Int? = null,
|
||||||
|
@SerialName("server_time") val serverTime: String? = null
|
||||||
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class MeResponse(
|
data class MeResponse(
|
||||||
val user: AuthUser,
|
val user: AuthUser,
|
||||||
|
|
@ -88,3 +102,7 @@ data class AuthSession(
|
||||||
val device: AuthDevice? = null,
|
val device: AuthDevice? = null,
|
||||||
val refreshToken: String? = null
|
val refreshToken: String? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -127,11 +127,21 @@ session
|
||||||
|
|
||||||
} catch (e: AuthApiException) {
|
} catch (e: AuthApiException) {
|
||||||
|
|
||||||
if (e.statusCode == 401) {
|
if (e.statusCode == 401 && !refreshToken.isNullOrBlank()) {
|
||||||
|
android.util.Log.i("AuthRepository", "401 inicial detectado - intentando refresh")
|
||||||
|
val refreshed = api.refresh(RefreshRequest(refreshToken))
|
||||||
|
val newToken = refreshed.accessToken?.takeIf { it.isNotBlank() } ?: throw e
|
||||||
|
val refreshedResponse = try { api.me(newToken) } catch (retryError: AuthApiException) { if (retryError.statusCode == 401) { store.clear(); android.util.Log.i("AuthRepository", "Segundo 401 - sesion eliminada"); throw retryError } else { throw retryError } }
|
||||||
|
val newRefreshToken = refreshed.refreshToken?.takeIf { it.isNotBlank() } ?: refreshToken
|
||||||
|
val refreshedSession = AuthSession(token = newToken, user = refreshedResponse.user, device = refreshedResponse.device ?: refreshedResponse.user.assignedDevice, refreshToken = newRefreshToken)
|
||||||
|
store.save(refreshedSession)
|
||||||
|
refreshedSession
|
||||||
|
} else if (e.statusCode == 401) {
|
||||||
store.clear()
|
store.clear()
|
||||||
|
throw e
|
||||||
|
} else {
|
||||||
|
throw e
|
||||||
}
|
}
|
||||||
|
|
||||||
throw e
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,3 +163,20 @@ suspend fun logout() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.bodycamera.twentyfoulabs.data.device
|
package com.bodycamera.twentyfoulabs.data.device
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
|
|
@ -82,8 +83,11 @@ class M530DeviceController @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val powerReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { if (intent?.action == Intent.ACTION_POWER_CONNECTED || intent?.action == Intent.ACTION_POWER_DISCONNECTED) { Log.i(TAG, "Cambio de cargador detectado: ${intent.action}"); logTelemetry() } } }
|
||||||
|
|
||||||
init {
|
init {
|
||||||
startLocationUpdates()
|
startLocationUpdates()
|
||||||
|
context.registerReceiver(powerReceiver, IntentFilter().apply { addAction(Intent.ACTION_POWER_CONNECTED); addAction(Intent.ACTION_POWER_DISCONNECTED) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -460,7 +464,7 @@ Result.success(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (location == null) {
|
if (location == null) {
|
||||||
Log.w(TAG, "GPS: sin ubicación reciente; se omite el envÃÂÂo")
|
Log.w(TAG, "GPS: sin ubicación reciente; se omite el envÃÂo")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -609,3 +613,6 @@ Result.success(file)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -203,6 +203,10 @@ private fun vibrateRecordingStopped() {
|
||||||
result.onSuccess { state ->
|
result.onSuccess { state ->
|
||||||
val previous = centralSosCadenceActive
|
val previous = centralSosCadenceActive
|
||||||
centralSosCadenceActive = state.isSosCadenceActive
|
centralSosCadenceActive = state.isSosCadenceActive
|
||||||
|
if (previous && !centralSosCadenceActive && sosSessionActive.get()) {
|
||||||
|
Log.i(TAG, "SOS cerrado desde central - finalizando sesion SOS local")
|
||||||
|
stopVideoFromUi()
|
||||||
|
}
|
||||||
if (previous != centralSosCadenceActive) {
|
if (previous != centralSosCadenceActive) {
|
||||||
Log.i(
|
Log.i(
|
||||||
TAG,
|
TAG,
|
||||||
|
|
@ -668,3 +672,4 @@ data class DeviceStatus(
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue