Melhorar a inspeção de código com anotações

O uso de ferramentas de inspeção de código, como o lint, pode ajudar a encontrar problemas e melhorar o código, mas elas não passam disso. Os IDs de recurso do Android, por exemplo, usam um int para identificar strings, gráficos, cores e outros tipos de recurso. Nesse caso, as ferramentas de inspeção não conseguem determinar quando você especificou um recurso de string onde precisaria ter especificado uma cor. Essa situação significa que o app poderá renderizar de forma incorreta ou apresentar falha geral na execução, mesmo se você usar a inspeção de código.

As anotações permitem disponibilizar dicas para ferramentas de inspeção de código, como o lint, ajudando a detectar os problemas de código mais sutis. Elas são adicionadas na forma de tags de metadados, anexadas a variáveis e parâmetros, e retornam valores para inspecionar os valores de retorno dos métodos, parâmetros passados, campos e variáveis locais. Quando usadas com ferramentas de inspeção de código, as anotações podem ajudar a detectar problemas, como exceções de ponteiro nulo e conflitos de tipo de recurso.

O Android é compatível com várias anotações por meio da Annotations Support Library. Acesse a biblioteca por meio do pacote android.support.annotation.

Observação: se um módulo tem uma dependência em um processador de anotações, você precisa usar a configuração de dependências "annotationProcessor" para adicioná-la. Para saber mais, leia Usar a configuração de dependências do processador de anotações.

Adicionar anotações ao projeto

Para permitir anotações no seu projeto, adicione a dependência support-annotations à biblioteca ou ao app. Toda anotação adicionada é verificada quando se realiza uma inspeção no código ou a tarefa lint.

Adicionar dependência da Annotations Support Library

A Annotations Support Library é publicada no repositório Maven do Google. Para adicionar a Annotations Support Library ao projeto, inclua a seguinte linha no bloco dependencies do arquivo build.gradle:

    dependencies {
        implementation 'com.android.support:support-annotations:28.0.0'
    }
    
Depois, na barra de tarefas ou na notificação de sincronização exibida, clique em Sync Now.

Se você usa anotações no próprio módulo de biblioteca, elas são incluídas como parte do artefato ARchive do Android (AAR) em formato XML no arquivo annotations.zip. A adição da dependência support-annotations não introduz uma dependência para nenhum usuário abaixo no fluxo da biblioteca.

Observação: se você usa a biblioteca appcompat, não precisa adicionar a dependência support-annotations. Como a biblioteca appcompat já depende da biblioteca de anotações, você tem acesso às anotações.

Para ver uma lista completa das anotações incluídas no repositório de suporte, leia o guia de referência da Annotations Support Library ou use o recurso de preenchimento automático para exibir as opções disponíveis para a declaração import android.support.annotation..

Realizar inspeções no código

Para iniciar uma inspeção de código no Android Studio, que contém anotações de validação e verificação automática do lint, selecione Analyze > Inspect Code na barra de menu. O Android Studio exibe mensagens de conflito para indicar eventuais problemas em que o código está conflitante com anotações e sugerir soluções.

Você também pode aplicar as anotações executando a tarefa lint por meio da linha de comando. Embora isso possa ser útil para identificar problemas junto a um servidor de integração contínua, a tarefa lint não aplica anotações de nulidade (somente o Android Studio faz isso). Para saber mais sobre como ativar e executar inspeções do lint, acesse Melhorar seu código com Lint.

Embora os conflitos de anotação gerem alertas, esses avisos não impedem a compilação do app.

Anotações de nulidade

Adicione as anotações @Nullable e @NonNull para verificar a nulidade de uma determinada variável, parâmetro ou valor de retorno. A anotação @Nullable indica uma variável, parâmetro ou valor de retorno que pode ser nulo, enquanto @NonNull indica uma variável, parâmetro ou valor de retorno que não pode ser nulo.

Por exemplo, se uma variável local que contém um valor nulo é passada como um parâmetro a um método que tem a anotação @NonNull vinculada a ele, a compilação do código gera um alerta, indicando um conflito de não nulidade. Por outro lado, a tentativa de referenciar o resultado de um método marcado com @Nullable sem antes verificar se o resultado é nulo gera um alerta de nulidade. Use @Nullable no valor de retorno de um método apenas se todo uso do método precisar ser explicitamente verificado quanto à nulidade.

O exemplo a seguir vincula a anotação @NonNull aos parâmetros context e attrs para verificar se os valores de parâmetro passados não são nulos. Ela também verifica se o próprio método onCreateView() retorna nulo. Com o Kotlin, não é necessário usar a anotação @NonNull porque ela será adicionada automaticamente ao bytecode gerado quando um tipo não anulável for especificado:

Kotlin

    import android.support.annotation.NonNull
    ...

        /** Add support for inflating the <fragment> tag. **/
        fun onCreateView(
                name: String?,
                context: Context,
                attrs: AttributeSet
        ): View? {
            ...
        }
    ...
    

Java

    import android.support.annotation.NonNull;
    ...

        /** Add support for inflating the <fragment> tag. **/
        @NonNull
        @Override
        public View onCreateView(String name, @NonNull Context context,
          @NonNull AttributeSet attrs) {
          ...
          }
    ...
    

Análise de valores nulos

O Android Studio é compatível com a execução de uma análise de valores nulos para determinar e inserir anotações de valores nulos automaticamente no código. Uma análise de valores nulos verifica os contratos em todas as hierarquias de método no código para detectar:

  • Métodos chamadores que podem retornar nulo
  • Métodos que não devem retornar nulo
  • Variáveis, como campos, variáveis locais e parâmetros, que podem ser nulos
  • Variáveis, como campos, variáveis locais e parâmetros, que não podem ter valor nulo

Em seguida, a análise insere automaticamente as anotações de nulo apropriadas nos locais detectados.

Para realizar uma análise de valores nulos no Android Studio, selecione Analyze > Infer Nullity. O Android Studio insere as anotações @Nullable e @NonNull do Android nos locais detectados no código. Depois de executar uma análise de valores nulos, é recomendado verificar as anotações inseridas.

Observação: ao adicionar anotações de nulidade, o recurso de preenchimento automático pode sugerir as anotações @Nullable e @NotNull do IntelliJ em vez das anotações de nulidade do Android. Esse recurso também pode importar de forma automática a biblioteca correspondente. No entanto, o verificador lint do Android Studio só busca anotações de nulidade do Android. Durante a revisão das suas anotações, verifique se o projeto está usando as anotações de nulidade do Android para que o verificador do lint possa emitir notificações corretas ao longo da inspeção de código.

Anotações de recurso

A validação de tipos de recurso pode ser útil porque as referências do Android a recursos, como drawables e strings, são passadas na forma de números inteiros. O código que espera que um parâmetro referencie um tipo específico de recurso, por exemplo, Drawables, pode ser passado no tipo de referência esperado de int, mas referenciar, na verdade, outro tipo de recurso, como R.string.

Por exemplo, adicione anotações @StringRes para verificar se um parâmetro de recurso contém uma referência a R.string, conforme mostrado abaixo:

Kotlin

    abstract fun setTitle(@StringRes resId: Int)
    

Java

    public abstract void setTitle(@StringRes int resId)
    

Durante a inspeção de código, a anotação gera um alerta se uma referência a R.string não é passada no parâmetro.

Anotações para os outros tipos de recursos, como @DrawableRes, @DimenRes, @ColorRes e @InterpolatorRes podem ser adicionadas usando o mesmo formato de anotação e executadas durante a inspeção de código. Se o parâmetro for compatível com diversos tipos de recurso, será possível colocar mais de uma dessas anotações nele. Use @AnyRes para indicar que o parâmetro com a anotação pode ser de qualquer tipo de recurso R.

Embora você possa usar @ColorRes para especificar que um parâmetro precisa ser um recurso de cor, um número inteiro de cor (no formato RRGGBB ou AARRGGBB) não é reconhecido como um recurso de cor. Use a anotação @ColorInt para indicar que um parâmetro precisa ser um número inteiro de cor. As ferramentas de compilação sinalizarão o código incorreto que passar um ID de recurso de cor como android.R.color.black, em vez de como um número inteiro de cor, aos métodos com anotações.

Anotações de linha de execução

As anotações de linha de execução verificam se um método é chamado em um tipo específico de linha de execução. As anotações de linha de execução a seguir são compatíveis:

Observação: as ferramentas de compilação tratam as anotações @MainThread e @UiThread como intercambiáveis. Assim, você pode chamar métodos @UiThread de métodos @MainThread e vice-versa. No entanto, é possível que uma linha de execução da IU seja diferente da linha de execução principal no caso de apps do sistema terem diversas visualizações em diferentes linhas de execução. Portanto, você precisa inserir a anotação @UiThread em métodos associados à hierarquia de visualizações do app e a anotação @MainThread somente em métodos associados ao ciclo de vida do app.

Se todos os métodos de uma classe compartilharem a mesma exigência de linha de execução, você poderá adicionar uma única anotação de linha de execução à classe para verificar se todos os métodos nessa classe são chamados no mesmo tipo de linha de execução.

Um uso comum da anotação de linha de execução é para validar neutralizações de método na classe AsyncTask, uma vez que essa classe realiza operações em segundo plano e publica os resultados somente na linha de execução da IU.

Anotações de limitação de valor

Use as anotações @IntRange, @FloatRange e @Size para validar os valores dos parâmetros passados. Tanto @IntRange quanto @FloatRange funcionam melhor se aplicadas aos parâmetros dos quais o usuário tem mais chances de usar o intervalo incorretamente.

A anotação @IntRange confirma que um valor de número inteiro ou longo de parâmetro está dentro de um intervalo especificado. O exemplo a seguir garante que o parâmetro alpha contenha um valor de número inteiro de 0 a 255:

Kotlin

    fun setAlpha(@IntRange(from = 0, to = 255) alpha: Int) { ... }
    

Java

    public void setAlpha(@IntRange(from=0,to=255) int alpha) { ... }
    

A anotação @FloatRange verifica se um valor de parâmetro flutuante ou duplo está dentro de um intervalo específico de valores de ponto flutuante. O exemplo a seguir garante que o parâmetro alpha contenha um valor flutuante de 0,0 a 1,0:

Kotlin

    fun setAlpha(@FloatRange(from = 0.0, to = 1.0) alpha: Float) {...}
    

Java

    public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {...}
    

A anotação @Size verifica o tamanho de um conjunto ou de uma matriz, além do tamanho de uma string. A anotação @Size pode ser usada para verificar as seguintes qualidades:

  • Tamanho mínimo (como @Size(min=2))
  • Tamanho máximo (como @Size(max=2))
  • Tamanho exato (como @Size(2))
  • Um número de que o tamanho precisa ser múltiplo (como @Size(multiple=2))

Por exemplo, @Size(min=1) verifica se um conjunto está vazio, e @Size(3) confirma se uma matriz contém exatamente três valores. O exemplo a seguir garante que a matriz location contenha pelo menos um elemento:

Kotlin

    fun getLocation(button: View, @Size(min=1) location: IntArray) {
        button.getLocationOnScreen(location)
    }
    

Java

    void getLocation(View button, @Size(min=1) int[] location) {
        button.getLocationOnScreen(location);
    }
    

Anotações de permissão

Use a anotação @RequiresPermission para validar as permissões do autor da chamada de um método. Para verificar a presença de uma única permissão de uma lista de permissões válidas, use o atributo anyOf. Para verificar a presença de um conjunto de permissões, use o atributo allOf. O exemplo a seguir insere anotação no método setWallpaper() para garantir que o autor da chamada do método tenha a permissão permission.SET_WALLPAPERS:

Kotlin

    @RequiresPermission(Manifest.permission.SET_WALLPAPER)
    @Throws(IOException::class)
    abstract fun setWallpaper(bitmap: Bitmap)
    

Java

    @RequiresPermission(Manifest.permission.SET_WALLPAPER)
    public abstract void setWallpaper(Bitmap bitmap) throws IOException;
    

Nesse exemplo, o autor da chamada do método copyFile() é obrigado a ter permissões de leitura e gravação no armazenamento externo:

Kotlin

    @RequiresPermission(allOf = [
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
    ])
    fun copyFile(dest: String, source: String) {
        ...
    }

Java

    @RequiresPermission(allOf = {
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE})
    public static final void copyFile(String dest, String source) {
        //...
    }
    

Para permissões de intents, coloque o requisito de permissão no campo "string" que define o nome da ação da intent:

Kotlin

    @RequiresPermission(android.Manifest.permission.BLUETOOTH)
    const val ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE"
    

Java

    @RequiresPermission(android.Manifest.permission.BLUETOOTH)
    public static final String ACTION_REQUEST_DISCOVERABLE =
                "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
    

Para permissões de provedores de conteúdo nos casos em que é preciso separar permissões de acesso de leitura das de gravação, encapsule cada requisito de permissão em uma anotação @RequiresPermission.Read ou @RequiresPermission.Write :

Kotlin

    @RequiresPermission.Read(RequiresPermission(READ_HISTORY_BOOKMARKS))
    @RequiresPermission.Write(RequiresPermission(WRITE_HISTORY_BOOKMARKS))
    val BOOKMARKS_URI = Uri.parse("content://browser/bookmarks")
    

Java

    @RequiresPermission.Read(@RequiresPermission(READ_HISTORY_BOOKMARKS))
    @RequiresPermission.Write(@RequiresPermission(WRITE_HISTORY_BOOKMARKS))
    public static final Uri BOOKMARKS_URI = Uri.parse("content://browser/bookmarks");
    

Permissões indiretas

Quando uma permissão depende do valor específico atribuído a um parâmetro do método, use @RequiresPermission no próprio parâmetro, sem listar as permissões específicas. Por exemplo, o método startActivity(Intent) usa uma permissão indireta na intent passada ao método:

Kotlin

    abstract fun startActivity(@RequiresPermission intent: Intent, bundle: Bundle?)
    

Java

    public abstract void startActivity(@RequiresPermission Intent intent, @Nullable Bundle)
    

Quando você usa permissões indiretas, as ferramentas de compilação realizam uma análise do fluxo de dados para verificar se o argumento passado no método tem alguma anotação @RequiresPermission. Em seguida, elas aplicam todas as anotações existentes do parâmetro ao próprio método. No exemplo do startActivity(Intent), as anotações da classe Intent geram os alertas resultantes em usos inválidos do startActivity(Intent) quando uma intent sem as permissões necessárias é passada ao método, conforme exibido na figura 1.

Figura 1. O alerta gerado por uma anotação de permissões indiretas no método startActivity(Intent).

As ferramentas de compilação geram o alerta em startActivity(Intent) a partir da anotação no nome da ação da intent correspondente da classe Intent:

Kotlin

    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    @RequiresPermission(Manifest.permission.CALL_PHONE)
    const val ACTION_CALL = "android.intent.action.CALL"
    

Java

    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    @RequiresPermission(Manifest.permission.CALL_PHONE)
    public static final String ACTION_CALL = "android.intent.action.CALL";
    

Se necessário, é possível trocar @RequiresPermission por @RequiresPermission.Read e/ou @RequiresPermission.Write ao inserir anotação em um parâmetro do método. No entanto, para permissões indiretas, @RequiresPermission não deve ser usada com nenhuma anotação de permissão de leitura ou gravação.

Anotações de valor de retorno

Use a anotação @CheckResult para confirmar que o resultado ou valor de retorno de um método seja efetivamente usado. Em vez de inserir a anotação @CheckResult em todo método não nulo, adicione a anotação para esclarecer os resultados de métodos possivelmente confusos. Por exemplo, muitas vezes, novos desenvolvedores do Java acham, por engano, que <String>.trim() remove espaços em branco da string original. O uso da anotação @CheckResult no método sinaliza usos de <String>.trim() em que o autor da chamada não faz nada com o valor de retorno do método.

O exemplo a seguir insere anotação no método checkPermissions() para garantir que o valor de retorno do método seja realmente referenciado. Nele, o método enforcePermission() também é indicado como uma opção a ser sugerida ao desenvolvedor como substituto:

Kotlin

    @CheckResult(suggest = "#enforcePermission(String,int,int,String)")
    abstract fun checkPermission(permission: String, pid: Int, uid: Int): Int
    

Java

    @CheckResult(suggest="#enforcePermission(String,int,int,String)")
    public abstract int checkPermission(@NonNull String permission, int pid, int uid);
    

Anotações CallSuper

Use a anotação @CallSuper para confirmar que um método substituto chame a superimplementação do método. O exemplo a seguir insere uma anotação no método onCreate() para garantir que todas as implementações de método substituto chamem super.onCreate():

Kotlin

    @CallSuper
    override fun onCreate(savedInstanceState: Bundle?) {
    }
    

Java

    @CallSuper
    protected void onCreate(Bundle savedInstanceState) {
    }
    

Anotações Typedef

Use as anotações @IntDef e @StringDef para criar anotações enumeradas de conjuntos de números inteiros e strings para validar outros tipos de referência de código. As anotações Typedef garantem que determinado parâmetro, valor de retorno ou campo referencie um conjunto específico de constantes. Elas também permitem que o preenchimento de código ofereça as constantes permitidas automaticamente.

As anotações Typedef usam @interface para declarar o novo tipo de anotação enumerada. As anotações @IntDef e @StringDef, juntamente com a @Retention, inserem a nova anotação e são necessárias para definir o tipo enumerado. A anotação @Retention(RetentionPolicy.SOURCE) instrui o compilador a não armazenar os dados da anotação enumerada no arquivo .class.

O exemplo a seguir ilustra as etapas para criar uma anotação que garanta que um valor passado como um parâmetro de método referencie uma das constantes definidas:

Kotlin

    import android.support.annotation.IntDef
    //...
    // Define the list of accepted constants and declare the NavigationMode annotation
    @Retention(AnnotationRetention.SOURCE)
    @IntDef(NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS)
    annotation class NavigationMode

    // Declare the constants
    const val NAVIGATION_MODE_STANDARD = 0
    const val NAVIGATION_MODE_LIST = 1
    const val NAVIGATION_MODE_TABS = 2

    abstract class ActionBar {

        // Decorate the target methods with the annotation
        // Attach the annotation
        @get:NavigationMode
        @setparam:NavigationMode
        abstract var navigationMode: Int

    }
    

Java

    import android.support.annotation.IntDef;
    //...
    public abstract class ActionBar {
        //...
        // Define the list of accepted constants and declare the NavigationMode annotation
        @Retention(RetentionPolicy.SOURCE)
        @IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
        public @interface NavigationMode {}

        // Declare the constants
        public static final int NAVIGATION_MODE_STANDARD = 0;
        public static final int NAVIGATION_MODE_LIST = 1;
        public static final int NAVIGATION_MODE_TABS = 2;

        // Decorate the target methods with the annotation
        @NavigationMode
        public abstract int getNavigationMode();

        // Attach the annotation
        public abstract void setNavigationMode(@NavigationMode int mode);
    }
    

Se o parâmetro mode não referenciar uma das constantes definidas (NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST ou NAVIGATION_MODE_TABS) na compilação desse código, um alerta será gerado.

Você também pode combinar @IntDef e @IntRange para indicar que um número inteiro pode ser um conjunto específico de constantes ou um valor dentro de um intervalo.

Ativar combinação de constantes com sinalizadores

Se o usuário puder combinar as constantes permitidas com um sinalizador (como |, &, ^, entre outros), você poderá definir uma anotação com um atributo flag para verificar se um parâmetro ou valor de retorno referencia um padrão válido. O exemplo a seguir cria a anotação DisplayOptions com uma lista de constantes DISPLAY_ válidas:

Kotlin

    import android.support.annotation.IntDef
    ...

    @IntDef(flag = true, value = [
        DISPLAY_USE_LOGO,
        DISPLAY_SHOW_HOME,
        DISPLAY_HOME_AS_UP,
        DISPLAY_SHOW_TITLE,
        DISPLAY_SHOW_CUSTOM
    ])
    @Retention(AnnotationRetention.SOURCE)
    annotation class DisplayOptions
    ...
    

Java

    import android.support.annotation.IntDef;
    ...

    @IntDef(flag=true, value={
            DISPLAY_USE_LOGO,
            DISPLAY_SHOW_HOME,
            DISPLAY_HOME_AS_UP,
            DISPLAY_SHOW_TITLE,
            DISPLAY_SHOW_CUSTOM
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface DisplayOptions {}

    ...
    

Se o parâmetro ou o valor de retorno decorado não referenciar um padrão válido durante a compilação do código com um sinalizador de anotação, um alerta será gerado.

Anotação Keep

A anotação @Keep garante que uma classe ou um método com anotação não sejam removidos quando o código é minificado durante a compilação. Normalmente, essa anotação é adicionada aos métodos e classes acessados por meio de reflexão para evitar que o compilador trate o código como não usado.

Cuidado: as classes e os métodos em que você insere anotações usando @Keep são sempre exibidos no APK do app, mesmo que você nunca os referencie dentro da lógica do app.

Para manter o tamanho do seu app pequeno, analise a necessidade de preservar todas as anotações @Keep. Se você usar a reflexão para acessar uma classe ou um método com anotação, use uma condicional -if nas regras do ProGuard, especificando a classe que faz as chamadas de reflexão.

Para ver mais informações sobre como minificar seu código e especificar códigos que não devem ser removidos, consulte Reduzir código e recursos.

Anotações de visibilidade de código

Use as seguintes anotações para denotar a visibilidade de partes específicas de código, como métodos, classes, campos ou pacotes.

Tornar visível para testes

A anotação @VisibleForTesting indica que um método com anotação é mais visível que o normalmente necessário para tornar o método passível de teste. Essa anotação conta com o argumento opcional otherwise, que permite designar qual seria a visibilidade do método se não houvesse a necessidade de torná-lo visível para o teste. O lint usa o argumento otherwise para aplicar a visibilidade pretendida.

No exemplo a seguir, myMethod() é normalmente private, mas é um pacote privado para testes. Com a designação VisibleForTesting.PRIVATE a seguir, o lint mostrará uma mensagem se esse método for chamado de fora do contexto permitido pelo acesso private, como de uma unidade de compilação diferente.

Kotlin

    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
    fun myMethod() {
        ...
    }
    

Java

    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
    void myMethod() { ... }
    

Você também pode especificar @VisibleForTesting(otherwise = VisibleForTesting.NONE) para indicar que um método existe apenas para testes. Esse formulário é o mesmo que usar @RestrictTo(TESTS). Ambos executam a mesma verificação no lint.

Restringir uma API

A anotação @RestrictTo indica que o acesso à API com anotação (pacote, classe ou método) é limitado da seguinte forma:

Subclasses

Use o formulário de anotação @RestrictTo(RestrictTo.Scope.SUBCLASSES) para restringir o acesso da API apenas a subclasses.

Apenas as classes que expandam a classe com anotação poderão ter acesso à API. O modificador protected do Java não é restritivo o suficiente, porque permite acesso de classes não relacionadas dentro do mesmo pacote. Além disso, há casos em que você quer deixar um método public para flexibilidade futura, porque você nunca pode tornar um método anteriormente protected e modificado public, mas você pode indicar que a classe é destinada apenas para usos dentro da classe ou a partir de subclasses.

Bibliotecas

Use o formulário de anotação @RestrictTo(RestrictTo.Scope.GROUP_ID) para restringir o acesso da API apenas às suas bibliotecas.

Apenas o código da sua biblioteca pode acessar a API com anotação. Isso permite que você não apenas organize seu código em qualquer hierarquia de pacotes, mas também compartilhe o código entre um grupo de bibliotecas relacionadas. Essa opção já está disponível para as bibliotecas de suporte que têm muito código de implementação não destinado para uso externo, mas que precisa ser public para ser compartilhado em várias bibliotecas de suporte complementares.

Observação: as classes e os pacotes da Android Support Library agora têm a anotação @RestrictTo(GROUP_ID). Isso significa que, se você usar acidentalmente essas classes de implementação, o lint alertará que essa ação não é recomendada.

Teste

Use o formulário de anotação @RestrictTo(RestrictTo.Scope.TESTS) para evitar que outros desenvolvedores acessem suas APIs de teste.

Apenas o código de teste pode acessar a API com anotação. Isso evita que outros desenvolvedores usem em atividades de desenvolvimento as APIs criadas apenas para fins de teste.