Handoff
Listo para abrir Android Studio
Estructura de módulos, contratos de cada capa, pantallas y el checklist que sigue el equipo nativo desde el primer commit hasta la prueba A en verde.
PROTOTIPO WEB / ESPECIFICACIÓNNO DEMOSTRADO EN HARDWARE
Punto de partida
- Android Studio con AGP y Kotlin recientes; JDK 17; minSdk 26 y targetSdk al último nivel estable.
- Kotlin, Jetpack Compose, corrutinas y Flow; Hilt para inyección; WorkManager para la cola.
- Dos teléfonos físicos de fabricantes distintos desde el día uno: la radio no se prueba en emulador.
- Ninguna capa de negocio importa una API del sistema: solo las interfaces del módulo domain.
Estructura de módulos
conecta-android/
├── settings.gradle.kts
├── build-logic/ convenciones de compilación compartidas
├── app/ ensamblado, navegación e inyección
├── core/
│ ├── model/ modelos puros, sin Android
│ ├── common/ Result, corrutinas, tiempo, logging
│ └── designsystem/ tema, tipografía, componentes Compose
├── feature/
│ ├── needhelp/ MODO 1 — necesito Internet
│ ├── offerhelp/ MODO 2 — quiero ayudar
│ ├── session/ sesión activa y finalización
│ └── history/ historial, seguridad y uso justo
├── domain/ casos de uso + interfaces de las capas
└── data/
├── discovery-ble/ BLE advertising y scanning
├── transport-p2p/ GATT y sockets Wi-Fi Direct
├── security-crypto/ X25519, HKDF, AES-GCM, Keystore
├── network-config/ panel de Ajustes y WifiNetworkSpecifier
├── local-store/ SQLite cifrada y outbox
└── sync/ WorkManager, envío idempotenteCada módulo de data implementa exactamente una interfaz de domain. Así el mismo diseño se traslada a iOS y una capa puede sustituirse sin tocar la lógica.
Interfaces de las capas
// domain/src/main/kotlin/.../ports
interface PeerDiscovery {
fun advertise(profile: EphemeralProfile): Flow<AdvertiseState>
fun scan(): Flow<List<DiscoveredPeer>> // alias efímero + rango de distancia
suspend fun stop()
}
interface PeerTransport {
suspend fun connect(peer: DiscoveredPeer): TransportChannel
fun incoming(): Flow<TransportChannel>
}
interface SecurityManager {
fun newEphemeralIdentity(): EphemeralIdentity
suspend fun handshake(channel: TransportChannel, id: EphemeralIdentity): SecureChannel
fun wipe(sessionId: SessionId)
}
interface NetworkConfigurator {
suspend fun openTetheringPanel(): PanelResult // confirmación del sistema
suspend fun joinNetwork(cred: OneTimeCredential): JoinResult // WifiNetworkSpecifier
fun hasRealInternet(): Flow<Boolean> // NetworkCapabilities + tráfico
}
interface SessionManager {
val state: StateFlow<SessionState> // IDLE, NEGOCIANDO, ACTIVA, TERMINADA
suspend fun start(agreement: Agreement)
suspend fun endNow(reason: EndReason)
}
interface FairUseManager { fun evaluate(history: List<SessionRecord>): FairUseVerdict }
interface LocalEventStore {
suspend fun append(event: SessionEvent) // nunca guarda secretos
fun outbox(): Flow<List<SessionEvent>>
}
interface SyncManager { fun scheduleUpload() }HIPÓTESIS TÉCNICA — REQUIERE VALIDACIÓN EN HARDWAREPantallas
| Pantalla | Contenido | Capa que la alimenta |
|---|---|---|
| Inicio | Elegir necesito ayuda o quiero ayudar | — |
| Motivo | Mensaje, transporte, dirección, llamada, emergencia, otro | domain |
| Necesidad | MB (100/250/500/1 GB) y minutos (5/15/30/60) | domain |
| Buscando | Escaneo activo, aviso de permisos y radio | PeerDiscovery |
| Ayudantes cerca | Alias efímero, distancia por rangos, oferta, reputación | PeerDiscovery |
| Solicitud enviada | Espera de respuesta con posibilidad de cancelar | PeerTransport |
| Solicitud entrante | Motivo y límites; aceptar o rechazar | PeerTransport |
| Guía de hotspot | Explicación y apertura del panel de Ajustes | NetworkConfigurator |
| Unirse | Diálogo del sistema y verificación de Internet real | NetworkConfigurator |
| Sesión activa | Temporizador, MB estimados y FINALIZAR AHORA | SessionManager |
| Resumen | Cierre, borrado de secretos y aviso de uso justo | FairUseManager |
| Historial | Eventos locales y estado de la cola | LocalEventStore |
| Seguridad | Consentimiento, bloqueo, reporte y privacidad | domain |
Checklist para el equipo nativo
| Paso | Terminado cuando | |
|---|---|---|
| 1 | Crear el proyecto y los módulos vacíos con las convenciones de build | Compila y arranca en los dos teléfonos |
| 2 | Declarar las interfaces de domain y modelos puros | domain no depende de ningún artefacto de Android |
| 3 | Pantallas Compose con datos falsos y etiquetas de estado | Se recorre el flujo completo sin radio |
| 4 | Permisos en tiempo de ejecución y pantallas de denegación | Cada permiso tiene explicación y salida sin bloqueo |
| 5 | BLE: anuncio y escaneo con identidad efímera | Prueba A en verde |
| 6 | Distancia por rangos y rotación de alias | Pruebas C y D en verde |
| 7 | Canal GATT y handshake X25519 + HKDF + AES-GCM | Prueba G en verde |
| 8 | Negociación de límites y consentimiento de ambos | Pruebas E, F y K en verde |
| 9 | Servicio en primer plano y comportamiento en segundo plano | Prueba B en verde por fabricante |
| 10 | Guía de hotspot y unión con WifiNetworkSpecifier | Pruebas H y J en verde |
| 11 | Verificación de Internet real con tráfico registrado | Prueba I en verde |
| 12 | Finalización inmediata y borrado de secretos | Pruebas L, M y N en verde |
| 13 | Cola local cifrada y envío idempotente | Pruebas O y P en verde |
| 14 | Errores de alcance y bloqueo de operador con estado claro | Pruebas Q y R documentadas |
| 15 | Ficha de compatibilidad por dispositivo y versión | Pixel, Samsung y Xiaomi con registro |
Ningún paso se marca como hecho sin registro de prueba física con dispositivo, versión, hora, resultado y evidencia.
Reglas que no se negocian
- · La app nunca enciende el compartir de conexión: siempre lo confirma el ayudante.
- · La app nunca lee ni muestra la contraseña del hotspot del sistema.
- · La app no corta el tráfico del invitado: el límite es un acuerdo, no un control.
- · Cero interacción física entre las personas en todo el flujo.
- · Nada se presenta como funcional mientras su prueba diga NO PROBADO.
El orden de hitos está en Fase 1, las APIs y permisos exactos en el prototipo Android y las pruebas en el plan de pruebas.