Saltar a contenido

Diagramas detallados del reacondicionado de móviles

Desarrolla el diagrama de alto nivel estado a estado, encajando cada caja del Lucidchart "Diagrama reparació Vincle Digital" en el estado de DeviceHub donde ocurre.

Leyenda

Todos los diagramas usan los mismos colores:

Color Significado
Azul Algo queda escrito en DeviceHub: evidencia, cambio de estado, nota o propiedad
Amarillo Checkpoint: evidencia de DH-scan o snapshot de workbench-android
Rojo Salida a DISMANTLE. Siempre con nota del motivo
Verde Sale del estado hacia el siguiente del camino normal
Morado Estado nuevo que no existe todavía en DeviceHub
Gris Documento o ficha de apoyo (cajas "documento" del Lucidchart)

1. Máquina de estados

La vista completa: qué estados existen y qué transiciones son válidas. El detalle de cada estado viene en las secciones siguientes.

stateDiagram-v2
    direction TB

    state "INBOX" as INBOX
    state "VISUAL INSPECTION" as VI
    state "PENDING DONOR (nuevo)" as PD
    state "INSTALL" as INSTALL
    state "TEST" as TEST
    state "REPAIR" as REPAIR
    state "PACKAGING" as PACK
    state "DONATION" as DON
    state "IN USE (nuevo)" as USE
    state "DISMANTLE" as DIS

    [*] --> INBOX: móvil recibido,<br/>primer POST de DH-scan
    INBOX --> VI: registrado
    INBOX --> DIS: daño evidente

    VI --> INSTALL: arranca y es accesible
    VI --> PD: bloqueado con PIN<br/>o FRP
    VI --> DIS: no carga<br/>o no arranca

    PD --> INSTALL: se recupera el acceso<br/>o se libera la gestión
    PD --> DIS: sin respuesta en 30 días

    INSTALL --> TEST: reset hecho,<br/>usuario de test configurado
    INSTALL --> DIS: obsoleto
    INSTALL --> PD: pide una contraseña<br/>o liberar la gestión

    TEST --> PACK: apto según<br/>criterios de entrega
    TEST --> REPAIR: requiere<br/>reparación

    REPAIR --> TEST: reparación<br/>completada
    REPAIR --> DIS: no reparable<br/>o reparación no viable

    PACK --> DON: entregado a receptor
    PACK --> REPAIR: no arranca<br/>tras el reset II
    PACK --> PD: pide la cuenta<br/>anterior (FRP)

    DON --> USE: receptor lo usa
    USE --> VI: devolución o<br/>cambio de persona
    USE --> DIS: se rompe sin arreglo

    DIS --> [*]

El procedimiento interno de REPAIR queda fuera del alcance de este documento. Una reparación completada requiere repetir TEST antes de decidir si el dispositivo es apto para PACKAGING.


2. INBOX · Etiquetado y cribado rápido

Es un cribado de pocos segundos por móvil: se etiqueta, se da de alta y se aparta lo que se ve a simple vista que no sirve. No se enciende el móvil ni se busca información del modelo: en este punto se hace un primer registro en DeviceHub para tener constancia de los móviles que recibimos.

flowchart TD
    START(["Móvil recibido"]) --> PEGAR["Pegar la siguiente etiqueta<br/>preimpresa de la plancha"]
    PEGAR --> SCAN["DH-scan o WebForm de DeviceHub:<br/>custom_id, fotos y tipo"]:::checkpoint
    SCAN --> LBL{"¿Tiene etiqueta<br/>del fabricante a la vista?"}
    LBL -->|"Sí"| OCR["DH-scan: barcode u OCR<br/>fabricante, modelo, serial,<br/>product code, GTIN"]:::checkpoint
    LBL -->|"No"| POST
    OCR --> POST["Primer POST de evidencia<br/>a DeviceHub: el móvil<br/>consta como recibido"]:::dh
    POST --> ST_INBOX["Estado INBOX"]:::dh

    ST_INBOX --> CRIBA{"Cribado a simple vista"}

    CRIBA -->|"iPhone"| IPH(["Fuera del flujo Android<br/>ver preguntas abiertas"]):::reject
    CRIBA -->|"Móvil de teclas<br/>u otro aparato"| OTRO(["Reclasificar o<br/>DISMANTLE"]):::reject
    CRIBA -->|"Batería hinchada"| N_BAT["Nota: [BATERIA-HINCHADA]<br/>+ foto"]:::dh
    N_BAT --> DIS(["DISMANTLE"]):::reject

    CRIBA -->|"Partido, mojado<br/>u otro daño grave"| N_DEST["Nota: [DAÑO-EVIDENTE]<br/>+ foto"]:::dh
    N_DEST --> DIS
    CRIBA -->|"Móvil o tablet Android"| NEXT(["→ VISUAL INSPECTION"]):::ok

    classDef reject fill:#f8d7da,stroke:#b02a37,color:#58151c
    classDef ok fill:#d1e7dd,stroke:#146c43,color:#0a3622
    classDef checkpoint fill:#fff3cd,stroke:#997404,color:#664d03
    classDef dh fill:#cfe2ff,stroke:#0a58ca,color:#052c65

ID y etiqueta. Las etiquetas se imprimen por adelantado en planchas A4 con numeración correlativa, con la herramienta generar_planchas.py.

  • El QR lleva solo el número, no una URL: DH-scan guarda el texto del QR tal cual como custom_id. En workbench-android el número se teclea y la app comprueba en DeviceHub que existe.

Solo lo evidente. Aquí se descarta lo que no necesita comprobación: pantalla partida en trozos, batería hinchada (apartar el aparato por riesgo de incendio) o señales claras de agua. El resto del hardware lo prueba workbench-android en TEST.

Queda en DeviceHub al salir de INBOX:

Dato Origen
custom_id QR de la etiqueta, leído por DH-scan y enviado en el primer POST
tipo DeviceType de móvil o de tablet de la institución
fotos DH-scan o WebForm de DeviceHub
fabricante, modelo, serial, product code, GTIN Barcode u OCR de la etiqueta, si la hay, como propiedades
estado INBOX La guía lo marca tras el primer POST, con el token API o a mano

3. VISUAL INSPECTION · Carga, arranque y bloqueo

Responde a lo que workbench-android no puede comprobar porque aún no está instalado: si el móvil carga, si arranca y si podemos entrar. Todo lo demás se mira en otro sitio:

flowchart TD
    IN(["Desde INBOX<br/>o desde IN USE"]) --> ST_VI["Estado VISUAL INSPECTION"]:::dh

    ST_VI --> CARGA{"Enchufar 15 min<br/>¿carga? icono o LED"}
    CARGA -->|"No"| OTRO_CAB["Probar otro cable<br/>y limpiar conector"]
    OTRO_CAB --> CARGA2{"¿Carga ahora?"}
    CARGA2 -->|"No"| N_NOCAR["Nota: no carga"]:::dh
    N_NOCAR --> DIS1(["DISMANTLE"]):::reject
    CARGA2 -->|"Sí"| ARRANCA
    CARGA -->|"Sí"| ARRANCA{"¿Arranca?"}

    ARRANCA -->|"No"| N_NOARR["Nota: no arranca<br/>bootloop o pantalla negra"]:::dh
    N_NOARR --> DIS2(["DISMANTLE"]):::reject

    ARRANCA -->|"Sí"| PANT{"¿Qué pantalla sale?"}
    PANT -->|"Escritorio sin bloqueo"| OK(["→ INSTALL"]):::ok
    PANT -->|"Asistente inicial"| FRP{"¿Pide la cuenta<br/>anterior? FRP"}
    FRP -->|"No"| OK
    FRP -->|"Sí"| PEND
    PANT -->|"Pantalla de bloqueo"| PIN{"¿El PIN venía<br/>con la donación<br/>y funciona?"}
    PIN -->|"Sí"| OK
    PIN -->|"No"| PEND(["→ PENDING DONOR"]):::newstate

    classDef reject fill:#f8d7da,stroke:#b02a37,color:#58151c
    classDef ok fill:#d1e7dd,stroke:#146c43,color:#0a3622
    classDef dh fill:#cfe2ff,stroke:#0a58ca,color:#052c65
    classDef newstate fill:#e2d9f3,stroke:#59359a,color:#2f1c6a

La carga va antes que el arranque porque un móvil sin batería no arranca y no se puede distinguir de uno roto. No hace falta cargarlo más: basta con que encienda. Si hay un tester USB a mano, se puede usar para comprobar si el móvil está consumiendo corriente aunque no muestre ningún icono o LED. El consumo concreto depende del modelo, de la batería y de la fase de carga.

Nunca se prueban PINs a ciegas: tras varios intentos el móvil se bloquea por tiempo o se borra, y lo segundo deja el FRP armado.


4. PENDING DONOR (RELEASE) · Espera de liberación (estado nuevo)

Espera la actuación del donante, propietario o empresa para obtener un PIN, completar la verificación FRP o retirar la gestión empresarial.

flowchart TD
    IN(["Desde VISUAL INSPECTION,<br/>INSTALL o PACKAGING"]) --> ST_PD["Estado PENDING DONOR<br/>nota: fecha límite = hoy + 30 días"]:::dh
    ST_PD --> GUARDAR["Guardar en estantería<br/>de espera, etiquetado"]
    GUARDAR --> CONTACTO{"¿Hay contacto del donante,<br/>propietario o empresa?"}

    CONTACTO -->|"No"| N_ANON["Nota: donante anónimo"]:::dh
    N_ANON --> DIS1(["DISMANTLE"]):::reject

    CONTACTO -->|"Sí"| MSG["Pedir que desbloquee el dispositivo,<br/>complete la verificación FRP<br/>o retire la gestión empresarial"]:::dh
    MSG --> R1{"¿Responde<br/>en 7 días?"}
    R1 -->|"No"| REC["Recordatorio"]:::dh
    REC --> R2{"¿Responde antes<br/>de la fecha límite?"}
    R2 -->|"No"| N_TIME["Nota: sin respuesta<br/>en 30 días"]:::dh
    N_TIME --> DIS2(["DISMANTLE"]):::reject

    R1 -->|"Sí"| QUE
    R2 -->|"Sí"| QUE{"¿Qué responde?"}
    QUE -->|"Da el PIN"| PIN["Probar PIN para desbloquear el móvil"]
    QUE -->|"FRP activo"| FRP_OK["El donante completa<br/>la verificación con una cuenta<br/>previamente sincronizada"]
    QUE -->|"Gestión empresarial"| MDM_OK["La empresa retira<br/>MDM, zero-touch o Knox"]
    QUE -->|"No quiere o no puede"| N_NEG["Nota: donante rechaza"]:::dh
    N_NEG --> DIS3(["DISMANTLE"]):::reject

    PIN --> FUNC{"¿Desbloquea?"}
    FUNC -->|"No"| MSG
    FUNC -->|"Sí"| N_OK["Nota: acceso recuperado"]:::dh
    FRP_OK --> N_OK
    MDM_OK --> N_OK
    N_OK --> OK(["→ INSTALL"]):::ok

    classDef reject fill:#f8d7da,stroke:#b02a37,color:#58151c
    classDef ok fill:#d1e7dd,stroke:#146c43,color:#0a3622
    classDef dh fill:#cfe2ff,stroke:#0a58ca,color:#052c65

5. INSTALL · Borrado de cuentas, reset y registro con workbench-android

flowchart TD
    IN(["Desde VISUAL INSPECTION<br/>o PENDING DONOR"]) --> ST_IN["Estado INSTALL"]:::dh

    ST_IN --> EMM{"¿Gestión empresarial?<br/>perfil de trabajo,<br/>zero-touch, Knox"}
    EMM -->|"Sí"| N_EMM["Nota: bloqueo MDM empresarial<br/>pedir baja a la empresa"]:::dh
    N_EMM --> PEND_MDM(["→ PENDING DONOR"]):::newstate

    EMM -->|"No"| BANDEJA["Sacar bandeja: retirar<br/>SIM y SD del donante"]
    BANDEJA --> DONATE["Instalar donate-android<br/>APK sin permisos ni red"]
    DONATE --> CUENTAS["donate-android guía:<br/>eliminar todas las cuentas,<br/>Google y fabricante"]
    CUENTAS --> PASS{"¿Pide una contraseña<br/>que no tenemos?"}
    PASS -->|"Sí"| PEND(["→ PENDING DONOR"]):::newstate
    PASS -->|"No"| LOCK["Quitar bloqueo de pantalla"]
    LOCK --> RESET["donate-android abre el<br/>factory reset del sistema"]

    RESET --> ASIST["Arranca en<br/>asistente inicial"]
    ASIST --> USR["Configurar usuario de test<br/>sin cuenta Google<br/>idioma, fecha, sin PIN"]
    USR --> WIFI_CFG["Conectar a WiFi del taller"]
    WIFI_CFG --> INSTWB["Instalar workbench-android<br/>APK"]
    INSTWB --> WBID["workbench-android:<br/>teclear el número de la etiqueta<br/>y comprobarlo en DeviceHub"]
    WBID --> INV["Snapshot de inventario<br/>modelo, Android, parche,<br/>RAM, almacenamiento, batería"]:::checkpoint

    INV --> OBS{"¿Obsoleto?<br/>parche de hace<br/>más de X años"}
    OBS -->|"Sí"| N_OBS["Nota: obsoleto<br/>modelo, Android y parche"]:::dh
    N_OBS --> DIS0(["DISMANTLE"]):::reject
    OBS -->|"No"| OK(["→ TEST"]):::ok

    classDef reject fill:#f8d7da,stroke:#b02a37,color:#58151c
    classDef ok fill:#d1e7dd,stroke:#146c43,color:#0a3622
    classDef checkpoint fill:#fff3cd,stroke:#997404,color:#664d03
    classDef dh fill:#cfe2ff,stroke:#0a58ca,color:#052c65
    classDef newstate fill:#e2d9f3,stroke:#59359a,color:#2f1c6a

donate-android guía el borrado de cuentas y abre el factory reset del propio Android: la app no puede hacer el reset ni saltarse nada. No pide permisos ni tiene acceso a red, así que se puede instalar en un móvil que aún tiene datos del donante. workbench-android, en cambio, se instala después del reset. La última APK publicada se descarga desde apps.sergiogimenez.com/workbench.

El orden importa: cuentas fuera antes del reset. Si se resetea con la cuenta puesta, el FRP aparece y solo el propietario puede quitarlo. No se intenta ningún bypass de FRP.

Qué reporta workbench-android

Lo que necesitamos del registro y lo que envía la app en el snapshot. Lo que llega a DeviceHub como propiedad se ve en la ficha del producto.

Dato Para qué En la app En DeviceHub
custom_id Unir con el alta de DH-scan Se teclea y se comprueba que existe en DeviceHub antes de enviar (la etiqueta está en la trasera del propio móvil, su cámara no la ve) Identificador del producto
Tipo Móvil o tablet Smartphone o Tablet (pantalla ≥ 600 dp) Tipo del producto
Fabricante, marca, modelo Ficha Sí, de Build Sí
Versión de Android, API Ficha, obsoleto Sí android:version, android:api_level
Parche de seguridad Decidir obsoleto Sí, Build.VERSION.SECURITY_PATCH android:security_patch
Obsoleto Salida a DISMANTLE No Falta la regla: se decide con android:security_patch
CPU, RAM, almacenamiento, pantalla, cámaras, sensores Ficha Sí Componentes
Batería: nivel, salud, voltaje, temperatura Ficha, TEST Sí Componente batería
Ciclos de batería Desgaste Solo API 34+ y según fabricante Sin alternativa fiable
Salud de batería en % Desgaste No, fijo a null Depende del fabricante
Serial Ficha No No accesible sin privilegios desde API 29. Sale de la etiqueta (DH-scan)
IMEI Ficha, trazabilidad No No accesible desde API 29. *#06# a mano
SIM o SD dentro Control de INSTALL, antes del reset Parcial: el test de SIM pide retirarla La SD no se comprueba
Specs PD (carga rápida) Cargador de entrega No No lo expone Android: ficha del fabricante

Falta fijar la X del criterio de obsoleto.


6. TEST · Diagnóstico con workbench-android

La idea es que todos los tests se hagan desde workbench-android, sin pruebas a mano ni diagnósticos de fábrica: es la única forma de que el taller no pierda tiempo y de que cada resultado quede en el snapshot.

flowchart TD
    IN(["Desde INSTALL"]) --> ST_T["Estado TEST"]:::dh
    ST_T --> WB["Completar todos los tests<br/>en Workbench Android<br/>y enviar el snapshot"]:::checkpoint
    WB --> PROPS["Resultados hwtest:*<br/>guardados en Propiedades<br/>de DeviceHub"]:::dh
    PROPS --> DEC{"¿Cumple los criterios<br/>de entrega?"}
    DEC -->|"Sí"| PACK(["→ PACKAGING"]):::ok
    DEC -->|"No"| REP(["→ REPAIR"]):::ok

    classDef ok fill:#d1e7dd,stroke:#146c43,color:#0a3622
    classDef checkpoint fill:#fff3cd,stroke:#997404,color:#664d03
    classDef dh fill:#cfe2ff,stroke:#0a58ca,color:#052c65

Workbench guía todas las pruebas —incluidas SIM y batería cuando corresponda—, registra PASS, FAIL o SKIP y envía el snapshot. La guía del taller solo confirma que se ha completado ese recorrido, sin duplicarlo como checklist. Los resultados quedan en DeviceHub y, según los criterios de entrega, el móvil pasa a PACKAGING o REPAIR.

Qué hace workbench-android

Todos los tests del diagrama están en la app. Cada resultado llega a DeviceHub como propiedad hwtest:<id>. Si cambia entre pasadas, el cambio queda en el log del producto.

Test Ids de resultado Cómo decide
Pantalla, táctil, multitáctil screen, touch, multitouch Operario; táctil pasa solo al cubrir la rejilla
Sensores accelerometer, gyroscope, magnetometer, proximity, light Pasa si la lectura cambia; SKIP si no existe
Vibración, linterna vibration, flashlight Operario
Carga charging Pass solo con el cargador detectado
WiFi wifi Pass solo con WiFi validada por el sistema
Audio speaker, earpiece, microphone Operario; auricular SKIP si no hay; el micrófono graba y reproduce
Cámaras camera_back, camera_front Operario con la vista previa; SKIP si no hay
Botones volume_up, volume_down, power Detectados: teclas de volumen y pantalla apagada
Bluetooth bluetooth Pass con al menos un dispositivo visible encontrado
GPS gps Pass con satélites visibles; la nota lleva satélites y fix
SIM sim, cellular_network, call, mobile_data SIM lista, registro en red, llamada por el marcador, datos validados. SKIP sin telefonía
Batería battery_drain Descarga de 15, 30 o 60 min; la caída va en la nota

Sin probar todavía en un móvil real: leer un QR real, auricular, micrófono con voz, Bluetooth con dispositivos cerca y la llamada. En el emulador funcionan el recorrido completo, la reanudación y el envío a DeviceHub.


7. PACKAGING → DONATION → IN USE · Preparación, entrega y uso

flowchart TD
    IN(["Desde TEST<br/>apto para entrega"]) --> ST_P["Estado PACKAGING"]:::dh

    ST_P --> RESET2["Reset II<br/>factory reset desde Ajustes:<br/>borra usuario de test y WiFi"]
    RESET2 --> ASIST{"¿Arranque correcto en asistente<br/>inicial sin pedir cuenta?"}
    ASIST -->|"No"| REP(["→ REPAIR"]):::ok
    ASIST -->|"Sí"| FRP{"¿Pide una cuenta<br/>anterior? FRP"}

    FRP -->|"Sí"| PEND(["→ PENDING DONOR"]):::newstate
    FRP -->|"No"| APAGAR["Apagar con<br/>batería al 50-80 %"]
    APAGAR --> LIMPIEZA["Limpieza exterior<br/>y protector si procede"]
    LIMPIEZA --> KIT["Kit: móvil, cargador,<br/>cable, funda,<br/>guía de primeros pasos"]
    KIT --> ETIQ["Etiqueta QR visible<br/>con custom_id"]
    ETIQ --> ESPERA["Estantería de listos"]

    ESPERA --> ASIGN{"¿Hay receptor<br/>asignado?"}
    ASIGN -->|"No"| ESPERA
    ASIGN -->|"Sí"| ENTREGA["Entrega al receptor<br/>firma de recepción"]

    ENTREGA --> ST_D["Estado DONATION<br/>nota: entidad o receptor"]:::dh
    ST_D --> CONF["Primera configuración<br/>con el receptor si lo necesita"]
    CONF --> ST_U["Estado IN USE"]:::newstate

    ST_U --> CHK["Pasada de workbench-android<br/>periódica o al volver"]:::checkpoint
    CHK --> EVENTO{"¿Qué pasa?"}
    EVENTO -->|"Sigue en uso"| ST_U
    EVENTO -->|"Cambio de persona<br/>o devolución"| VI(["→ VISUAL INSPECTION"]):::ok
    EVENTO -->|"Se rompe"| REV{"¿Reparable?"}
    REV -->|"Sí"| VI
    REV -->|"No"| DIS(["DISMANTLE"]):::reject

    classDef reject fill:#f8d7da,stroke:#b02a37,color:#58151c
    classDef ok fill:#d1e7dd,stroke:#146c43,color:#0a3622
    classDef checkpoint fill:#fff3cd,stroke:#997404,color:#664d03
    classDef dh fill:#cfe2ff,stroke:#0a58ca,color:#052c65
    classDef newstate fill:#e2d9f3,stroke:#59359a,color:#2f1c6a

La vuelta desde IN USE entra por VISUAL INSPECTION y no por TEST: el móvil ha estado en manos de otra persona y puede volver con cuentas, PIN o daños nuevos.

Cada fila DONATION del historial abre un periodo de uso y la siguiente transición lo cierra. Con eso se calculan las horas de impacto social sin marcar evidencias a mano.


8. DISMANTLE · Catálogo de motivos

Todas las salidas rojas acaban aquí. Para poder contar después por qué se pierden móviles, el motivo tiene que ser uno de esta lista y ir al principio de la nota del cambio de estado, por ejemplo [NO-CARGA] probado con dos cables.

flowchart LR
    subgraph INBOX
        M2["NO-ANDROID"]
        M0["DAÑO-EVIDENTE"]
        M4["BATERIA-HINCHADA"]
    end
    subgraph VISUAL_INSPECTION["VISUAL INSPECTION"]
        M5["NO-CARGA"]
        M6["NO-ARRANCA"]
    end
    subgraph PENDING_DONOR["PENDING DONOR"]
        M7["DONANTE-ANONIMO"]
        M8["SIN-RESPUESTA"]
        M9["DONANTE-RECHAZA"]
    end
    subgraph INSTALL
        M1["OBSOLETO"]
        M10["MDM-EMPRESA"]
    end
    subgraph IN_USE["IN USE"]
        M19["ROTO-EN-USO"]
    end

    INBOX --> DIS
    VISUAL_INSPECTION --> DIS
    PENDING_DONOR --> DIS
    INSTALL --> DIS
    IN_USE --> DIS

    DIS["DISMANTLE"]:::reject --> DEST{"Destino"}
    DEST --> PIEZAS["Donante de piezas<br/>pantalla, batería, cámara"]
    DEST --> WEEE["Gestor autorizado WEEE<br/>con borrado certificado<br/>si no se pudo resetear"]

    classDef reject fill:#f8d7da,stroke:#b02a37,color:#58151c

Preguntas abiertas

Decisiones que tomé para poder dibujar y que conviene validar:

  1. iPhone. Que hacemos con ellos?
  2. Criterio de obsoleto. ¿Cuántos años de antigüedad del parche de seguridad hacen obsoleto un móvil?
  3. Umbral de batería. "Descarga excesiva en 60 minutos" necesita un número concreto por grado.