Rango entre dispositivos

Android 16 presenta el módulo de rango, que proporciona una interfaz unificada y estandarizada para un rango preciso entre dispositivos. Puedes usar esta superficie de API para medir la distancia y la posición de los dispositivos pares sin tener que controlar cada tecnología de medición de rango de forma individual.

El módulo de rango admite las siguientes tecnologías:

Funciones y disponibilidad de los rangos

La clase RangingManager proporciona a las apps información sobre las tecnologías de medición de rango que admite el dispositivo local, así como la disponibilidad y las capacidades de cada tecnología. Las apps pueden registrarse para obtener un Callback y recibir actualizaciones sobre cualquier cambio en la disponibilidad o las funciones de las tecnologías compatibles.

Roles de los dispositivos

Un dispositivo que participa en una sesión de medición de rango debe ser un iniciador o un respondedor. El dispositivo iniciador inicia la sesión de medición de rango con uno o más dispositivos de respuesta. Un dispositivo de respuesta responde a las solicitudes de rango de un solo iniciador a la vez. Puedes especificar el rol de un dispositivo determinado en una sesión de medición de rango con la clase RangingPreference.

Tipos de sesiones de rango

Cuando se inicia una sesión de medición de rango entre dispositivos, a menudo es necesario establecer un transporte de datos fuera de banda (OOB) para intercambiar parámetros de la sesión.

El módulo de rango puede controlar las negociaciones fuera del rango por ti, pero también admite implementaciones fuera del rango personalizadas.

Figura 1. Flujo fuera de banda para los tipos de sesión

Implementación predeterminada de OOB

En este tipo de sesión (RANGING_SESSION_OOB), el módulo de rango controla las negociaciones fuera del rango para iniciar una sesión de rango. Selecciona parámetros adecuados según las preferencias de rango que proporciona la app y usa las tecnologías adecuadas según lo que admiten ambos dispositivos. Este tipo de sesión usa un OOB specification estandarizado.

El módulo de rango solo define el formato y la secuencia de datos fuera de banda que se usarán para interactuar con un dispositivo par. No controla el descubrimiento de dispositivos pares ni el establecimiento de conexiones.

Implementación personalizada fuera del perímetro

En este tipo de sesión (RANGING_SESSION_RAW), la app pasa por alto el flujo de OOB del módulo de rango y controla su propia negociación y parámetros de OOB. Eso significa que la app debe determinar qué tecnologías admite el dispositivo del cliente, negociar los parámetros de rango y comenzar la sesión de rango.

Preferencias de rango

Usa un objeto RangingPreference para especificar los parámetros deseados para una sesión de medición de rango. Se incluye lo siguiente:

  • Rol del dispositivo. Esto indica si el dispositivo será el iniciador o el objeto de respuesta.
  • Configuración de rango. Un objeto RangingConfig especifica el tipo de sesión de rango y otros parámetros necesarios para iniciar una sesión de rango.
  • Configuración de la sesión. Un objeto SessionConfig especifica los parámetros que se aplicarán en la sesión de medición, como el límite de medición, la fusión de sensores, la configuración de geovallado y mucho más.

Permiso de rango

El módulo de rango requiere un nuevo permiso unificado (android.permission.RANGING) para acceder a todas las tecnologías de rango actuales y futuras. Este permiso se encuentra en la lista NEARBY_DEVICES_PERMISSIONS.

<uses-permission android:name="android.permission.RANGING" />

Restricciones y limitaciones

El módulo de rango puede restringir el rango por varios motivos, incluidos los siguientes:

  • Las apps de terceros solo pueden realizar mediciones en segundo plano con la banda ultraancha y solo en dispositivos compatibles. No se permite el rango en segundo plano con otras tecnologías.
  • No se permite el rango cuando se alcanza la cantidad máxima de sesiones de rango simultáneas por dispositivo.
  • Es posible que el rango se restrinja debido a problemas relacionados con el estado del sistema, como la batería, el rendimiento o la memoria.

El módulo de rango también tiene las siguientes limitaciones conocidas:

  • El módulo de rango solo admite la entrega de datos de rango a dispositivos pares para la banda ultra ancha. En el caso de otras tecnologías, el módulo de rango solo entrega datos de rango al dispositivo iniciador.
  • El módulo de rango solo admite la adición dinámica de dispositivos en el modo de rango sin procesar y solo para la banda ultraancha.
  • El módulo de rango no admite sesiones de banda ultraancha de uno a varios para las implementaciones de OOB predeterminadas. Si pasas varios controladores de dispositivos, el módulo crea una sesión uno a uno para cada dispositivo de intercambio de tráfico que admita la banda ultraancha.

Cómo realizar una sesión de medición de rango

Para realizar una sesión de medición de rango con el módulo de medición de rango, sigue estos pasos:

  1. Verifica que todos los dispositivos funcionen con Android 16 o versiones posteriores.
  2. Solicita el permiso android.permission.RANGING en el manifiesto de la app.
  3. Evalúa las capacidades y la disponibilidad de las tecnologías de medición de distancia.
  4. Descubre un dispositivo par para las operaciones de rango.
  5. Establece una conexión para un intercambio fuera de banda con cualquiera de los tipos de sesión que se describen en Tipos de sesión de rango.
  6. Inicia el rango y adquiere datos de rango de forma continua.
  7. Finaliza la sesión de medición de rango.

En la siguiente muestra de código, se demuestran estos pasos para el rol de iniciador y el rol de persona que responde.

Kotlin

class RangingApp {

    // Starts a ranging session on the initiator side.
    fun startRangingInitiator(
        context: Context,
        deviceHandle: DeviceHandle,
        executor: Executor,
        callback: RangingSessionCallback
    ) {

        // Get the RangingManager which is the entry point for ranging module.
        val manager = context.getSystemService(RangingManager::class.java)

        // Create a new RangingSession using the provided executor and callback.
        val session = manager.createRangingSession(executor, callback)

        // Create an OobInitiatorRangingConfig, which specifies the ranging parameters for
        // the initiator role.
        val config = OobInitiatorRangingConfig.Builder()
            .setFastestRangingInterval(Duration.ofMillis(100))
            .setSlowestRangingInterval(Duration.ofMillis(5000))
            .setRangingMode(RANGING_MODE_AUTO)
            .setSecurityLevel(SECURITY_LEVEL_BASIC)
            .addDeviceHandle(deviceHandle)
            .build()

        // Create a RangingPreference, which specifies the role (initiator) and
        // configuration for the ranging session.
        val preference =
            RangingPreference.Builder(DEVICE_ROLE_INITIATOR, config).build()

        // Start ranging session.
        session.start(preference)

        // If successful, the ranging data will be sent through callback#onResults

        // Stop ranging session
        session.stop()
    }

    // Starts a ranging session on the responder side.
    fun startRangingResponder(
        context: Context,
        deviceHandle: DeviceHandle,
        executor: Executor,
        callback: RangingSessionCallback
    ) {

        // Get the RangingManager which is the entry point for ranging module.
        val manager = context.getSystemService(RangingManager::class.java)

        // Create a new RangingSession using the provided executor and callback.
        val session = manager.createRangingSession(executor, callback)

        // Create an OobResponderRangingConfig, which specifies the ranging parameters for
        // the responder role.
        val config = OobResponderRangingConfig.Builder(deviceHandle).build()

        // Create a RangingPreference, which specifies the role (responder) and
        // configuration for the ranging session.
        val preference =
            RangingPreference.Builder(DEVICE_ROLE_RESPONDER, config).build()

        // Start the ranging session.
        session.start(preference)

        // Stop the ranging session
        session.stop()
    }
}

Java

public class RangingApp {

    // Starts a ranging session on the initiator side.
    void startRangingInitiator(Context context, DeviceHandle deviceHandle, Executor executor, RangingSessionCallback callback) {

        // Get the RangingManager which is the entry point for ranging module.
        RangingManager manager = context.getSystemService(RangingManager.class);

        // Create a new RangingSession using the provided executor and callback.
        RangingSession session = manager.createRangingSession(executor, callback);

        // Create an OobInitiatorRangingConfig, which specifies the ranging parameters for
        // the initiator role.
        OobInitiatorRangingConfig config = new OobInitiatorRangingConfig.Builder()
                .setFastestRangingInterval(Duration.ofMillis(100))
                .setSlowestRangingInterval(Duration.ofMillis(5000))
                .setRangingMode(RANGING_MODE_AUTO)
                .setSecurityLevel(SECURITY_LEVEL_BASIC)
                .addDeviceHandle(deviceHandle)
                .build();

        // Create a RangingPreference, which specifies the role (initiator) and
        // configuration for the ranging session.
        RangingPreference preference =
                new RangingPreference.Builder(DEVICE_ROLE_INITIATOR, config).build();

        // Start ranging session.
        session.start(preference);

        // If successful, the ranging data will be sent through callback#onResults

        // Stop ranging session
        session.stop();

    }

    // Starts a ranging session on the responder side.
    void startRangingResponder(Context context,  DeviceHandle deviceHandle, Executor executor, RangingSessionCallback callback) {

        // Get the RangingManager which is the entry point for ranging module.
        RangingManager manager = context.getSystemService(RangingManager.class);

        // Create a new RangingSession using the provided executor and callback.
        RangingSession session = manager.createRangingSession(executor, callback);

        // Create an OobResponderRangingConfig, which specifies the ranging parameters for
        // the responder role.
        OobResponderRangingConfig config = new OobResponderRangingConfig.Builder(  deviceHandle).build();

        // Create a RangingPreference, which specifies the role (responder) and
        // configuration for the ranging session.
        RangingPreference preference =
                new RangingPreference.Builder(DEVICE_ROLE_RESPONDER, config).build();

        // Start the ranging session.
        session.start(preference);

        // Stop the ranging session
        session.stop();
    }
}

App de ejemplo

Para ver un ejemplo de extremo a extremo de cómo usar el módulo de rango, consulta la app de ejemplo en AOSP. Esta app de ejemplo abarca todas las tecnologías de medición de rango que admite el módulo de medición de rango y, además, incluye flujos para ambos tipos de sesión compatibles.