App Android
APX Android es una app nativa que encapsula la superficie de celular del daemon. Mantiene la UI móvil React existente como implementación única; Android maneja mascota flotante, notificaciones del sistema y apertura de la app.
La app abre /mobile, que el panel redirige a /m/chat — la dirección actual de
la superficie de celular, donde convive con /m/tasks y /m/commitments detrás
de una barra inferior.
Vincular una vez
Sección titulada «Vincular una vez»- Hacé accesible el daemon desde el teléfono, por LAN o puerto inverso ADB.
- Ejecutá
apx pair weben la máquina del daemon. - Ingresá URL del daemon y código mostrado dentro de APX Android.
- Otorgá permiso de notificaciones cuando Android lo solicite.
- Otorgá Mostrar sobre otras apps solo si querés mascota flotante.
La app recibe un token cliente propio kind: android. No reutiliza el token
guardado por Chrome o la PWA instalada porque Android aísla almacenamiento por
app. Pairing web existente sigue válido; ambos clientes aparecen en
apx pair list y pueden revocarse por separado.
Configuración del auto una sola vez
Sección titulada «Configuración del auto una sola vez»Android no permite que una app se otorgue acceso a notificaciones ni permiso No molestar. Instalación nueva necesita dos switches explícitos del sistema para experiencia completa:
| Capacidad | Acción única | Necesaria para |
|---|---|---|
| Notificaciones APX | Aceptar solicitud Android | Toda notificación APX |
| Avisos durante conducción | Menú APX → Permitir avisos durante conducción y activar APX en pantalla del sistema | Cards flotantes mientras Android Auto activa No molestar |
| Detección de viajes | Menú APX → Activar detección de viajes y activar acceso a notificaciones APX | Leer estado y destino de navegación Google Maps, y detectar una sesión de Android Auto |
| Ubicación | Elegir Mientras se usa la app | Enviar el origen del viaje y la posición en vivo durante el viaje |
| Overlay | Activar Mostrar sobre otras apps | Solo mascota flotante; no necesario para cards del auto |
| Batería | Menú APX → Quitar restricción de batería y confirmar el diálogo de Android | Que el inicio y el fin del viaje lleguen a tiempo con el teléfono en el bolsillo |
En configuración Android Auto, mantener Ver notificaciones de mensajes activo. Activar Mostrar la primera línea de los mensajes para ver texto APX en card, no solo anuncio de mensaje nuevo.
Comportamiento nativo
Sección titulada «Comportamiento nativo»- Inicio normal abre
<daemon>/mobiledentro de la app, no Chrome. - Mascota flota sobre escritorio y otras apps, puede arrastrarse y recuerda posición.
- Avatar sigue Ajustes → Super-agente → Avatar. WebSocket autenticado envía valor actual al conectar y cada cambio posterior; Android lo guarda local y repinta overlay inmediatamente.
- Se oculta mientras APX está abierta y reaparece cuando APX pasa al fondo.
- Eventos APX entrantes disparan burbuja, sonido incluido y notificación Android.
- Tocar mascota o notificación abre app nativa en
/mobile. - Notificación persistente de mascota incluye acción Ocultar.
- Puntos suspensivos exclusivos de app, junto a Preferencias, abren opciones nativas. Chrome y PWA instalada no los muestran.
- Opciones nativas permiten mutear/reactivar sonido sin desactivar mascota.
- Preferencias → Notificaciones muestra permiso Android real. Tocarlo abre ajustes de notificaciones de APX en sistema.
- Menú nativo permite activar Detección de viajes APX. Con acceso a
notificaciones otorgado, app detecta inicio y fin de navegación Google Maps
mediante metadatos de notificación. Muestra barra nativa con icono de auto y
acceso directo a Maps. Inicio nuevo envía evento autenticado
trip.starteda/api/mobility/events, con última ubicación disponible como origen. Si Maps omite destino, card Android Auto pregunta dónde vas; Responder acepta dictado de voz y completa mismo viaje. Cambiar destino inicia evaluación nueva. No sube ruta, historial ni contenido completo de notificaciones. - El banner de viaje abre los pendientes del viaje, no Maps: al tocarlo muestra
una tarjeta por mandado pendiente, del más cercano al más lejano, con los
mismos cuatro botones que trae la tarjeta de Telegram — Navegar, Sumar a la
ruta, Voy, En la siguiente. Un “voy” acá llega al mismo registro que un “voy” en
Telegram, y gana el mismo seguimiento después del viaje; una tarjeta ya
contestada muestra la respuesta en lugar de volver a preguntar. Cuando un
mandado todavía tiene varios lugares posibles la tarjeta lo dice, en vez de
presentar el más cercano como una decisión que APX ya tomó. La etiqueta de la
derecha lleva la cuenta en vivo (“8 cerca”). La lista sale de
GET /api/mobility/trip, que es de solo lectura (consultarla nunca dispara un recordatorio), y las respuestas van aPOST /api/mobility/errands/answer. Limitada a ocho mandados. - Mensajes de viaje tienen límite deliberado. Destino conocido debe quedar estable 45 segundos; navegación sin destino espera 10 minutos. Reabrir mismo destino queda silencioso 30 minutos; destino distinto no dispara otra evaluación Roby antes de 5 minutos. Cancelar/reiniciar rápido actualiza estado local sin ráfaga de mensajes. APX envía contexto de viaje al daemon apenas lo detecta; esas esperas limitan evaluación y avisos, no conciencia de Roby.
- Como alternativa explícita, desde Maps en teléfono elegí Compartir progreso
del viaje → Más → Compartir viaje con APX. APX acepta solo enlaces Google
Maps, adjunta ubicación permitida y actualiza viaje activo. Shares actuales
suelen traer solo enlace opaco
maps.app.goo.gl, sin texto de destino; APX debe mostrarlo como progreso compartido y nunca inventar destino. Android Auto puede mostrar solo contactos y ocultar share targets de apps; en ese caso hacelo desde teléfono o usá respuesta de voz APX. - Daemon pide a Roby revisar tareas y compromisos pendientes usando herramientas
de solo lectura. Eventos de viaje configurados por usuario se procesan al
instante, fuera de rondas y presupuesto proactivo, pero actualizan contexto
de movilidad en vez de forzar Telegram. Roby ve viaje actual, última pregunta
y última respuesta botonera durante chats y rondas de secretaria posteriores.
Solo escribe ante oportunidad nueva y concreta;
SILENTqueda como opción normal. Roby no afirma cercanía ni desvíos sin datos suficientes. - Con origen y destino disponibles, daemon geocodifica mediante Nominatim, calcula ruta con Valhalla/OSRM y busca comercios OpenStreetMap dentro de 700 m. Envía máximo tres coincidencias y enlaces Google Maps; cero coincidencias verificadas producen silencio.
- Aviso Telegram ofrece Sí, voy ahora, No podré, Recordarme luego y No avisar más hoy. Recordar luego crea delivery pendiente para próxima ronda. Cerrar Maps antes del envío cancela aviso pendiente.
- Android Auto es una segunda fuente de viaje, independiente de Maps. El
mismo listener de notificaciones reconoce la notificación de sesión de Android
Auto (“Android Auto · Conectado al vehículo”) y abre un viaje apenas el
teléfono proyecta en una head unit, con ruta cargada o sin ella. El banner
pasa a decir Estás en el auto. Los avisos (“tocá para configurar Android
Auto”) y la notificación del servidor de unidad principal de modo
desarrollador nunca cuentan como sesión. El viaje termina solo cuando se
apagan LAS DOS fuentes: una ruta que termina con el teléfono todavía enchufado
mantiene el mismo viaje y el mismo
trip_id. - Mientras hay un viaje activo, APX reporta posición a
/api/mobility/positionscada 30 s / 150 m desde un servicio en primer plano de tipolocation. Ese servicio es la razón por la que APX no pideACCESS_BACKGROUND_LOCATION: la notificación persistente “Viaje en curso” es el modelo de permiso, y el seguimiento se corta con el viaje. Cada muestra es un punto y su precisión: no se sube ni se guarda geometría de ruta ni historial de ubicación. - El daemon cruza cada posición con las tareas pendientes que nombran un mandado físico y avisa una vez cuando un lugar compatible queda a menos de 2 km. Un aviso por mandado y por viaje — una tarea “comprar ibuprofeno” que matchea trece farmacias recibe la más cercana, no trece tarjetas — y como mucho dos tarjetas por muestra. No se repite, ni siquiera después de reiniciar el daemon.
- La tarjeta de cercanía trae cuatro chips: Navegar y Sumar a la ruta (links profundos a Google Maps; “Sumar a la ruta” conserva el destino actual e inserta el lugar como parada), más Voy y Avisar en la siguiente. Contestar “Voy” es una promesa, no una acción: cuando el viaje termina APX pregunta ¿Pasaste por ese lugar? con Hecho — que cierra la tarea — y Todavía no, que la deja abierta.
- “Avisar en la siguiente” descarta el local, no el mandado. Dejar pasar la sucursal por la que justo venías manejando deja la tarea con un aviso pendiente: el próximo comercio que sirva para lo mismo todavía puede avisarte en el mismo viaje, y sólo la sucursal que descartaste no vuelve a aparecer. Cuando no hay siguiente se queda callado por el resto del viaje, que es lo que el viejo “Hoy no” le hacía al mandado entero al primer toque.
- Mientras hay un viaje activo, cada respuesta automática de Telegram sale dos
veces: primero una nota de voz y después las mismas palabras como texto bajo
una línea discreta
[Transcripción]— una etiqueta, no un cartel: el audio es el mensaje y el texto está para pasarle el ojo. El turno corre en modo voz, así que la respuesta son una o dos frases habladas y no un párrafo leído en voz alta. Si falla el TTS offmpegse pierde el audio, nunca el mensaje. Se apaga convoice.mobility_replies: false. El seguimiento de fin de viaje va en texto plano: se lee estacionado. - Delivery de movilidad también genera card Android APX y sonido local cuando sonido nativo está activo.
- Mensajes directos APX usan formato mensajería Android. Android Auto puede mostrarlos como avisos flotantes y leerlos sin abrir Telegram. Menú nativo incluye Probar aviso Android Auto para pruebas DHU o vehículo. Android Auto activa No molestar; concedé Avisos durante conducción una vez para permitir que APX lo atraviese.
Cuánto cuesta cuando no pasa nada
Sección titulada «Cuánto cuesta cuando no pasa nada»APX es una cáscara con un WebView adentro y, en reposo, no debería costar nada. El viaje es el único estado que puede ser caro: ahí corre el GPS y ahí un socket caído tiene que recuperarse en segundos.
- La mascota se anima mientras la arrastrás, salta o muestra un mensaje. En reposo mantiene la pose y solo parpadea, en lugar de redibujarse treinta veces por segundo encima de la app que estés usando.
- Salir de APX pausa el
/mobileembebido y detiene sus timers de JavaScript; al volver se reanuda. Las notificaciones nativas no dependen de eso: llegan por el servicio en foreground, no por el WebView. - La escalera de reconexión del socket se corta en 15 segundos durante un viaje y en 5 minutos fuera de uno, y se detiene del todo cuando el teléfono no tiene red: despierta con el callback de conectividad de Android, no con un temporizador. Antes, un teléfono lejos del daemon lo rediscaba cada 15 segundos todo el día. Al abrirse un viaje reconecta enseguida.
- Menú APX → Quitar restricción de batería abre el diálogo propio de Android. Conviene darlo para la detección de viajes: sin eso Android demora el inicio y el fin del viaje con el teléfono en el bolsillo. La fila del menú muestra el estado actual, y una vez que APX está exento la misma fila abre la lista del sistema, que es donde se revierte.
- También decide si el seguimiento por GPS puede arrancar solo. La ubicación es un permiso de “mientras se usa”, así que otorgarlo no alcanza: Android además exige que la app esté en un “estado elegible” para levantar un servicio en primer plano de tipo ubicación, y el listener de notificaciones que detecta el viaje corre en segundo plano. Sin la excepción ese arranque se rechaza, APX lo registra y sigue: el daemon igual se entera de que el viaje empezó, pero no hay flujo de posiciones y por lo tanto no hay avisos de cercanía hasta que abrís APX, lo que vuelve elegible a la app y reintenta. Con la excepción, el seguimiento arranca por sí solo.
El plan del viaje: cuántas búsquedas cuesta manejar
Sección titulada «El plan del viaje: cuántas búsquedas cuesta manejar»Un mandado no siempre es un lugar. “Comprar pan” lo resuelve la panadería de la esquina o cualquiera de los dos supermercados, y cuál corresponde depende de dónde está el auto en ese momento. Contestar esa pregunta buscando de nuevo en cada muestra de GPS sería una llamada al proveedor de lugares cada pocos segundos; contestarla una sola vez al principio dejaría pasar al conductor por tres opciones mejores.
Por eso el daemon mantiene un plan de viaje: una entrada por mandado, con todos los lugares que podrían resolverlo y aquel al que apunta ahora.
- El plan se arma cuando te subís al auto, desde el origen que reporta el teléfono — no de forma perezosa en la primera muestra, tomada 800 m más adelante.
- Reordenar es gratis. Elegir el candidato más cercano mientras el auto se mueve es aritmética sobre coordenadas que ya están en memoria. Sin llamadas, sin modelo.
- Volver a buscar es raro. Pasa solo cuando el auto se aleja 8 km del área buscada, o cuando cambia la lista de mandados abiertos — una lectura de archivo local, chequeada en cada muestra, así que una tarea agregada en un semáforo está viva en la siguiente.
- Un mandado resuelto deja de buscar. Un único candidato es la decisión, y un “voy” también: los dos fijan el mandado, y un mandado fijado no se vuelve a buscar ni a reapuntar. Cuando todos están fijados el plan está terminado y el resto del viaje no cuesta nada.
Un viaje normal con la lista de compras resuelta cuesta entonces una
búsqueda de lugares. Un viaje donde cada tarea trae su propia ubicación cuesta
cero — y cero llamadas al modelo en ambos casos, porque una tarea trip
dice qué es y dónde, en vez de pedirle a un modelo que lea el título y adivine.
Si alguna vez querés pagar por mejores lugares
Sección titulada «Si alguna vez querés pagar por mejores lugares»Lo que viene de fábrica es el stack gratuito (Nominatim para lugares, Valhalla/OSRM para rutas), y el plan de arriba es lo que hace barato cambiarlo. Como referencia, a precios de 2026 las alternativas de Google cobran por llamada, así que la cantidad de llamadas es todo el juego:
- Places API Nearby/Text Search — 5.000 llamadas gratis por mes, después USD 32 cada 1.000. Una búsqueda por viaje es accesible; una por muestra de GPS no.
- Routes API
computeRoutes— desde USD 5 cada 1.000, y puede optimizar el orden de hasta 25 paradas intermedias. Esta es la pieza que armaría una ruta real de varios mandados en vez de una lista por cercanía. - Search Along Route —
computeRoutesdevuelve una polilínea codificada, y Text Search la acepta comosearchAlongRouteParameters, devolviendo solo lugares que están en el camino. Dos llamadas por viaje, y estrictamente mejor que buscar en un radio alrededor de un punto cuando hay destino. - El geofencing propio de Android (
GeofencingClient, parte de Play Services y sin costo) es la otra mitad: le entrega hasta 100 cercos al sistema operativo, que despierta la app cuando se cruza uno usando geofencing por hardware, en vez de que la app muestree GPS con un temporizador. El plan de arriba ya produce exactamente el conjunto chico y estable de lugares que una API así necesita.
Qué ruta conoce APX
Sección titulada «Qué ruta conoce APX»APX no recibe polilínea exacta de Google Maps. Android envía último punto GPS disponible como origen y, cuando existe, texto de destino expuesto por notificación Maps, compartido explícitamente o confirmado por voz. Daemon geocodifica destino y arma ruta propia con Valhalla; usa OSRM como fallback.
Ruta reconstruida alcanza para buscar corredor y lugares cercanos, pero puede diferir de Google Maps: no incluye tráfico Google, preferencias de desvío ni decisiones sobre caminos privados. Si falta destino, Roby recibe solo posición actual y no afirma conocer ruta ni evalúa proximidad.
Head unit controlada por APX (experimental)
Sección titulada «Head unit controlada por APX (experimental)»Android Auto también manda mensajes semánticos de navegación al head unit. Canal privado del protocolo de proyección; no API disponible para app Android. Prueba USB/DHU real capturó:
0x8003: navegación activa/inactiva;0x8006: maniobra, calles y dirección de destino;0x8007: distancia restante y llegada.
Payload real incluyó guía Bosque Petrificado y destino R8400, Río Negro. Resultado: head unit APX puede detectar contexto automáticamente, sin leer notificaciones, voz, compartir Maps ni API Google.
Android → head unit/proxy APX → decoder navegación → /api/mobility/events autenticado → RobyConexión prueba contexto de conducción. Emitir trip.started solo cuando
navegación activa y destino útil. Emitir trip.ended al terminar navegación o
desconectar. Deduplicar frames 0x8006; nunca guardar video/audio proyectado.
Conseguir la app
Sección titulada «Conseguir la app»Instalarla, y elegir a qué dirección se conecta, tiene su propia página: Instalar en Android. En corto:
apx android install # por USB: instala, abre el túnel y vincula de unao abrir el APK publicado desde el teléfono.
Compilarla vos mismo
Sección titulada «Compilarla vos mismo»cd src/interfaces/android./gradlew testDebugUnitTest assembleDebugadb install -r app/build/outputs/apk/debug/app-debug.apkUn build release necesita una keystore en el entorno (APX_KEYSTORE,
APX_KEYSTORE_PASSWORD, APX_KEY_ALIAS, APX_KEY_PASSWORD); sin ella,
assembleRelease produce un APK sin firmar que Android no instala. CI hace esto
en cada cambio bajo src/interfaces/android/ y republica el release — ver
.github/workflows/android.yml.