Criar um app Android para casos relevantes

1. Olá!

Criado para unificar os padrões de IoT, o Matter conecta dispositivos de casa inteligente em vários ecossistemas, como o Google Home, Zigbee, Bluetooth Mesh, Z-Wave e muito mais.

Os dispositivos móveis são um ponto central de interação com os dispositivos de casa inteligente. Se você quer criar seus próprios apps Android para oferecer suporte aos dispositivos Matter, podemos ajudar você a começar rapidamente.

O app de exemplo do Google Home para o Matter (GHSA for Matter) mostra as APIs do SDK do Google Mobile para dispositivos móveis, permitindo que os usuários comissionem e compartilhem dispositivos. Você também pode usar o app de exemplo como uma ferramenta de aprendizado para entender melhor os principais conceitos do Matter e depurar e resolver problemas com esses dispositivos.

Atividades deste laboratório

Neste codelab, você vai fazer o download do código-fonte do app de exemplo e aprender a usar o SDK do Home Mobile para comissionar e compartilhar dispositivos. Você também aprenderá a usar as bibliotecas de cluster e de comissionamento do repositório Matter (connectedhomeip).

Depois de fazer o download do app de exemplo, analisaremos o código-fonte no Android Studio e implementaremos as seguintes APIs do SDK do Google Mobile:

Você também vai aprender mais sobre os conceitos de comissionamento, tecidos do Matter e como controlar dispositivos Matter.

O que é necessário

Antes de começar, siga estas etapas:

Você não precisa de um hub, como o Google Nest Hub (segunda geração), para comissionar e controlar dispositivos com o app de exemplo.

2. Preparativos

O repositório do app de exemplo do GitHub inclui bibliotecas de terceiros do repositório Matter (connectedhomeip). Essas bibliotecas nativas têm mais de 50 MB e exigem o uso do Git File Storage Storage (LFS grande).

O app inicial do codelab está localizado na ramificação codelab. Para começar a trabalhar com o código-fonte do codelab, faça o download do arquivo ZIP. Esse ZIP inclui as bibliotecas nativas do SDK do Matter sem a necessidade do Git LFS:

Você usará esse arquivo ZIP codelab para criar uma amostra em funcionamento.

Versões do codelab

A ramificação codelab é marcada com a versão 1.2.2 do app de exemplo. Para comparar suas atualizações em cada etapa, você pode fazer o download do código-fonte completo desta versão.

Se você quiser clonar o repositório do GitHub, siga as instruções no arquivo README do aplicativo de amostra.

Dependências

Orientaremos você no código-fonte necessário para compartilhar e encomendar dispositivos, mas talvez seja importante conhecer as seguintes dependências antes de começar:

  • SDK de dispositivos móveis para casa.
    implementation 'com.google.android.gms:play-services-home:16.0.0'
    
  • Bibliotecas do SDK do Matter.
    // Native libs
    implementation fileTree(dir: "third_party/connectedhomeip/libs", include: ["*.jar", "*.so"])
    
  • Material Design. Para saber mais, consulte MDC-103 Android: temas do Material Design com cor, elevação e tipo (Kotlin) e Material Theme Builder (links em inglês).
    implementation 'com.google.android.material:material:1.5.0'
    
  • Proto DataStore, usado para manter os dados do app. Os repositórios e serializadores do Datastore são armazenados em java/data, incluindo esquemas para dispositivos e preferências do usuário. Para saber mais sobre o DataStore, consulte Como trabalhar com o Proto DataStore.
    implementation "androidx.datastore:datastore:$dataStoreVersion"
    implementation 'androidx.datastore:datastore-core:1.0.0'
    implementation 'com.google.protobuf:protobuf-javalite:3.18.0'
    
  • Hilt para manter os dados e oferecer suporte à injeção de dependência.
    kapt 'com.google.dagger:hilt-compiler:2.41'
    implementation 'com.google.dagger:hilt-android:2.41'
    

Código-fonte

A interface do usuário e a maioria das funcionalidades já foram criadas para você.

Neste codelab, vamos adicionar a funcionalidade Matter aos seguintes arquivos:

  • java/commissioning/AppCommissioningService: permite encomendar dispositivos para a infraestrutura de desenvolvimento
  • java/screens/HomeFragment e java/screens/HomeViewModel.kt: inclui a funcionalidade de comissionamento do Home Mobile SDK
  • java/screens/DeviceViewModel: inclui as chamadas da API Share Device.

Cada arquivo é comentado com o bloco de código que você modificará, por exemplo:

// CODELAB: add commissioningFunction()

Isso permite que você localize rapidamente a seção correspondente no codelab.

3. Comissão para o Google

Antes que você possa controlar os dispositivos e permitir que eles se comuniquem entre si no mesmo tecido, eles precisam ser encomendados por um comissário, que neste caso é o aplicativo de exemplo do Google Home para a matéria.

É importante entender os seguintes conceitos sobre a comissão da Matter:

  • Os tecidos permitem que os dispositivos se comuniquem entre si.
  • Os tecidos mantêm um conjunto compartilhado de credenciais exclusivas.
  • Os ecossistemas são responsáveis por emitir certificados raiz confiáveis, atribuir IDs de tecido e IDs de nó exclusivos. Um ecossistema é o serviço de back-end de um comissário, por exemplo, o Home Graph do ecossistema do Google Home.
  • Os dispositivos podem ser encomendados a mais de uma malha (recurso multiadministrador).

Para comissionar um dispositivo, você precisa usar a API CommissioningClient. Uma chamada para .commissionDevice() retorna um IntentSender, que inicia a atividade adequada no Google Play Services:

interface CommissioningClient {
  Task<IntentSender> commissionDevice(CommissioningRequest request);
}

Nas próximas seções, abordaremos o código mínimo necessário para comissionar dispositivos no conjunto do Google.

Etapa 1: acesso rápido às atividades

Para processar o IntentSender do CommissioningClient, você pode usar um ActivityResultLauncher:

private lateinit var commissioningLauncher: ActivityResultLauncher<IntentSenderRequest>
commissioningLauncher = registerForActivityResult(
    StartIntentSenderForResult()
) { result: ActivityResult ->
    if (result.resultCode == RESULT_OK) {
        Timber.d(TAG, "Commissioning succeeded.")
    } else {
        Timber.d(TAG, "Commissioning failed. " + result.resultCode)
    }
}

Etapa 2: função de comissionamento

Veja um exemplo básico que usa a API CommissioningClient para comissionar um dispositivo no tecido do Google.

  1. O processo de comissionamento começa com a função commissionDevice(). Primeiro, um CommissioningRequest é definido. Com essa configuração padrão, os dispositivos são encomendados apenas para a infraestrutura local do Android.
  2. Matter é o ponto de entrada do SDK do Home Mobile. Na próxima chamada, .getCommissioningClient recebe um CommissioningClient de this (Activity).
  3. .commissionDevice() aceita CommissioningRequest.
  4. Por fim, .addOnSuccessListener é chamado para processar o CommissioningResult e iniciar a atividade do dispositivo de comissão do Google Play Services (GPS).
private fun commissionDevice() {
    val request: CommissioningRequest = CommissioningRequest.builder().build()
    Matter.getCommissioningClient(this)
        .commissionDevice(request)
        .addOnSuccessListener { result ->
            commissioningLauncher.launch(IntentSenderRequest.Builder(result).build())
        }
}

O Android Fabric local pode ser aproveitado por meio de configurações do Android para simplificar o processo de comissionamento de seus dispositivos para outros tecidos.

Em seguida, você vai aprender a comissionar um dispositivo para uma malha de desenvolvimento.

Para uma visão geral da interface do usuário durante o processo de comissionamento, consulte o Guia de amostra do app Google Home para o caso.

4. Comissão para uma malha de desenvolvimento

Os dispositivos podem ser encomendados a mais de um tecido. Para gerenciar pares confiáveis, os dispositivos armazenam um FabricTable que contém vários membros do FabricInfo, por exemplo:

  • Identificação do tecido
  • ID do nó atribuído pelo Fabric ao dispositivo
  • ID do fornecedor
  • ID do Fabric
  • Credenciais operacionais do dispositivo

O gerenciador de domínio administrativo (ADM) define as credenciais da malha. No cenário anterior, o Google Play Services é o ecossistema que atua como uma autoridade de certificação (CA, na sigla em inglês) raiz confiável. Quando você encomenda dispositivos para a malha local do Android, cada dispositivo inclui o mesmo conjunto de credenciais e o mesmo conjunto de CAs.

Serviços de comissão personalizados

Para comissionar no tecido do Android local, usamos os parâmetros padrão para criar o CommissioningRequest na API CommissioningClient:

val request: CommissioningRequest = CommissioningRequest.builder().build()

Se quiser controlar e gerenciar novos dispositivos a partir do aplicativo, crie uma malha de desenvolvimento local e receba as credenciais operacionais para encomendar dispositivos. Nesse cenário, seu app se torna um ecossistema único e independente que atribui aos dispositivos as credenciais de nó adequadas.

Você pode informar ao SDK do Google Home Mobile que deseja comissionar dispositivos para seu tecido passando um serviço personalizado para o CommissioningRequest:

class CommissioningRequest {
  static CommissioningRequest.Builder builder();

  class Builder {
    Builder setCommissioningService(@Nullable ComponentName commissioningService);

    CommissioningRequest build();
  }
}

Nas próximas etapas, modificaremos a função commissionDevice() para usar um serviço personalizado. Também adicionaremos um inicializador de atividade ao fragmento inicial e usaremos os objetos LiveData para gerenciar o fluxo da API.

Etapa 1: criar um acesso rápido às atividades do GPS

Primeiro, vamos criar um acesso rápido de atividades para processar o IntentSender da API CommissioningClient.

  1. Abra HomeFragment na pasta java/screens/home/.
  2. Substitua o comentário // CODELAB: commissionDeviceLauncher declaration pela seguinte declaração:
    // The ActivityResult launcher that launches the "commissionDevice" activity in Google Play
    // Services.
    private lateinit var commissionDeviceLauncher: ActivityResultLauncher<IntentSenderRequest>
    
  3. Substitua o comentário // CODELAB: commissionDeviceLauncher definition pelo seguinte código para registrar e gerenciar o resultado da atividade de ativação:
    commissionDeviceLauncher =
        registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result ->
          // Commission Device Step 5.
          // The Commission Device activity in GPS has completed.
          val resultCode = result.resultCode
          if (resultCode == Activity.RESULT_OK) {
            Timber.d("CommissionDevice: Success")
            // We now need to capture the device information for the app's fabric.
            // Once this completes, a call is made to the viewModel to persist the information
            // about that device in the app.
            showNewDeviceAlertDialog(result)
          } else {
            viewModel.commissionDeviceFailed(resultCode)
          }
        }    ```
    
    

Etapa 2: criar objetos LiveData

O callback da API .commissionDevice() fornece o IntentSender a ser usado para iniciar a atividade do dispositivo da comissão no Google Play Services. No HomeViewModel, criaremos dois objetos LiveData para gerar relatórios sobre o resultado dessa chamada de API:

  • commissionDeviceStatus para rastrear o TaskStatus.
  • commissionDeviceIntentSender para processar o resultado da chamada .commissionDevice(). Esse objeto LiveData iniciará o ActivityLauncher que acabamos de criar e exibirá a atividade do dispositivo da comissão do GPS para o usuário.
  1. No private fun setupObservers(), substitua o comentário // CODELAB: commissionDeviceStatus pelo seguinte observador:
    // The current status of the share device action.
    viewModel.commissionDeviceStatus.observe(viewLifecycleOwner) { status ->
      Timber.d("commissionDeviceStatus.observe: status [${status}]")
    }
    
  2. Em seguida, substitua o comentário // CODELAB: commissionDeviceIntentSender pelo seguinte observador:
    viewModel.commissionDeviceIntentSender.observe(viewLifecycleOwner) { sender ->
      Timber.d(
          "commissionDeviceIntentSender.observe is called with [${intentSenderToString(sender)}]")
      if (sender != null) {
        // Commission Device Step 4: Launch the activity described in the IntentSender that
        // was returned in Step 3 (where the viewModel calls the GPS API to commission
        // the device).
        Timber.d("CommissionDevice: Launch GPS activity to commission device")
        commissionDeviceLauncher.launch(IntentSenderRequest.Builder(sender).build())
        viewModel.consumeCommissionDeviceIntentSender()
      }
    }
    

Etapa 3: chamar a API

Agora que criamos o código para processar o fluxo da API, é hora de chamar a API, transmitir um serviço personalizado (que será definido na próxima etapa) e postar nos objetos LiveData.

  1. Abra HomeViewModel.kt na pasta java/screens/home/.
  2. Substitua o comentário // CODELAB: commissionDevice pelo seguinte commissionDeviceRequest. setCommissioningService vincula AppCommissioningService a uma instância de CommissioningService, retornada em uma função de callback. Quando você passa um serviço personalizado, o SDK do Google Home para dispositivos móveis primeiro encomenda os dispositivos para a malha do Google e, em seguida, envia o payload de integração para o AppCommissioningService.
    fun commissionDevice(context: Context) {
      _commissionDeviceStatus.postValue(TaskStatus.InProgress)
    
      val commissionDeviceRequest =
          CommissioningRequest.builder()
              .setCommissioningService(ComponentName(context, AppCommissioningService::class.java))
              .build()
    
  3. Chame .getCommissioningClient() e, em seguida, chame .commissionDevice().
    Matter.getCommissioningClient(context)
        .commissionDevice(commissionDeviceRequest)
    

Para concluir nossa função commissionDevice, adicione um addOnSuccessListener e um addOnFailureListener e publique nos objetos LiveData:

      .addOnSuccessListener { result ->
        // Communication with fragment is via livedata
        _commissionDeviceIntentSender.postValue(result)
      }
      .addOnFailureListener { error ->
        Timber.e(error)
        _commissionDeviceStatus.postValue(
          TaskStatus.Failed("Failed to to get the IntentSender.", error)
      }
}

Depois de usar o remetente, consumeCommissionDeviceIntentSender() precisa ser chamado para evitar o recebimento do remetente novamente após uma mudança de configuração.

  /**
   * Consumes the value in [_commissionDeviceIntentSender] and sets it back to null. Needs to be
   * called to avoid re-processing the IntentSender after a configuration change (where the LiveData
   * is re-posted).
   */
  fun consumeCommissionDeviceIntentSender() {
    _commissionDeviceIntentSender.postValue(null)
  }

5. Criar um CommissioningService

Na função commissionDevice(), solicitamos o recebimento de um CommissioningService da API CommissioningClient. Nesse fluxo, a API CommissioningClient encomenda dispositivos para a malha local do Android primeiro e depois retorna um callback que inclui o objeto CommissioningRequestMetadata:

public interface CommissioningService {
interface Callback {
    void onCommissioningRequested(CommissioningRequestMetadata metadata);
  }
}

Agora, precisamos herdar o CommissioningService.Callback e fornecer a funcionalidade necessária para ativar dispositivos no nosso app de exemplo. Veja um exemplo de implementação básica de CommissioningService:

class MatterCommissioningService : Service(), CommissioningService.Callback {
   private val commissioningServiceDelegate =
     CommissioningService.Builder(this)
       .setCallback(this)
       .build()

   override fun onBind(intent: Intent) = commissioningServiceDelegate.asBinder()

   override fun onCommissioningRequested(metadata: CommissioningRequestMetadata) {
     // perform commissioning

     commissioningServiceDelegate
       .sendCommissioningComplete(CommissioningCompleteMetadata.builder().build())
   }
 }

Etapa 1: explorar o AppCommissioningService personalizado

Para ajudar você a começar, já definimos a estrutura de classes básica para nosso CommissioningService personalizado. Esta é uma visão geral rápida da funcionalidade do serviço. Para acompanhar, abra AppCommissioningService em java/commissioning.

Adicionamos as seguintes importações às APIs Mobile SDK:

import com.google.android.gms.home.matter.commissioning.CommissioningCompleteMetadata
import com.google.android.gms.home.matter.commissioning.CommissioningRequestMetadata
import com.google.android.gms.home.matter.commissioning.CommissioningService

AppCommissioningService também inclui bibliotecas do repositório Matter (connectedhomeip):

import com.google.home_sample_app_for_matter.chip.ChipClient

Por fim, o serviço inclui importações compatíveis com Hilt e corrotinas de Kotlin.

Em seguida, criamos o construtor e definimos alguns itens, incluindo o commissioningServiceDelegate, que usaremos para informar ao Google Play Services quando o comissionamento estiver concluído.

private lateinit var commissioningServiceDelegate: CommissioningService
...
commissioningServiceDelegate = CommissioningService.Builder(this).setCallback(this).build()

Agora é hora de adicionar as funções de comissionamento.

Etapa 2: substituir onCommissioningRequested

Para encomendar dispositivos para a malha de desenvolvimento do app, siga estas etapas:

  1. Abrir AppCommissioningService em java/commissioning.
  2. Localize a função onCommissioningRequested(). Fornecemos uma mensagem de registro que mostra o CommissioningRequestMetadata. Substitua o comentário // CODELAB: onCommissioningRequested() para iniciar a corrotina serviceScope e receber o deviceId.
    // Perform commissioning on custom fabric for the sample app.
    serviceScope.launch {
      val deviceId = devicesRepository.incrementAndReturnLastDeviceId()
    
  3. Realize o comissionamento. Para esta etapa, podemos transmitir as informações do dispositivo retornadas no objeto CommissioningRequestMetadata. O ChipClient usa essas informações para criar um canal seguro entre o app GHSA for Matter e seu dispositivo.
    Timber.d("Commissioning: App fabric -> ChipClient.establishPaseConnection(): deviceId [${deviceId}]")
    chipClient.awaitEstablishPaseConnection(
        deviceId,
        metadata.networkLocation.ipAddress.hostAddress!!,
        metadata.networkLocation.port,
        metadata.passcode)
    Timber.d("Commissioning: App fabric -> ChipClient.commissionDevice(): deviceId [${deviceId}]")
    chipClient.awaitCommissionDevice(deviceId, null)
    
  4. Use o commissioningServiceDelegate para informar ao Google Play Services que o comissionamento foi concluído. Em .sendCommissioningComplete(), transmita CommissioningCompleteMetadata.
      Timber.d("Commissioning: Calling commissioningServiceDelegate.sendCommissioningComplete()")
      commissioningServiceDelegate
          .sendCommissioningComplete(
              CommissioningCompleteMetadata.builder().setToken(deviceId.toString()).build())
          .addOnSuccessListener {
              Timber.d("Commissioning: OnSuccess for commissioningServiceDelegate.sendCommissioningComplete()")
          }
          .addOnFailureListener { ex -> 
            Timber.e(ex, "Commissioning: Failed to send commissioning complete.", ex)
          }
    }
    

Executar o app

Agora que todo o código necessário está pronto para ser comissionado com nossa malha local, é hora de testá-lo. Escolha seu dispositivo Android e execute o app. Na tela inicial, toque em Adicionar dispositivo e siga as etapas para ativar o dispositivo.

Agora, quando o comissionamento for concluído, o dispositivo participará de dois tecidos: o tecido local do Android e o tecido de desenvolvimento local. Cada tecido tem o próprio conjunto de credenciais e um ID de tecido exclusivo de 64 bits.

6. Controlar dispositivos

A ativação de uma malha de desenvolvimento permite que você use as bibliotecas do repositório Matter (connectedhomeip) para controlar dispositivos do app de amostra.

Criamos algumas classes auxiliares para facilitar o acesso aos clusters do dispositivo e o envio de comandos. Para saber mais, abra ClustersHelper em java/clusters. Esse auxiliar de Singleton importa as seguintes bibliotecas para acessar as informações do dispositivo:

import chip.devicecontroller.ChipClusters
import chip.devicecontroller.ChipStructs

Podemos usar essa classe para receber o cluster de ativação/desativação de um dispositivo e chamar .toggle:

suspend fun toggleDeviceStateOnOffCluster(deviceId: Long, endpoint: Int) {
  Timber.d("toggleDeviceStateOnOffCluster())")
  val connectedDevicePtr =
      try {
        chipClient.getConnectedDevicePointer(deviceId)
      } catch (e: IllegalStateException) {
        Timber.e("Can't get connectedDevicePointer.")
        return
      }
  return suspendCoroutine { continuation ->
    getOnOffClusterForDevice(connectedDevicePtr, endpoint)
        .toggle(
            object : ChipClusters.DefaultClusterCallback {
              override fun onSuccess() {
                continuation.resume(Unit)
              }
              override fun onError(ex: Exception) {
                Timber.e("readOnOffAttribute command failure: $ex")
                continuation.resumeWithException(ex)
              }
            })
  }
}

Alternar um dispositivo

Depois de comissionar um dispositivo, o payload retornado em CommissioningResult é adicionado ao DataStore. Isso permite que nosso app acesse informações do dispositivo que podem ser usadas para enviar comandos.

Os apps Matter são orientados por eventos. Quando a pilha do Matter é inicializada, os serviços do cluster detectam mensagens recebidas. Quando um dispositivo é comissionado, os clientes do Matter enviam comandos pelo canal operacional seguro estabelecido durante a ativação do dispositivo.

No dispositivo, os pacotes são validados, descriptografados e enviados com um callback. As funções de callback incluem EndpointId, ClusterId e AttributeId, que podem ser acessadas no attributePath. Por exemplo, este código pode ser implementado em um dispositivo Matter:

void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t mask, uint8_t type,
                                       uint16_t size, uint8_t * value)
{
    // handle callback
    ClusterId clusterId     = attributePath.mClusterId;
    AttributeId attributeId = attributePath.mAttributeId;
}

Nas próximas etapas, você vai usar o SDK do Matter e o ClustersHelper para alternar um dispositivo.

  1. Vá para DeviceViewModel em java/screens/device.
  2. Localize a função updateDeviceStateOn.
  3. Substitua o comentário // CODELAB: toggle pelo código para chamar clustersHelper e atualize o repositório do dispositivo:
    Timber.d("Handling real device")
        try {
          clustersHelper.setOnOffDeviceStateOnOffCluster(deviceUiModel.device.deviceId, isOn, 1)
          devicesStateRepository.updateDeviceState(deviceUiModel.device.deviceId, true, isOn)
        } catch (e: Throwable) {
          Timber.e("Failed setting on/off state")
        }
    

Esta função é chamada a partir de DeviceFragment:

// Change the on/off state of the device
binding.onoffSwitch.setOnClickListener {
  val isOn = binding.onoffSwitch.isChecked
  viewModel.updateDeviceStateOn(selectedDeviceViewModel.selectedDeviceLiveData.value!!, isOn)
}

Executar o app

Execute o app para recarregar as atualizações. Na tela inicial, ative e desative o dispositivo.

7. Compartilhar dispositivos com outros ecossistemas

O compartilhamento de um dispositivo é chamado de fluxo de vários administradores na especificação do Matter.

Nas etapas anteriores, aprendemos que o SDK do Google Mobile para dispositivos móveis permite encomendar dispositivos para a malha local do Android e também para uma malha de desenvolvimento do app de exemplo. Este é um exemplo de fluxo de vários administradores, em que os dispositivos podem ser encomendados a mais de uma malha.

Agora, você pode querer compartilhar dispositivos com ainda mais tecidos, especialmente se esta for uma família em que as pessoas têm suas próprias preferências em relação a aplicativos e plataformas.

O SDK do Mobile para dispositivos móveis oferece essa funcionalidade na API ShareDeviceRequest, que permite:

  1. Abra uma janela de comissionamento temporária para os dispositivos.
  2. Altere o estado dos dispositivos, permitindo que eles sejam encomendados a outro tecido.
  3. Controle seus dispositivos a partir de outros apps e ecossistemas.

Nas próximas etapas, você usará o SDK do Google Home para dispositivos móveis para compartilhar dispositivos.

Etapa 1: criar um acesso rápido às atividades do GPS

Assim como o inicializador de atividades de comissionamento, criado quando encomendamos um tecido de desenvolvimento, criamos um iniciador de atividade de compartilhamento de dispositivo para gerenciar o IntentSender da API CommissioningClient.

  1. Abra DeviceFragment na pasta java/screens/device/.
  2. Substitua o comentário // CODELAB: shareDeviceLauncher definition pelo seguinte código para registrar e processar o resultado da atividade .shareDevice():
    shareDeviceLauncher =
        registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result ->
          // Share Device Step 5.
          // The Share Device activity in GPS (step 4) has completed.
          val resultCode = result.resultCode
          if (resultCode == RESULT_OK) {
            Timber.d("ShareDevice: Success")
            viewModel.shareDeviceSucceeded(selectedDeviceViewModel.selectedDeviceLiveData.value!!)
          } else {
            viewModel.shareDeviceFailed(
                selectedDeviceViewModel.selectedDeviceLiveData.value!!, resultCode)
          }
        }
    

Etapa 2: revisar objetos LiveData

O callback da API .shareDevice() fornece o IntentSender a ser usado para iniciar a atividade Compartilhar dispositivo no Google Play Services. No DeviceViewModel, criamos dois objetos LiveData para gerar relatórios sobre o resultado dessa chamada de API:

  • _shareDeviceStatus para rastrear o TaskStatus.
    // The current status of the share device action.
    viewModel.shareDeviceStatus.observe(viewLifecycleOwner) { status ->
      val isButtonEnabled = status !is InProgress
      updateShareDeviceButton(isButtonEnabled)
      if (status is TaskStatus.Failed) {
        showAlertDialog(errorAlertDialog, status.message, status.cause!!.toString())
      }
    }
    
  • _shareDeviceIntentSender para processar o resultado da chamada .sharedevice().
    viewModel.shareDeviceIntentSender.observe(viewLifecycleOwner) { sender ->
      Timber.d("shareDeviceIntentSender.observe is called with [${intentSenderToString(sender)}]")
      if (sender != null) {
        // Share Device Step 4: Launch the activity described in the IntentSender that
        // was returned in Step 3 (where the viewModel calls the GPS API to commission
        // the device).
        Timber.d("ShareDevice: Launch GPS activity to share device")
        shareDeviceLauncher.launch(IntentSenderRequest.Builder(sender).build())
        viewModel.consumeShareDeviceIntentSender()
      }
    }
    

Nas próximas etapas, vamos usar esses objetos LiveData na nossa chamada da API .shareDevice().

Etapa 3: chamar a API

Agora é hora de iniciar uma tarefa de compartilhamento de dispositivo.

  1. Abra DeviceViewModel.kt na pasta java/screens/device/.
  2. Localize a função shareDevice(). Substitua o comentário // CODELAB: shareDevice pelo ShareDeviceRequest. O DeviceDescriptor fornece informações específicas sobre o dispositivo, como o ID do fornecedor, o ID do produto e o deviceType. Neste exemplo, codificamos os valores.
      Timber.d("ShareDevice: Setting up the IntentSender")
      val shareDeviceRequest =
          ShareDeviceRequest.builder()
              .setDeviceDescriptor(DeviceDescriptor.builder().build())
              .setDeviceName("temp device name")
    
  3. Defina CommissioningWindow e parâmetros. Neste ponto, a janela de comissionamento temporária está aberta no dispositivo.
              .setCommissioningWindow(
                  CommissioningWindow.builder()
                      .setDiscriminator(Discriminator.forLongValue(DISCRIMINATOR))
                      .setPasscode(SETUP_PIN_CODE)
                      .setWindowOpenMillis(SystemClock.elapsedRealtime())
                      .setDurationSeconds(OPEN_COMMISSIONING_WINDOW_DURATION_SECONDS.toLong())
                      .build())
              .build()
    
  4. Chame .getCommissioningClient(), só que desta vez, use a API .shareDevice(). O callback de sucesso da API commissioningClient.shareDevice() fornece o IntentSender a ser usado para iniciar a atividade "Compartilhar dispositivo" no Google Play Services.
    Matter.getCommissioningClient(activity)
        .shareDevice(shareDeviceRequest)
    
  5. Para concluir a função shareDevice, adicione um addOnSuccessListener e um addOnFailureListener e publique nos objetos LiveData:
          .addOnSuccessListener { result ->
            Timber.d("ShareDevice: Success getting the IntentSender: result [${result}]")
            // Communication with fragment is via livedata
            _backgroundWorkAlertDialogAction.postValue(BackgroundWorkAlertDialogAction.Hide)
            _shareDeviceIntentSender.postValue(result)
          }
          .addOnFailureListener { error ->
            Timber.e(error)
            _backgroundWorkAlertDialogAction.postValue(BackgroundWorkAlertDialogAction.Hide)
            _shareDeviceStatus.postValue(
                TaskStatus.Failed("Setting up the IntentSender failed", error))
          }
    

Depois de usar o remetente, consumeShareDeviceIntentSender precisa ser chamado para evitar o recebimento do remetente novamente após uma mudança de configuração.

  /**
   * Consumes the value in [_shareDeviceIntentSender] and sets it back to null. Needs to be called
   * to avoid re-processing an IntentSender after a configuration change where the LiveData is
   * re-posted.
   */
  fun consumeShareDeviceIntentSender() {
    _shareDeviceIntentSender.postValue(null)
  }

Executar o app

Para compartilhar o dispositivo Matter com outros ecossistemas, é preciso ter outra plataforma instalada no dispositivo Android. Criamos outra instância do aplicativo de amostra que você pode usar como comissário de destino.

Depois de instalar o comissário de destino no dispositivo Android, verifique se é possível compartilhar o dispositivo Matter. O app de comissão do alvo é rotulado como GHSAFM-TC.

Seus dispositivos agora podem participar de três tecidos:

  1. O tecido local do Android.
  2. Seu tecido de desenvolvimento (este app).
  3. Este terceiro tecido com que você acabou de compartilhar o dispositivo.

8. Próximas etapas

Parabéns

Parabéns! Você concluiu este codelab e aprendeu a comissionar e compartilhar dispositivos usando o SDK do Google Home para dispositivos móveis.

Se você tiver problemas com o app de exemplo, siga as etapas abaixo para verificar o ambiente:

Se você tiver dúvidas sobre como usar o app de amostra ou descobrir um bug de código, envie os problemas para o Issue Tracker no repositório do GitHub:

Para receber orientações oficiais do Google sobre dúvidas técnicas, use o Fórum de desenvolvedores da casa inteligente:

Para receber suporte técnico da comunidade, use a tag google-smart-home no Stack Overflow: