Gerenciar atalhos

Depois de criar atalhos, pode ser necessário gerenciá-los durante o ciclo de vida do app. Por exemplo, você pode querer otimizar o app determinando a frequência com que os usuários realizam ações específicas com os atalhos. Em outros casos, você pode optar por desativar um atalho fixado para evitar que o app execute ações desatualizadas ou ausentes. Este guia descreve essas e outras formas comuns de gerenciar seus atalhos.

Comportamento de atalhos

As seções a seguir contêm informações gerais sobre o comportamento de atalhos, incluindo visibilidade, ordem de exibição e classificações.

Visibilidade de atalhos

Observação de segurança importante: todas as informações de atalho são salvas no armazenamento criptografado de credenciais. Portanto, o app não pode acessar os atalhos do usuário antes que o dispositivo seja desbloqueado.

Os atalhos estáticos e os atalhos dinâmicos aparecem em uma tela de início compatível quando o usuário realiza um gesto específico. Nas telas de início compatíveis atualmente, o gesto consiste em tocar no ícone do app na tela de início e mantê-lo pressionado, mas o gesto real pode ser diferente em outros apps na tela de início.

A classe LauncherApps fornece APIs para apps na tela de início para acessar atalhos.

Como os atalhos fixados aparecem na própria tela de início, eles estão sempre visíveis. Um atalho fixado só é removido da tela de início nas seguintes situações:

  • Removido pelo usuário.
  • O app associado ao atalho foi desinstalado.
  • Para limpar os dados do app, o usuário acessa Configurações > Apps e notificações, seleciona um app e pressiona Armazenamento > Limpar armazenamento.

Ordem de exibição de atalhos

Quando a tela de início exibe os atalhos de um app, eles aparecem na seguinte ordem:

  1. Atalhos estáticos: atalhos cujo método isDeclaredInManifest() retorna true.
  2. Atalhos dinâmicos: atalhos cujo método ShortcutInfo.isDynamic() retorna true.

Em cada tipo de atalho (estático e dinâmico), os atalhos são categorizados em ordem crescente de classificação, de acordo com ShortcutInfo.getRank().

As classificações são números inteiros sequenciais não negativos. Você pode atualizar as classificações dos atalhos existentes ao chamar updateShortcuts(List), addDynamicShortcuts(List) ou setDynamicShortcuts(List).

Observação: as classificações são ajustadas automaticamente para que sejam exclusivas para cada tipo de atalho (estático ou dinâmico). Por exemplo, caso haja três atalhos dinâmicos com classificações 0, 1 e 2, adicionar outro atalho dinâmico com classificação 1 representa uma solicitação para colocar esse atalho na segunda posição. Em resposta, o terceiro e o quarto atalho são movidos mais para o final da lista de atalhos e as classificações deles mudam para 2 e 3, respectivamente.

Gerenciar várias intents e atividades

Se você quiser que seu app execute várias operações quando o usuário ativar um atalho, é possível configurá-lo para acionar atividades sucessivas. Você pode fazer isso atribuindo várias intents, iniciando uma atividade a partir de outra ou definindo sinalizações de intent, dependendo do tipo de atalho.

Atribuir várias intents

Ao criar um atalho com ShortcutInfo.Builder, você pode usar setIntents() em vez de setIntent(). Ao chamar setIntents(), você pode iniciar várias atividades no app quando o usuário selecionar um atalho, colocando todas as atividades da lista, menos a última, na pilha de retorno. Se o usuário decidir pressionar o botão "Voltar" do dispositivo, ele verá outra atividade no app em vez de retornar à tela de início do dispositivo.

Observação: quando o usuário seleciona um atalho e, em seguida, pressiona o botão "Voltar", o app inicia a atividade correspondente à penúltima intent do atalho listado no arquivo de recursos do app. Esse padrão de comportamento continua quando o botão "Voltar" é pressionado repetidamente, até que o usuário limpe toda a pilha de retorno criada por um atalho. Quando o usuário pressionar o botão "Voltar" novamente, o sistema voltará à tela de início.

Iniciar uma atividade a partir de outra

Os atalhos estáticos não podem ter sinalizações de intent personalizadas. A primeira intent de um atalho estático sempre terá Intent.FLAG_ACTIVITY_NEW_TASK e Intent.FLAG_ACTIVITY_CLEAR_TASK definidos. Isso significa que, quando o app já estiver em execução, todas as atividades existentes nele serão destruídas quando um atalho estático for iniciado. Se esse não for o comportamento desejável, você pode usar uma atividade trampolim ou uma atividade invisível que inicia outra atividade no Activity.onCreate(Bundle) e chama Activity.finish() em seguida:

  1. No arquivo AndroidManifest.xml, a atividade trampolim precisa incluir a atribuição android:taskAffinity="" do atributo.
  2. No arquivo de recursos de atalhos, a intent no atalho estático precisa referenciar a atividade trampolim.

Para ver mais informações sobre as atividades trampolim, leia Iniciar uma atividade a partir de outra.

Definir sinalizações de intent

Os atalhos dinâmicos podem ser publicados com qualquer conjunto de sinalizações Intent. De preferência, você especificará Intent.FLAG_ACTIVITY_CLEAR_TASK com suas outras sinalizações. Caso contrário, se você tentar iniciar outra tarefa enquanto o app estiver em execução, a atividade de destino poderá não aparecer.

Para saber mais sobre tarefas e sinalizações de intent, leia o guia de tarefas e pilha de retorno.

Atualização de atalhos

O ícone na tela de início de cada app pode conter no máximo o número de getMaxShortcutCountPerActivity() de atalhos estáticos e dinâmicos combinados. No entanto, não há limite para o número de atalhos fixados que um app pode criar.

Quando um atalho dinâmico é fixado, mesmo se removido como atalho dinâmico pelo editor, o atalho fixado continua visível e pode ser iniciado. Isso permite que um app tenha mais do que o número de getMaxShortcutCountPerActivity() de atalhos.

Por exemplo, suponha que getMaxShortcutCountPerActivity() seja quatro:

  1. Um app de chat publica quatro atalhos dinâmicos que representam as quatro conversas mais recentes (c1, c2, c3, c4).
  2. O usuário fixa todos os quatro atalhos.
  3. Mais tarde, o usuário inicia outras três conversas (c5, c6 e c7) e, por isso, o app do editor republica os atalhos dinâmicos. A nova lista de atalhos dinâmicos será: c4, c5, c6, c7.

    O app precisa remover c1, c2 e c3, porque não é possível exibir mais de quatro atalhos dinâmicos. No entanto, c1, c2 e c3 ainda são atalhos fixados que o usuário pode acessar e iniciar.

    Agora, o usuário pode acessar um total de sete atalhos que vinculam a atividades no app do editor. Isso ocorre porque o total inclui o número máximo de atalhos e os três atalhos fixados.

  4. O app pode usar updateShortcuts(List) para atualizar qualquer um dos sete atalhos existentes. Por exemplo, você pode atualizar esse conjunto de atalhos quando os ícones de chat mudarem.
  5. Os métodos addDynamicShortcuts(List) e setDynamicShortcuts(List) também podem ser usados para atualizar atalhos existentes com os mesmos IDs. Contudo, eles não podem ser usados para atualizar atalhos fixados e não dinâmicos, porque esses dois métodos tentam converter a lista especificada de atalhos em atalhos dinâmicos.

Para saber mais sobre nossas diretrizes para atalhos de apps, incluindo atualização de atalhos, leia as Práticas recomendadas.

Processar as mudanças de localidade do sistema

Os apps atualizam os atalhos dinâmicos e fixados quando recebem a transmissão Intent.ACTION_LOCALE_CHANGED, indicando que a localidade do sistema mudou.

Rastrear o uso de atalhos

Para determinar as situações em que os atalhos estáticos e dinâmicos precisam aparecer, a tela de início examina o histórico de ativação dos atalhos. É possível monitorar quando os usuários realizam ações específicas no seu app chamando o método reportShortcutUsed() e passando para ele o ID do atalho quando qualquer um dos seguintes eventos ocorrer:

  • O usuário selecionar o atalho com o ID fornecido.
  • O usuário completar manualmente a ação correspondente ao mesmo atalho no app.

Desativar atalhos

Como o app e os usuários podem fixar atalhos na tela de início do dispositivo, é possível que esses atalhos fixados direcionem os usuários a ações no app que estejam desatualizadas ou não existam mais. Para gerenciar essa situação, é possível desativar os atalhos que você não quer que os usuários selecionem, chamando disableShortcuts(), que remove os atalhos especificados da lista de atalhos estáticos e dinâmicos e desativa todas as cópias fixadas desses atalhos. Você também pode usar uma versão sobrecarregada desse método, que aceita um CharSequence como uma mensagem de erro personalizada. Essa mensagem de erro será exibida quando os usuários tentarem iniciar um atalho desativado.

Observação: se você remover alguns dos atalhos estáticos ao atualizar o app, o sistema desativará esses atalhos automaticamente.

Limitação de taxa

Ao usar os métodos setDynamicShortcuts(), addDynamicShortcuts() ou updateShortcuts(), lembre-se de que talvez você só possa chamar esses métodos um número específico de vezes em um app em segundo plano, um app sem atividades ou serviços em primeiro plano no momento. O limite para o número específico de vezes que você pode chamar esses métodos é chamado de limitação de taxa. Esse recurso é usado para evitar que ShortcutManager consuma recursos do dispositivo em excesso.

Quando a limitação de taxa está ativada, isRateLimitingActive() retorna verdadeiro. No entanto, a limitação de taxa é redefinida durante determinados eventos, de modo que até mesmo apps em segundo plano podem chamar métodos ShortcutManager até que o limite seja atingido novamente. Esses eventos incluem o seguinte:

  • Um app aparece em primeiro plano.
  • A localidade do sistema muda.
  • O usuário executa a ação de resposta in-line em uma notificação.

Se você encontrar a limitação de taxa durante o desenvolvimento ou teste, selecione Opções do desenvolvedor > Redefinir limitação de taxa do ShortcutManager nas configurações do dispositivo ou insira o seguinte comando em adb:

$ adb shell cmd shortcut reset-throttling [ --user your-user-id ]

Backup e restauração

Você pode permitir que os usuários realizem operações de backup e restauração no app ao trocar de dispositivo incluindo a atribuição de atributo android:allowBackup="true" no arquivo de manifesto do app. Se você permitir o backup e a restauração, lembre-se dos pontos a seguir sobre os atalhos de apps:

  • Os atalhos estáticos são publicados novamente de forma automática, mas somente depois que o app é reinstalado pelo usuário em um novo dispositivo.
  • Os atalhos dinâmicos não são armazenados em backup. Por isso, é necessário incluir uma lógica no app para publicá-los novamente quando o usuário abrir o app em um novo dispositivo.
  • Os atalhos fixados são restaurados automaticamente na tela de início do dispositivo, mas o sistema não faz backup de ícones associados a atalhos fixados. Por isso, salve as imagens dos atalhos fixados no seu app, para que seja fácil restaurá-los em um novo dispositivo.

O snippet de código a seguir mostra qual é a melhor forma de restaurar os atalhos dinâmicos do app e como verificar se os atalhos fixados foram preservados:

Kotlin

class MyMainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val shortcutManager = getSystemService(ShortcutManager::class.java)

        if (shortcutManager!!.dynamicShortcuts.size == 0) {
            // Application restored. Need to re-publish dynamic shortcuts.
            if (shortcutManager.pinnedShortcuts.size > 0) {
                // Pinned shortcuts have been restored. Use
                // updateShortcuts() to make sure they contain
                // up-to-date information.
            }

        }
    }
    // ...
}

Java

public class MainActivity extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ShortcutManager shortcutManager =
                getSystemService(ShortcutManager.class);

        if (shortcutManager.getDynamicShortcuts().size() == 0) {
            // Application restored. Need to re-publish dynamic shortcuts.
            if (shortcutManager.getPinnedShortcuts().size() > 0) {
                // Pinned shortcuts have been restored. Use
                // updateShortcuts() to make sure they contain
                // up-to-date information.
            }
        }
    }
    // ...
}

Outros recursos

A amostra AppShortcuts do Android demonstra melhor o uso dos fluxos de trabalho abordados nesta página (link em inglês).