Ferramentas de inspeção de código, como o lint, podem ajudar você a encontrar
problemas e melhorar o código, mas elas não fazem muito mais do que isso. 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 fornecer dicas para ferramentas de inspeção de código, como lint, para ajudar a detectar esses 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 oferece suporte a várias anotações usando a
Biblioteca Jetpack Annotations.
Acesse a biblioteca com o
pacote
androidx.annotation
.
Observação: se um módulo tem uma dependência em um processador de anotações,
você precisa usar a configuração kapt
ou ksp
para Kotlin
ou a configuração annotationProcessor
para Java para adicionar essa
dependência.
Adicionar anotações ao projeto
Para ativar as anotações no projeto, adicione a dependência androidx.annotation:annotation
à biblioteca ou ao app. Todas as anotações adicionadas serão verificadas quando você executar uma inspeção
de código ou uma tarefa lint
.
Adicionar a dependência da biblioteca Annotations do Jetpack
A biblioteca Annotations do Jetpack é publicada no
repositório Maven do Google.
Para adicionar a biblioteca Annotations Jetpack ao projeto, inclua a linha
a seguir no bloco dependencies
do arquivo build.gradle
ou
build.gradle.kts
:
Kotlin
dependencies { implementation("androidx.annotation:annotation:1.8.2") }
Groovy
dependencies { implementation 'androidx.annotation:annotation:1.8.2' }
Se você usa anotações no próprio módulo de biblioteca, elas são incluídas como parte do artefato do
Archive do Android (AAR) em formato XML no arquivo annotations.zip
. Adicionar a
dependência androidx.annotation
não introduz uma dependência para nenhum usuário abaixo no
fluxo da biblioteca.
Observação: se você estiver usando outras bibliotecas do Jetpack,
talvez não seja necessário adicionar a dependência androidx.annotation
. Como muitas outras
bibliotecas do Jetpack dependem da biblioteca Annotations, talvez você já tenha acesso às
anotações.
Para ver uma lista completa de anotações incluídas no repositório do Jetpack, consulte a
Referência da biblioteca Annotations
do Jetpack ou use o recurso de preenchimento automático para exibir as opções disponíveis na
instrução import androidx.annotation.
.
Realizar inspeções no código
Para iniciar uma inspeção de código no Android Studio, que inclui a validação de anotações e verificação automática do lint, selecione Analyze > Inspect Code no menu. O Android Studio exibe mensagens de conflito para sinalizar eventuais problemas em que o código entra em conflito com anotações e sugerir possíveis soluções.
Você também pode impor as anotações executando a
tarefa lint
pela linha de comando. Embora isso possa ser útil para sinalizar problemas
com um servidor de integração contínua, a tarefa lint
não impõe anotações
de nulidade (descritas na seção a seguir). 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 avisos, eles não impedem a compilação do app.
Anotações de nulidade
Anotações de nulidade podem ser úteis em código Java para determinar se os valores podem ser nulos. Elas são menos úteis no código Kotlin, porque ele tem regras de nulidade aplicadas no tempo de compilação.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, um parâmetro ou um valor de retorno que pode ser nulo.
@NonNull
indica uma variável, um parâmetro ou um valor de retorno que não pode ser nulo.
Por exemplo, se uma variável local contendo um valor nulo for transmitida como um parâmetro para um método
com a anotação @NonNull
vinculada a esse parâmetro, a criação do código vai gerar um
alerta que indica um conflito de não nulidade. Além disso, uma tentativa de referenciar o resultado de um
método marcado por @Nullable
sem primeiro verificar se o resultado é nulo gera
um aviso 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 demonstra a nulidade em ação. O código de exemplo em Kotlin não usa
a anotação @NonNull
porque ela é adicionada automaticamente ao bytecode gerado
quando um tipo não anulável é especificado. O exemplo em Java aproveita a anotação @NonNull
nos parâmetros context
e attrs
para verificar se os valores de parâmetro passados
não são nulos. Ele também
confere se o método onCreateView()
do Java não retorna um valor nulo:
Kotlin
... /** Annotation not used because of the safe-call operator(?)**/ override fun onCreateView( name: String?, context: Context, attrs: AttributeSet ): View? { ... } ...
Java
import androidx.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 oferece suporte à execução de uma análise de nulidade para determinar e inserir anotações de valores nulos automaticamente no código. Uma análise de nulidade verifica os contratos em todas as hierarquias de método no código para detectar:
- métodos de chamada que podem retornar nulo;
- métodos que não podem 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 conter valores nulos.
Em seguida, a análise insere automaticamente as anotações de nulidade adequadas nos locais detectados.
Para realizar uma análise de nulidade 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 conferir 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 verificação das
anotações, confira 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, como String
,
pode ser transmitido para o tipo de referência esperado de int
, mas referenciar outro
tipo de recurso, como um recurso R.string
.
Por exemplo, adicione anotações @StringRes
para
verificar se um parâmetro de recurso contém uma referência R.string
, conforme mostrado a seguir:
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 aviso quando uma referência R.string
não é transmitida no parâmetro.
Anotações para 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 do código.
Se o parâmetro
oferecer suporte a vários tipos de recursos, será possível colocar mais de uma anotação de tipo de recurso
em um determinado parâmetro. 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. Em vez disso, use a anotação @ColorInt
para
indicar que um parâmetro precisa ser um número inteiro de cor. As ferramentas de build sinalizarão códigos incorretos que
passarem aos métodos com anotações um ID de recurso de cor como android.R.color.black
, em vez de um
número inteiro de cor.
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. Veja as anotações de linha de execução que recebem suporte:
As ferramentas de build tratam as anotações @MainThread
e @UiThread
como intercambiáveis. Assim, você pode chamar métodos com @UiThread
de métodos com @MainThread
e vice-versa. No entanto, é possível que uma linha de execução de interface
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 de um app e a anotação
@MainThread
somente em métodos associados ao ciclo de vida de um 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 nela são chamados no mesmo tipo de linha de execução.
Anotações de linha de execução são usadas normalmente para validar se métodos ou classes anotados com
@WorkerThread
são chamados apenas de uma linha de execução adequada em segundo plano.
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
são mais úteis quando aplicadas a parâmetros em que os usuários têm mais chances de não entender o intervalo corretamente.
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 indica que o parâmetro alpha
precisa conter um valor 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 indica que o parâmetro
alpha
precisa conter 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 uma
matriz ou o comprimento 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 indica que a matriz
location
precisa conter 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 uma anotação no método
setWallpaper()
para indicar que o autor da chamada do método precisa ter 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 copyImageFile()
precisa ter acesso de leitura ao armazenamento externo e aos metadados de local
na imagem copiada:
Kotlin
@RequiresPermission(allOf = [ Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.ACCESS_MEDIA_LOCATION ]) fun copyImageFile(dest: String, source: String) { ... }
Java
@RequiresPermission(allOf = { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.ACCESS_MEDIA_LOCATION}) public static final void copyImageFile(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 que precisam de permissões separadas para acesso de leitura
e gravação, envolva 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 parâmetro, sem listar as permissões específicas.
Por exemplo, o método startActivity(Intent)
usa uma permissão indireta sobre a intent passada para o
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 build 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
startActivity(Intent)
, as anotações na classe Intent
geram os alertas resultantes
em usos inválidos de startActivity(Intent)
quando uma intent sem as permissões
apropriadas é transmitida para o método, como mostrado na Figura 1.
![](https://developer.android.google.cn/static/studio/images/write/indirect-permissions-warning_2-2_2x.png?authuser=0000&hl=pt)
Figura 1. O alerta gerado por uma anotação de
permissões indiretas no método startActivity(Intent)
.
As ferramentas de build geram o alerta em startActivity(Intent)
a partir da anotação
no nome da ação de intent correspondente na classe Intent
:
Kotlin
@RequiresPermission(Manifest.permission.CALL_PHONE) const val ACTION_CALL = "android.intent.action.CALL"
Java
@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
ou @RequiresPermission.Write
ao inserir uma anotação
em um parâmetro do método. No entanto, para permissões indiretas,
não é recomendável usar @RequiresPermission
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 é 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, novos desenvolvedores Java muitas vezes acreditam erroneamente que
<String>.trim()
remove espaços em branco da string original. Anotar
o método com @CheckResult
sinaliza o uso 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 uma anotação no método checkPermissions()
para verificar se o valor de retorno do método é
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
As anotações Typedef verificam se determinado parâmetro, valor de retorno ou campo se refere a um conjunto específico de constantes. Elas também permitem que o preenchimento de código ofereça as constantes permitidas automaticamente.
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ências de código.
As anotações Typedef usam @interface
para declarar o novo tipo de anotação enumerada.
As anotações @IntDef
e @StringDef
, junto à
@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 abaixo mostra as etapas para criar uma anotação que verifica se um valor transmitido como um parâmetro de método faz referência a uma das constantes definidas:
Kotlin
import androidx.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 androidx.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); }
Ao criar esse código, um aviso será gerado se o parâmetro mode
não
referenciar uma das constantes definidas (NAVIGATION_MODE_STANDARD
,
NAVIGATION_MODE_LIST
ou NAVIGATION_MODE_TABS
).
Combine @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 os usuários puderem combinar as constantes permitidas com uma sinalização (como |
,
&
, ^
etc.), você poderá definir uma anotação com o 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 androidx.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 androidx.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 {} ...
Ao criar código com uma sinalização de anotação, um aviso será gerado se o parâmetro ou valor de retorno decorado não referenciar um padrão válido.
Anotação Keep
A anotação @Keep
garante que uma classe ou um método com anotação não seja removido quando o código
for minimizado no momento da compilação.
Normalmente, essa anotação é adicionada
aos métodos e classes acessados por 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 mostrados no APK do app, mesmo que você nunca
os referencie dentro da lógica do app.
Para manter o app pequeno, considere se é necessário preservar cada
anotação @Keep
. Se você usar reflexão para acessar uma classe ou
um método com anotação, use um
-if
condicional nas regras do ProGuard, especificando a classe
que faz as chamadas de reflexão.
Para saber mais sobre como reduzir o código e especificar qual código não será removido, consulte Reduzir, ofuscar e otimizar o app.
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.
Deixar o código visível para testes
A anotação
@VisibleForTesting
indica que um método com anotação é mais visível que o necessário para tornar o método
testável. Essa anotação conta com o argumento otherwise
opcional, que permite designar
qual seria a visibilidade do método se não houvesse a necessidade de torná-lo visível para
teste. O lint usa o argumento otherwise
para aplicar a visibilidade pretendida.
No exemplo a seguir, myMethod()
normalmente é private
, mas é
package-private
para testes. Com a designação VisibleForTesting.PRIVATE
abaixo, o lint vai 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 existe um método somente para testes. Esse formato representa 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 somente a subclasses.
Apenas as classes que ampliem a classe com anotação poderão ter acesso à API. O modificador protected
do Java não é suficientemente restritivo porque permite o 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 nunca é possível transformar um método
protected
que foi substituído em um método public
, mas talvez você queira fornecer uma
dica de que a classe se destina para usos dentro da classe ou apenas de subclasses.
Bibliotecas
Use o formulário de anotação @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
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 não apenas organizar seu código
em qualquer hierarquia de pacotes que você quiser, mas também compartilhar
o código entre um grupo de bibliotecas relacionadas. Essa opção já está disponível para as bibliotecas
do Jetpack que têm muito código de implementação não destinado a uso externo, mas
que precisa ser public
para ser compartilhado entre as várias bibliotecas complementares do Jetpack.
Testes
Use o formulário de anotação @RestrictTo(RestrictTo.Scope.TESTS)
para impedir
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 para desenvolvimento as APIs criadas apenas para fins de teste.