O Android 16 apresenta o módulo Ranging, que oferece uma interface unificada e padronizada para alcance preciso entre dispositivos. Você pode usar essa superfície de API para medir a distância e a posição de dispositivos pareados sem precisar processar cada tecnologia de alcance individualmente.
O módulo Ranging oferece suporte às seguintes tecnologias:
- Banda ultralarga
- Sondagem de canal Bluetooth
- Wi-Fi NAN RTT
- Alcance RSSI Bluetooth
Recursos e disponibilidade de alcance
A classe RangingManager fornece aos apps informações sobre as tecnologias de alcance
com suporte no dispositivo local, bem como a disponibilidade e
os recursos de cada tecnologia. Os apps podem se registrar para um Callback para
receber atualizações sobre mudanças na disponibilidade ou nos recursos de qualquer
tecnologia com suporte.
Funções do dispositivo
Um dispositivo que participa de uma sessão de alcance precisa ser um iniciador ou um
respondente. O dispositivo iniciador inicia a sessão de alcance com um ou mais
dispositivos respondentes. Um dispositivo respondente responde a solicitações de alcance de apenas um
iniciador por vez. É possível especificar a função de um determinado dispositivo em uma sessão de alcance
com a RangingPreference classe.
Tipos de sessão de alcance
Ao iniciar uma sessão de alcance entre dispositivos, geralmente é necessário estabelecer um transporte de dados fora de banda (OOB, na sigla em inglês) para trocar parâmetros da sessão.
O módulo Ranging pode processar negociações OOB para você, mas também oferece suporte a implementações OOB personalizadas.
Implementação OOB padrão
Nesse tipo de sessão (RANGING_SESSION_OOB), o módulo Ranging processa
negociações OOB para iniciar uma sessão de alcance. Ele seleciona parâmetros adequados
com base nas preferências de alcance fornecidas pelo app e usa as
tecnologias apropriadas com base no que os dois dispositivos oferecem suporte. Esse tipo de sessão
usa uma OOB specification padronizada.
O módulo Ranging define apenas o formato e a sequência de dados OOB a serem usados para interagir com um dispositivo pareado. Ele não processa a descoberta de dispositivos pareados nem o estabelecimento de conexão.
Implementação OOB personalizada
Nesse tipo de sessão (RANGING_SESSION_RAW), o app ignora o fluxo OOB do módulo Ranging
e processa a própria negociação e parâmetros OOB. Isso significa
que o app precisa determinar quais tecnologias o dispositivo pareado oferece suporte, negociar
parâmetros de alcance e iniciar a sessão de alcance.
Preferências de alcance
Use um objeto RangingPreference para especificar os parâmetros selecionados para uma sessão de alcance. Isso inclui o seguinte:
- Função do dispositivo. Indica se o dispositivo será o iniciador ou o respondente.
- Configuração de alcance. Um objeto
RangingConfigespecifica o tipo de sessão de alcance e outros parâmetros necessários para iniciar uma sessão de alcance. - Configuração da sessão. Um
SessionConfigobjeto especifica parâmetros a serem aplicados na sessão de alcance, como limite de medição, fusão de sensores, configuração de geofence e muito mais.
Permissão de alcance
O módulo Ranging exige uma nova permissão unificada
(android.permission.RANGING) para acessar todas as tecnologias de alcance atuais e futuras. Essa permissão está na lista NEARBY_DEVICES_PERMISSIONS.
<uses-permission android:name="android.permission.RANGING" />
Restrições e limitações
O módulo Ranging pode restringir o alcance por vários motivos, incluindo o seguinte:
- Apps de terceiros só podem realizar o alcance em segundo plano com banda ultralarga e apenas em dispositivos com suporte. O alcance em segundo plano com outras tecnologias não é permitido.
- O alcance não é permitido quando o número máximo de sessões de alcance simultâneas por dispositivo é atingido.
- O alcance pode ser restrito devido a problemas de integridade do sistema, como bateria, desempenho ou memória.
O módulo Ranging também tem as seguintes limitações conhecidas:
- O módulo Ranging só oferece suporte à entrega de dados de alcance a dispositivos pareados para banda ultralarga. Para outras tecnologias, o módulo Ranging só entrega dados de alcance ao dispositivo iniciador.
- O módulo Ranging só oferece suporte à adição dinâmica de dispositivos no modo de alcance bruto e apenas para banda ultralarga.
- O módulo Ranging não oferece suporte a sessões de banda ultralarga de um para muitos para implementações OOB padrão. Se você transmitir vários identificadores de dispositivos, o módulo criará uma sessão individual para cada dispositivo pareado que oferece suporte à banda ultralarga.
Realizar uma sessão de alcance
Para realizar uma sessão de alcance usando o módulo Ranging, siga estas etapas:
- Verifique se todos os dispositivos estão operando no Android 16 ou mais recente.
- Solicite a
android.permission.RANGINGpermissão no manifesto do app. - Avalie os recursos e a disponibilidade das tecnologias de alcance.
- Descubra um dispositivo pareado para operações de alcance.
- Estabeleça uma conexão para uma troca fora de banda, usando um dos tipos de sessão descritos em Tipos de sessão de alcance.
- Inicie o alcance e adquira dados de alcance continuamente.
- Encerre a sessão de alcance.
O exemplo de código a seguir demonstra essas etapas para a função de iniciador e de respondente.
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();
}
}
Interoperabilidade da UWB com dispositivos iOS
O módulo Ranging oferece suporte à interoperabilidade com dispositivos iOS usando banda ultralarga (UWB). Para alcançar um dispositivo iOS, você precisa usar uma implementação OOB personalizada e configurar a sessão de alcance com parâmetros específicos que correspondam ao protocolo de acessório de interação por proximidade da Apple. Consulte o app de exemplo para referência.
Ao criar o RangingPreference, use RawRangingDevice e
UwbRangingParams para especificar a configuração. Os seguintes parâmetros são
essenciais para a interoperabilidade do iOS:
- ID de configuração: Use
UwbRangingParams.CONFIG_UNICAST_DS_TWR. - Informações da chave de sessão:forneça uma matriz de bytes que contenha o ID do fornecedor e o STS IV estático.
- Canal complexo: defina o número do canal e o índice do preâmbulo para corresponder à configuração do dispositivo iOS.
O snippet de código a seguir demonstra como criar um RangingPreference para
um dispositivo iniciador que varia com um respondente iOS:
Kotlin
// Create UwbRangingParams with iOS-specific configuration
val uwbRangingParams = UwbRangingParams.Builder(
sessionId,
UwbRangingParams.CONFIG_UNICAST_DS_TWR,
sourceAddress,
destinationAddress
)
.setComplexChannel(
UwbComplexChannel.Builder()
.setChannel(channelNumber)
.setPreambleIndex(preambleIndex)
.build()
)
.setRangingUpdateRate(updateRate)
.setSessionKeyInfo(sessionKeyInfo) // Vendor ID + STS IV
.setSlotDuration(slotDuration)
.build()
// Create RawRangingDevice
val rawRangingDevice = RawRangingDevice.Builder()
.setRangingDevice(RangingDevice.Builder().build())
.setUwbRangingParams(uwbRangingParams)
.build()
// Create SessionConfig
val sessionConfig = SessionConfig.Builder()
.setAngleOfArrivalNeeded(true)
.setDataNotificationConfig(DataNotificationConfig.Builder()
.setNotificationConfigType(DataNotificationConfig.NOTIFICATION_CONFIG_ENABLE)
.build())
.build()
// Create RangingPreference for the initiator
val preference = RangingPreference.Builder(
RangingPreference.DEVICE_ROLE_INITIATOR,
RawInitiatorRangingConfig.Builder()
.addRawRangingDevice(rawRangingDevice)
.build()
)
.setSessionConfig(sessionConfig)
.build()
Java
// Create UwbRangingParams with iOS-specific configuration
UwbRangingParams uwbRangingParams = new UwbRangingParams.Builder(
sessionId,
UwbRangingParams.CONFIG_UNICAST_DS_TWR,
sourceAddress,
destinationAddress)
.setComplexChannel(new UwbComplexChannel.Builder()
.setChannel(channelNumber)
.setPreambleIndex(preambleIndex)
.build())
.setRangingUpdateRate(updateRate)
.setSessionKeyInfo(sessionKeyInfo) // Vendor ID + STS IV
.setSlotDuration(slotDuration)
.build();
// Create RawRangingDevice
RawRangingDevice rawRangingDevice = new RawRangingDevice.Builder()
.setRangingDevice(new RangingDevice.Builder().build())
.setUwbRangingParams(uwbRangingParams)
.build();
// Create SessionConfig
SessionConfig sessionConfig = new SessionConfig.Builder()
.setAngleOfArrivalNeeded(true)
.setDataNotificationConfig(new DataNotificationConfig.Builder()
.setNotificationConfigType(DataNotificationConfig.NOTIFICATION_CONFIG_ENABLE)
.build())
.build();
// Create RangingPreference for the initiator
RangingPreference preference = new RangingPreference.Builder(
RangingPreference.DEVICE_ROLE_INITIATOR,
new RawInitiatorRangingConfig.Builder()
.addRawRangingDevice(rawRangingDevice)
.build())
.setSessionConfig(sessionConfig)
.build();
App de exemplo
Para um exemplo de ponta a ponta de como usar o módulo Ranging, consulte o app de exemplo na AOSP. Esse app de exemplo abrange todas as tecnologias de alcance com suporte no módulo Ranging e inclui fluxos para os dois tipos de sessão com suporte.
Interoperabilidade da UWB com dispositivos iOS
O app de exemplo do Android oferece suporte ao início de uma sessão de alcance da UWB com o app de exemplo do iOS.