diff --git a/GUIA_DE_DESARROLLO.md b/GUIA_DE_DESARROLLO.md index 44d8117..cf9b62a 100644 --- a/GUIA_DE_DESARROLLO.md +++ b/GUIA_DE_DESARROLLO.md @@ -54,9 +54,15 @@ Ahora mismo hay enganches en `main_views.js`, `tribes_view.js`, `vote_view.js`, ## Llamadas: las del dev La rama tuvo un módulo de salas y llamadas propio (Karvan). Se quitó el 19/10/2026 -porque el dev ya trae Teléfono y Salas. Lo nuestro es solo que funcionen en Android: -los permisos del envoltorio y el puente de audio y cámara. Si falta algo en las -llamadas, se arregla en ese puente o se le pide al dev, no se monta otro módulo. +porque el dev ya trae Teléfono y Salas. En Android el sonido y la cámara pasan por un +puente nativo de la app (`.audio_bridge`, ficheros `src/server/phone_*_android.js`, +que son del dev). La APK oficial lo trae; nuestra app Android todavía no, y es lo +que falta para que las llamadas suenen. Si falta algo en las llamadas, se arregla en +ese puente o se le pide al dev, no se monta otro módulo. + +Ojo al comparar con el dev: para el móvil la referencia es el `nodejs-project` de su +APK oficial, no su repositorio git. Hay ficheros, como `SSB_server.js` o +`phone_module.js`, cuya versión de móvil solo está en la APK. Lo mismo vale para cualquier módulo: antes de hacer uno propio, mirad si el dev ya lo tiene o lo está haciendo. @@ -80,9 +86,6 @@ Aquí se puede hacer lo que haga falta. - `src/backend/mobile_layer.js`: lo que el móvil necesita del backend (rutas que se cortan, módulos que no van, avatar y lanzador, retoques del HTML, descargas de la copia de seguridad). La monta `fork_routes.js`. -- `main.js`: arranca el backend en el móvil. Ahí se enchufan el audio, la cámara y la - emisión de Android (`src/server/phone_*_android.js`) en el Teléfono y las Salas del - dev, con `setAudioFactory` y compañía, sin tocar `SSB_server.js`. - `src/models/fork_workflows.js`: nuestros workflows. - `src/client/assets/translations/i18n_fork.js`: nuestros textos. - `src/client/assets/images/ux-*.svg`: nuestras imágenes. diff --git a/README.md b/README.md index 4d969c1..85640c5 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,8 @@ Android 7 o superior, 64 bits · se instala junto al Oasis oficial sin pisarlo parlamento, votaciones y eventos. El resto se enciende en *Módulos* o en *Ajustes → Workflows*. - Las llamadas son las de Oasis. Fuera Karvan, el módulo propio de salas: ahora se usan - el Teléfono y las Salas del dev, con el micrófono y la cámara del móvil enchufados. + el Teléfono y las Salas del dev. Ojo: en esta APK todavía no suenan, porque a nuestra + app Android le falta el puente de audio nativo que sí trae la oficial (ver abajo). - Votaciones como en asamblea: al crear una se elige Sí/No, semáforo (verde, amarillo, rojo) o termómetro (del 1 al 5). Los resultados salen en barras. - Borrar pide confirmación. Antes la X de una tribu la borraba de un toque. @@ -58,12 +59,12 @@ Android 7 o superior, 64 bits · se instala junto al Oasis oficial sin pisarlo | | Oasis oficial | Esta rama | |---|---|---| -| Llamadas y salas | Teléfono y Salas, pero sin micrófono ni cámara en Android | Los mismos, con el micrófono y la cámara del móvil | +| Llamadas y salas | Teléfono y Salas, con micrófono y cámara | Los mismos; el puente de audio de Android todavía falta | | Interfaz de móvil | El menú de escritorio en una pantalla pequeña | Tema Acampada, lanzador con iconos, fichas, barra de cuatro atajos | | Primer arranque | Casi sesenta módulos encendidos | Modo acampada: lo justo para organizarse | | Votaciones | Seis opciones fijas en una tabla | Sí/No, semáforo o termómetro, con barras | | Varias identidades | Una por instalación | Varias en el mismo móvil, con aviso si dos comparten clave | -| Envoltorio Android | APK sin permisos de cámara ni micrófono | Proyecto Gradle propio: permisos, subida de ficheros, servicio que sobrevive | +| Envoltorio Android | El del dev, sin código publicado | Proyecto Gradle propio y abierto: permisos, subida de ficheros, servicio que sobrevive | | Metadatos de las fotos | Se quitan solo si está `sharp`; en Android nunca | Se quitan siempre: GPS, marca, modelo, número de serie | Los nombres de las categorías, los módulos y el resto de la aplicación son los de @@ -103,10 +104,13 @@ mensaje en tu nombre ni cambiar lo que dijiste. ![Llamadas: las del dev, con el móvil enchufado](docs/capturas/esquema-llamadas.png) El Teléfono (llamadas de uno a uno, con buzón de voz) y las Salas (hasta cincuenta -personas, con vídeo, grabación y emisión) son de Oasis. La APK oficial no pide -permisos de micrófono ni de cámara, así que en Android no suenan. Esta rama trae su -propio envoltorio, que sí los pide, y enchufa el audio y la cámara del móvil en los -puntos que el propio Oasis deja para eso. La rama no tiene llamadas propias. +personas, con vídeo, grabación y emisión) son de Oasis. En Android el sonido y la +cámara no los maneja Node: el servidor se conecta a un puente nativo de la app +(`.audio_bridge`), que graba, reproduce, saca fotogramas de la cámara y emite ficheros. + +La APK oficial del dev trae ese puente. La de esta rama todavía no: nuestra app +Android es otra (tiene el código publicado) y el puente hay que escribirlo. Hasta +entonces, en esta APK el Teléfono dice que las llamadas no están disponibles. En la barra de arriba, junto al avatar, está el botón de *No molestar* del Teléfono. diff --git a/android/README.md b/android/README.md index 046d879..3df3429 100644 --- a/android/README.md +++ b/android/README.md @@ -5,6 +5,10 @@ molde. ## Por que existe +Nota (19/10/2026): desde la 1.3.x la APK oficial ya pide microfono y camara y trae un +puente nativo de audio y camara (`.audio_bridge`) para el Telefono y las Salas. Esta app +aun no lo tiene. Lo de abajo describe la situacion anterior. + El APK que se venia usando es el de epsylon re-firmado, y su `classes.dex` **no implementa `WebChromeClient.onPermissionRequest`**. Sin ese metodo el WebView de Android deniega por defecto toda peticion de `getUserMedia()`, de modo que las diff --git a/docs/capturas/esquema-llamadas.png b/docs/capturas/esquema-llamadas.png index 273318a..929bc3c 100644 Binary files a/docs/capturas/esquema-llamadas.png and b/docs/capturas/esquema-llamadas.png differ diff --git a/docs/capturas/esquema-rama.png b/docs/capturas/esquema-rama.png index da69c17..9904962 100644 Binary files a/docs/capturas/esquema-rama.png and b/docs/capturas/esquema-rama.png differ diff --git a/docs/capturas/generar_portada.py b/docs/capturas/generar_portada.py index 716568b..c4156c1 100644 --- a/docs/capturas/generar_portada.py +++ b/docs/capturas/generar_portada.py @@ -163,7 +163,7 @@ def esquema_rama(): ((740, 210, 1060, 400), "RUTAS", ["fork_routes.js y", "mobile_layer.js, delante", "del router del dev: lo que", "no atienden pasa al suyo"], NEON), ((1080, 210, 1340, 400), "ANDROID", - ["envoltorio propio:", "permisos de micro y", "cámara, y el puente", "de audio del Teléfono"], NEON), + ["envoltorio propio y", "abierto: permisos,", "ficheros y servicio.", "Falta el puente de audio"], NEON), ] for box, t, l, r in capa: caja(d, box, t, l, r) @@ -178,29 +178,29 @@ def esquema_rama(): def esquema_llamadas(): - """Las llamadas son las del dev; la rama solo enchufa el movil.""" + """Las llamadas son las del dev; en Android pasan por un puente nativo de la app.""" W, H = 1400, 700 out = Image.new("RGB", (W, H), BG) d = ImageDraw.Draw(out) - titulo(d, "LLAMADAS: LAS DEL DEV, CON EL MÓVIL ENCHUFADO", - "Teléfono y Salas son de Oasis. La rama no tiene llamadas propias: solo hace que suenen en Android.") + titulo(d, "LLAMADAS: LAS DEL DEV", + "Teléfono y Salas son de Oasis. En Android el sonido y la cámara pasan por un puente nativo de la app.") cajas = [ ((50, 200, 360, 430), "TELÉFONO Y SALAS", ["De Oasis, tal cual.", "Llamadas de uno a uno", "con buzón de voz; salas", "de hasta 50, con vídeo,", "grabación y emisión."], BG), ((400, 200, 700, 430), "LOS ENCHUFES", - ["setAudioFactory", "setVideoFactory", "setStreamFactory", "", "Los deja el propio dev."], BG), - ((740, 200, 1040, 430), "EL PUENTE", - ["main.js enchufa ahí", "phone_*_android.js:", "el audio y la cámara", "pasan por la app de", "Android."], NEON), + ["phone_*_android.js", "(del dev): se conectan", "a un puerto local que", "deja la app en", ".audio_bridge"], BG), + ((740, 200, 1040, 430), "EL PUENTE NATIVO", + ["Dentro de la app:", "R graba el micro", "P reproduce", "V saca la cámara", "S emite un fichero"], NEON), ((1080, 200, 1350, 430), "EL MÓVIL", - ["Micrófono, cámara", "y altavoz. Los permisos", "se piden la primera vez", "que llamas o entras", "en una sala."], NEON), + ["Micrófono, cámara", "y altavoz, con los", "permisos que se piden", "la primera vez."], BG), ] for box, t, l, r in cajas: caja(d, box, t, l, r) for a, b in (((362, 315), (398, 315)), ((702, 315), (738, 315)), ((1042, 315), (1078, 315))): flecha(d, a, b) - caja(d, (50, 480, 1350, 630), "¿Y CON LA APK OFICIAL?", - ["No declara micrófono ni cámara y su navegador interno deniega esas peticiones:", - "en Android las llamadas no pueden sonar. Por eso esta rama trae su propio envoltorio."], BG) + caja(d, (50, 480, 1350, 630), "DÓNDE ESTÁ CADA COSA", + ["La APK oficial trae el puente: ahí las llamadas suenan. La app de esta rama todavía no lo tiene,", + "así que en ella el Teléfono dice que no hay llamadas. Escribir ese puente es lo siguiente."], BG) out.save(HERE / "esquema-llamadas.png", optimize=True) diff --git a/main.js b/main.js index 35fcda6..c174b81 100644 --- a/main.js +++ b/main.js @@ -102,19 +102,6 @@ try { } } catch (e) {} -// Telefono y Salas del dev: en Android el audio, la camara y la emision van por el -// puente de la app (src/server/phone_*_android.js). El modulo del dev deja enchufarlos -// con setAudioFactory y compania; se hace aqui, antes de arrancar, para no tocar -// SSB_server.js. Ver GUIA_DE_DESARROLLO.md. -try { - const phone = require('./src/server/phone_module'); - phone.setAudioFactory(require('./src/server/phone_audio_android')); - phone.setVideoFactory(require('./src/server/phone_video_android')); - phone.setStreamFactory(require('./src/server/phone_stream_android')); -} catch (e) { - console.error('[Oasis] Phone bridge not available:', e && e.message); -} - const backendPath = path.join(__dirname, 'src', 'backend', 'backend.js'); console.log('[Oasis] Launching Oasis Social Network Utopia...'); diff --git a/src/client/assets/styles/mobile_ux.css b/src/client/assets/styles/mobile_ux.css index a313301..e0e8147 100644 --- a/src/client/assets/styles/mobile_ux.css +++ b/src/client/assets/styles/mobile_ux.css @@ -506,3 +506,7 @@ form.oasis-phone-state .oasis-phone-state-btn { .main-column .bb-manage h3, .main-column .bb-manage-add h3 { font-size: 20px !important; margin: 18px 0 10px !important; } .main-column a.bb-manage-done { display: block !important; width: 100% !important; margin-top: 18px !important; text-align: center; } .main-column div.bb-manage, .main-column div.bb-manage-add, .main-column div.bb-manage-list, .main-column div.bb-pick-grid { padding: 0 !important; margin: 0 !important; border: 0 !important; } + +/* el aviso de bienvenida, encima del lanzador: debajo quedaba a 1.300px y quien + abria la app por primera vez no lo veia */ +body > .welcome-banner { order: -1; margin-top: 10px !important; } diff --git a/src/server/SSB_server.js b/src/server/SSB_server.js index 00e5c95..ea12deb 100644 --- a/src/server/SSB_server.js +++ b/src/server/SSB_server.js @@ -80,7 +80,7 @@ const Server = SecretStack({ caps }) .use(require('ssb-unix-socket')) .use(require('ssb-no-auth')) .use(require('./snapshot_plugin')) - .use(require('./phone_module')) + .use((() => { const pm = require('./phone_module'); try { if (process.env.OASIS_MOBILE === '1') { pm.setAudioFactory(require('./phone_audio_android')); pm.setVideoFactory(require('./phone_video_android')); pm.setStreamFactory(require('./phone_stream_android')); } } catch (_) {} return pm; })()) .use(require('./network_pause')); if (!config.pub) {