Enviar e receber mensagens no Wear

Você envia mensagens usando a API MessageClient e anexa os seguintes itens à mensagem:

  • Um payload arbitrário (opcional)
  • Um caminho que identifique de forma exclusiva a ação da mensagem

Ao contrário do caso de itens de dados, não ocorre sincronização entre os apps de dispositivos portáteis e de wearables. As mensagens são um mecanismo de comunicação de uma única direção que é útil para chamadas de procedimento remoto (RPC, na sigla em inglês), como uma mensagem enviada ao wearable para iniciar uma atividade.

Vários dispositivos wearable podem ser conectados ao dispositivo portátil de um usuário. Cada dispositivo conectado à rede é considerado um . Com vários dispositivos conectados, você precisa considerar quais nós recebem as mensagens. Por exemplo, em um app de transcrição de voz que recebe dados de voz no dispositivo wearable, você precisa enviar a mensagem para um nó com o poder de processamento e a capacidade de bateria para processar a solicitação, como um dispositivo portátil.

Observação: com versões do Google Play Services anteriores à 7.3.0, apenas um dispositivo wearable pode ser conectado por vez ao dispositivo portátil. Você pode precisar atualizar o código existente para considerar o recurso de conexão simultânea a vários nós. Caso você não implemente as mudanças, as mensagens podem não ser entregues aos dispositivos pretendidos.

Confira os seguintes recursos relacionados:

Enviar mensagem

Um app wearable pode fornecer funcionalidade para os usuários, como a transcrição de voz. O usuário pode falar no microfone do dispositivo wearable e ter a transcrição salva em formato de nota. Como um dispositivo wearable normalmente não tem o poder de processamento e a capacidade da bateria necessários para processar a atividade de transcrição de voz, o app precisa transferir esse trabalho para um dispositivo conectado mais potente.

As seções a seguir mostram como anunciar nós de dispositivos que podem processar solicitações de atividades, descobrir os nós capazes de atender uma necessidade de solicitação e enviar mensagens para esses nós.

Para iniciar uma atividade em um dispositivo portátil usando um dispositivo wearable, use a classe MessageClient para enviar a solicitação. Como vários wearables podem ser conectados ao dispositivo portátil, o app para wearables precisa determinar se um nó conectado é capaz de iniciar a atividade. No app portátil, anuncie que o nó em que ele é executado tem recursos específicos.

Para anunciar os recursos do app portátil:

  1. Crie um arquivo de configuração XML no diretório res/values/ do seu projeto e nomeie-o como wear.xml.
  2. Adicione um recurso chamado android_wear_capabilities a wear.xml.
  3. Defina os recursos que o dispositivo oferece.

Observação: recursos são strings personalizadas que você define e precisam ser únicos dentro do app.

O exemplo a seguir mostra como adicionar uma capacidade chamada voice_transcription a wear.xml:

    <resources xmlns:tools="http://schemas.android.com/tools"
               tools:keep="@array/android_wear_capabilities">
        <string-array name="android_wear_capabilities">
            <item>voice_transcription</item>
        </string-array>
    </resources>
    

Recuperar nós com os recursos necessários

Inicialmente, você pode detectar os nós compatíveis chamando o método getCapability da classe CapabilityClient. O exemplo a seguir mostra como recuperar manualmente os resultados dos nós ao alcance com a capacidade voice_transcription:

Kotlin

    private const val VOICE_TRANSCRIPTION_CAPABILITY_NAME = "voice_transcription"
    ...
    private fun setupVoiceTranscription() {
        val capabilityInfo: CapabilityInfo = Tasks.await(
                Wearable.getCapabilityClient(context)
                        .getCapability(
                                VOICE_TRANSCRIPTION_CAPABILITY_NAME,
                                CapabilityClient.FILTER_REACHABLE
                        )
        )
        // capabilityInfo has the reachable nodes with the transcription capability
        updateTranscriptionCapability(capabilityInfo)
    }
    

Java

    private static final String
        VOICE_TRANSCRIPTION_CAPABILITY_NAME = "voice_transcription";
        ...
    private void setupVoiceTranscription() {
        CapabilityInfo capabilityInfo = Tasks.await(
            Wearable.getCapabilityClient(context).getCapability(
                VOICE_TRANSCRIPTION_CAPABILITY_NAME, CapabilityClient.FILTER_REACHABLE));
        // capabilityInfo has the reachable nodes with the transcription capability
        updateTranscriptionCapability(capabilityInfo);
    }
    

Para detectar nós compatíveis conforme eles forem conectados ao dispositivo wearable, registre uma instância de um listener, mais especificamente, um OnCapabilityChangedListener de um objeto CapabilityClient. O exemplo a seguir mostra como registrar o listener e recuperar os resultados de nós ao alcance com o recurso voice_transcription:

Kotlin

    private fun setupVoiceTranscription() {
        updateTranscriptionCapability(capabilityInfo).also { capabilityListener ->
            Wearable.getCapabilityClient(context).addListener(
                    capabilityListener,
                    VOICE_TRANSCRIPTION_CAPABILITY_NAME
            )
        }
    }
    

Java

    private void setupVoiceTranscription() {
        ...
        // This example uses a Java 8 Lambda. Named or anonymous classes can also be used.
        CapabilityClient.OnCapabilityChangedListener capabilityListener =
            capabilityInfo -> { updateTranscriptionCapability(capabilityInfo); };
        Wearable.getCapabilityClient(context).addListener(
            capabilityListener,
            VOICE_TRANSCRIPTION_CAPABILITY_NAME);
    }
    

Depois de detectar os nós compatíveis, determine o destino da mensagem. Você precisa escolher um nó que esteja próximo ao seu dispositivo wearable para minimizar o roteamento de mensagens por vários nós. Um nó próximo é um nó que está diretamente conectado ao dispositivo. Para determinar se um nó está próximo, chame o método Node.isNearby().

O exemplo a seguir mostra como você pode determinar o melhor nó para usar:

Kotlin

    private var transcriptionNodeId: String? = null

    private fun updateTranscriptionCapability(capabilityInfo: CapabilityInfo) {
        transcriptionNodeId = pickBestNodeId(capabilityInfo.nodes)
    }

    private fun pickBestNodeId(nodes: Set<Node>): String? {
        // Find a nearby node or pick one arbitrarily
        return nodes.firstOrNull { it.isNearby }?.id ?: nodes.firstOrNull()?.id
    }
    

Java

    private String transcriptionNodeId = null;

    private void updateTranscriptionCapability(CapabilityInfo capabilityInfo) {
        Set<Node> connectedNodes = capabilityInfo.getNodes();

        transcriptionNodeId = pickBestNodeId(connectedNodes);
    }

    private String pickBestNodeId(Set<Node> nodes) {
        String bestNodeId = null;
        // Find a nearby node or pick one arbitrarily
        for (Node node : nodes) {
            if (node.isNearby()) {
                return node.getId();
             }
             bestNodeId = node.getId();
        }
        return bestNodeId;
    }
    

Entregar a mensagem

Depois de identificar o melhor nó para usar, envie a mensagem usando a classe MessageClient.

O exemplo abaixo mostra como enviar uma mensagem para o nó compatível com transcrições a partir de um dispositivo wearable. Verifique se o nó está disponível antes de tentar enviar a mensagem. Esse chamado é síncrono e bloqueia o processamento até o sistema colocar a mensagem na fila de entrega.

Observação: um código de resultado bem-sucedido não garante que a mensagem foi entregue. Se o app exigir confiabilidade de dados, use objetos DataItem ou a classe ChannelClient para enviar dados entre dispositivos.

Kotlin

    const val VOICE_TRANSCRIPTION_MESSAGE_PATH = "/voice_transcription"
    ...
    private fun requestTranscription(voiceData: ByteArray) {
        transcriptionNodeId?.also { nodeId ->
            val sendTask: Task<*> = Wearable.getMessageClient(context).sendMessage(
                    nodeId,
                    VOICE_TRANSCRIPTION_MESSAGE_PATH,
                    voiceData
            ).apply {
                addOnSuccessListener { ... }
                addOnFailureListener { ... }
            }
        }
    }
    

Java

    public static final String VOICE_TRANSCRIPTION_MESSAGE_PATH = "/voice_transcription";
    private void requestTranscription(byte[] voiceData) {
        if (transcriptionNodeId != null) {
            Task<Integer> sendTask =
                Wearable.getMessageClient(context).sendMessage(
                  transcriptionNodeId, VOICE_TRANSCRIPTION_MESSAGE_PATH, voiceData);
             // You can add success and/or failure listeners,
             // Or you can call Tasks.await() and catch ExecutionException
             sendTask.addOnSuccessListener(...);
             sendTask.addOnFailureListener(...);
        } else {
            // Unable to retrieve node with transcription capability
        }
    }
    

Observação: para saber mais sobre chamadas síncronas e assíncronas para o Google Play Services e quando usar cada uma delas, consulte a API Tasks.

Você também pode transmitir mensagens para todos os nós conectados. Para recuperar todos os nós conectados aos quais você pode enviar mensagens, implemente o seguinte código:

Kotlin

    private fun getNodes(): Collection<String> {
        return Tasks.await(Wearable.getNodeClient(context).connectedNodes).map { it.id }
    }
    

Java

    private Collection<String> getNodes() {
        HashSet <String>results = new HashSet<String>();
        List<Node> nodes =
            Tasks.await(Wearable.getNodeClient(context).getConnectedNodes());
        for (Node node : nodes.getNodes()) {
            results.add(node.getId());
        }
        return results;
    }
    

Receber uma mensagem

Para receber notificações de mensagens recebidas, implemente a interface MessageClient.OnMessageReceivedListener para fornecer um listener para eventos de mensagem. Em seguida, registre o listener com o método addListener. Este exemplo mostra como você pode implementar o listener para verificar o VOICE_TRANSCRIPTION_MESSAGE_PATH. Se essa condição for true, inicie uma atividade para processar os dados de voz.

Kotlin

    fun onMessageReceived(messageEvent: MessageEvent) {
        if (messageEvent.path == VOICE_TRANSCRIPTION_MESSAGE_PATH) {
            val startIntent = Intent(this, MainActivity::class.java).apply {
                addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                putExtra("VOICE_DATA", messageEvent.data)
            }
            startActivity(this, startIntent)
        }
    }
    

Java

    @Override
    public void onMessageReceived(MessageEvent messageEvent) {
        if (messageEvent.getPath().equals(VOICE_TRANSCRIPTION_MESSAGE_PATH)) {
            Intent startIntent = new Intent(this, MainActivity.class);
            startIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startIntent.putExtra("VOICE_DATA", messageEvent.getData());
            startActivity(this, startIntent);
        }
    }
    

Isso é apenas um snippet que precisa de mais detalhes de implementação. Saiba como implementar uma atividade ou um serviço completo de listener em Detectar eventos de Data Layer.