Expor dados para complicações

Os apps de provedores de dados expõem informações para complicações do mostrador do relógio, disponibilizando campos que contêm texto, strings, imagens e números.

O serviço do provedor de dados estende o ComplicationProviderService para fornecer informações úteis diretamente para o mostrador do relógio.

Criar um projeto de provedor de dados

Para criar um projeto no Android Studio para seu app de provedor de dados, siga estas etapas:

  1. Clique em Studio > New > New project.
  2. Na janela Project Template, clique na guia "Wear OS", selecioneNo Activity e, em seguida, clique em Next.
  3. Na janela Configure Your Project, insira um nome, preencha as informações padrão do projeto e clique em Finish.
  4. O Android Studio cria um projeto com um módulo do app para o provedor de dados. Para ver mais informações sobre projetos no Android Studio, consulte Criar um projeto.
  5. Inicie o app de provedor de dados criando uma nova classe que estenda BroadcastReceiver. O objetivo dessa classe é ouvir solicitações de atualização de complicações do sistema Wear OS. Além disso, crie uma nova classe que estenda o ComplicationProviderService para fornecer dados conforme solicitado pelas complicações apropriadas. Para mais informações, consulte os recursos abaixo:

    Observação: adicionar uma atividade ao provedor de dados é opcional. Por exemplo, talvez você queira que uma atividade seja iniciada apenas quando o usuário tocar em uma complicação.

Implementar um método para solicitar atualizações

Quando dados de complicação são necessários, o sistema Wear OS envia solicitações de atualização ao provedor de dados. As solicitações são recebidas pelo BroadcastReceiver. Para responder às solicitações de atualização, o provedor de dados precisa implementar o método onComplicationUpdate() da classe ComplicationProviderService.

O sistema Wear OS chama onComplicationUpdate() quando precisa de dados do provedor. Por exemplo, quando uma complicação que usa seu provedor se torna ativa ou depois de passar uma quantidade fixa de tempo. Ela transmite um objeto ComplicationManager como um parâmetro ao elemento onComplicationUpdate, que é usado para enviar dados ao sistema.

Observação: quando o app de provedor disponibiliza dados, o mostrador do relógio recebe os valores brutos enviados para mostrar as informações.

O snippet de código abaixo mostra um exemplo de implementação do método onComplicationUpdate:

Kotlin

override fun onComplicationUpdate(
    complicationId: Int, dataType: Int, complicationManager: ComplicationManager) {

    Log.d(TAG, "onComplicationUpdate() id: $complicationId")

    // Used to create a unique key to use with SharedPreferences for this complication.
    val thisProvider = ComponentName(this, javaClass)

    // Retrieves your data; in this case, grabs an incrementing number from SharedPrefs.
    val preferences = getSharedPreferences(ComplicationTapBroadcastReceiver.COMPLICATION_PROVIDER_PREFERENCES_FILE_KEY, 0)

    val number = preferences.getInt(
            ComplicationTapBroadcastReceiver.getPreferenceKey(
                    thisProvider, complicationId),
                    0)
    val numberText = String.format(Locale.getDefault(), "%d!", number)

    var complicationData: ComplicationData? = null

    when (dataType) {
        ComplicationData.TYPE_SHORT_TEXT -> complicationData = ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
                .setShortText(ComplicationText.plainText(numberText))
                .build()
        else -> if (Log.isLoggable(TAG, Log.WARN)) {
                    Log.w(TAG, "Unexpected complication type $dataType")
                }
    }

    if (complicationData != null) {
        complicationManager.updateComplicationData(complicationId, complicationData)
    } else {
        // If no data is sent, we still need to inform the ComplicationManager, so
        // the update job can finish and the wake lock isn't held any longer.
        complicationManager.noUpdateRequired(complicationId)
    }
}

Java

@Override
public void onComplicationUpdate(
       int complicationId, int dataType, ComplicationManager complicationManager) {

   Log.d(TAG, "onComplicationUpdate() id: " + complicationId);

   // Used to create a unique key to use with SharedPreferences for this complication.
   ComponentName thisProvider = new ComponentName(this, getClass());

   // Retrieves your data; in this case, grabs an incrementing number from SharedPrefs.
   SharedPreferences preferences =
     getSharedPreferences( ComplicationTapBroadcastReceiver.COMPLICATION_PROVIDER_PREFERENCES_FILE_KEY, 0);

   int number =
           preferences.getInt(
                   ComplicationTapBroadcastReceiver.getPreferenceKey(
                           thisProvider, complicationId),
                   0);
   String numberText = String.format(Locale.getDefault(), "%d!", number);

   ComplicationData complicationData = null;

   switch (dataType) {
       case ComplicationData.TYPE_SHORT_TEXT:
           complicationData =
                   new ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
                           .setShortText(ComplicationText.plainText(numberText))
                           .build();
           break;
       default:
           if (Log.isLoggable(TAG, Log.WARN)) {
               Log.w(TAG, "Unexpected complication type " + dataType);
           }
   }

   if (complicationData != null) {
       complicationManager.updateComplicationData(complicationId, complicationData);

   } else {
       // If no data is sent, we still need to inform the ComplicationManager, so
       // the update job can finish and the wake lock isn't held any longer.
       complicationManager.noUpdateRequired(complicationId);
   }
}

Declarações e permissões do manifesto

Um app de provedor de dados precisa incluir declarações específicas no manifesto para ser tratado como provedor de dados pelo sistema Android. Esta seção explica as configurações necessárias para um app de provedor de dados.

No manifesto do app, declare o serviço e adicione um filtro de intent da ação de solicitação de atualização. O manifesto também precisa proteger o serviço, adicionando a permissão BIND_COMPLICATION_PROVIDER para garantir que apenas o sistema Wear OS se vincule aos serviços do provedor.

Além disso, inclua um atributo android:icon no elemento service que forneça um ícone branco. Recomendamos drawables vetoriais para os ícones. O ícone representa o provedor e é mostrado no seletor de provedores.

Confira um exemplo:

<service
    android:name=".provider.IncrementingNumberComplicationProviderService"
    android:icon="@drawable/icn_complications"
    android:label="@string/complications_provider_incrementing_number"
    android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER">
    <intent-filter>
        <action
         android:name="android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST"/>
    </intent-filter>
</service>

Especificar os elementos de metadados

No arquivo de manifesto, inclua metadados para especificar os tipos com suporte, o período de atualização e a ação de configuração, conforme mostrado no exemplo a seguir:

<meta-data
    android:name="android.support.wearable.complications.SUPPORTED_TYPES"
    android:value="RANGED_VALUE,SHORT_TEXT,LONG_TEXT" />

<meta-data
    android:name="android.support.wearable.complications.UPDATE_PERIOD_SECONDS"
    android:value="300" />

Quando o provedor de dados de complicação está ativo, UPDATE_PERIOD_SECONDS especifica a frequência com que você quer que o sistema verifique se há atualizações para os dados. Caso não seja necessário atualizar as informações mostradas na complicação regularmente, como ao usar atualizações push, defina esse valor como 0.

Se você não definir UPDATE_PERIOD_SECONDS como 0, será necessário usar um valor de pelo menos 300 (cinco minutos), que é o período mínimo de atualização que o sistema impõe, para preservar a duração da bateria do dispositivo. Além disso, as solicitações de atualização ocorrem com menos frequência quando o dispositivo está no modo ambiente ou não está sendo usado.

Para mais detalhes sobre o envio de atualizações, consulte as chaves listadas para a classe ComplicationProviderService na Referência da API Wear OS.

Adicionar uma atividade de configuração

Se necessário, um provedor pode incluir uma atividade de configuração, que é mostrada quando o usuário seleciona um provedor de dados. Para incluir a atividade de configuração, inclua um item de metadados na declaração do serviço de provedor no manifesto com esta chave:

<meta-data
    android:name="android.support.wearable.complications.PROVIDER_CONFIG_ACTION"
    android:value="PROVIDER_CONFIG_ACTION"/>

O valor pode ser qualquer ação.

Em seguida, crie a atividade de configuração com um filtro de intent para essa ação. A atividade de configuração precisa ficar no mesmo pacote que o provedor. A atividade de configuração precisa retornar RESULT_OK ou RESULT_CANCELED para informar ao sistema se o provedor será definido.

Mostradores de relógio seguros especificados pelo provedor

Os provedores podem especificar alguns mostradores do relógio como "seguros" para receber dados. Essa função só é usada quando um mostrador de relógio tenta usar o provedor como padrão e o provedor confia no app do mostrador.

Para declarar que os mostradores de relógio são seguros, o provedor adiciona metadados com uma chave de android.support.wearable.complications.SAFE_WATCH_FACES. O valor dos metadados é uma lista separada por vírgulas de nomes de componentes WatchFaceService, fornecidos como se ComponentName.flattenToString() tivesse sido chamado, ou nomes de pacotes do app. Nesse caso todos os mostradores do relógio em um app especificado são considerados seguros. O espaço em branco na lista de valores é ignorado. Por exemplo:

<meta-data
       android:name="android.support.wearable.complications.SAFE_WATCH_FACES"
       android:value="
          com.app.watchface/com.app.watchface.MyWatchFaceService,
          com.anotherapp.anotherwatchface/com.something.WatchFaceService,
          com.something.text"/>

Usar imagens com proteção de pixels

Evite usar blocos sólidos de cor no modo ambiente em telas suscetíveis a burn-in. Se os ícones ou as imagens incluírem blocos sólidos de cor, forneça também uma versão com proteção contra burn-in.

Ao disponibilizar um ícone usando ComplicationData.Builder#setIcon, inclua uma versão com proteção contra burn-in, com ComplicationData.Builder#setBurnInProtectionIcon.

Ao fornecer uma imagem usando ComplicationData.Builder#setSmallImage, inclua uma versão com proteção contra burn-in, com ComplicationData.Builder#setBurnInProtectionSmallImage.

Usar atualizações push

Em vez de especificar um intervalo de atualizações diferente de zero para uma complicação no manifesto do app, é possível usar uma instância de ComplicationDataSourceUpdateRequester para solicitar atualizações de forma dinâmica. Para solicitar uma atualização do conteúdo visível ao usuário da complicação, chame requestUpdate().

Cuidado: para preservar a duração da bateria do dispositivo, não chame o método requestUpdate() da instância do ComplicationDataSourceUpdateRequester com frequência maior do que a cada cinco minutos, em média.

Fornecer valores dinâmicos

A partir do Wear OS 4, algumas complicações podem mostrar valores que são atualizados com mais frequência com base nos disponíveis diretamente para a plataforma. Para oferecer esse recurso nas complicações, use os campos ComplicationData que aceitam valores dinâmicos. A plataforma avalia e atualiza esses valores com frequência, sem exigir que o provedor de complicações esteja em execução.

Os campos de exemplo incluem o campo de valor dinâmico de GoalProgressComplicationData e DynamicComplicationText, que podem ser usados em qualquer campo ComplicationText. Esses valores dinâmicos são baseados na biblioteca androidx.wear.protolayout.expression.

Em determinadas situações, a plataforma não consegue avaliar valores dinâmicos:

Fornecer valores que dependem do horário

Algumas complicações precisam exibir um valor que é associado ao horário atual. Alguns exemplos são a data atual, o tempo restante até a próxima reunião ou a hora em um fuso horário diferente.

Não atualize uma complicação a cada segundo ou minuto. Em vez disso, especifique os valores como relativos à data ou ao horário, usando um texto dependente de horário. Use builders na classe ComplicationText para criar esses valores que dependem do horário.

Taxa de atualização de complicações

É possível atualizar as complicações com bastante frequência. No entanto, isso pode afetar a duração da bateria do dispositivo. Você pode usar uma API de solicitação de complicações privilegiada que permite que complicações específicas sejam atualizadas com mais frequência. No entanto, o uso dessa API precisa ser permitido pelo fabricante do smartwatch. Cada fabricante decide quais complicações podem ser atualizadas com uma frequência mais rápida do que o permitido normalmente.