Esta página mostra como configurar seu ambiente e criar Slices no seu app.
Observação: o Android Studio 3.2 e versões mais recentes têm outras ferramentas e recursos que podem ajudar no desenvolvimento de Slice:
- Ferramenta de refatoramento do AndroidX: necessária para trabalhar em um projeto que usa bibliotecas do AndroidX.
- Verificações lint para Slices: detecta práticas não recomendadas comuns na criação de Slices.
- Modelo
SliceProvider
: processa códigos de texto clichê na criação de umSliceProvider
.
Download e instalação do Slice Viewer
Faça o download da versão mais recente da amostra do
APK do Slice Viewer (em inglês),
que pode ser usada para testar seus Slices sem implementar
a API SliceView
.
Se o adb não estiver configurado corretamente no seu ambiente, consulte o Guia do ADB para saber mais.
Instale o Slice Viewer no dispositivo executando o seguinte comando no
mesmo diretório em que o slice-viewer.apk
foi salvo:
adb install -r -t slice-viewer.apk
Executar o Slice Viewer
Você pode abrir o Slice Viewer no projeto do Android Studio ou na linha de comando:
Abrir o Slice Viewer no projeto do Android Studio
- No projeto, selecione Run > Edit Configurations....
- No canto superior esquerdo, clique no sinal de adição verde.
Selecione Android App.
Digite o nome slice no campo "Name".
Selecione o módulo do app no menu suspenso Module.
Em Launch Options, selecione URL no menu suspenso Launch.
Digite
slice-<your slice URI>
no campo "URL".Exemplo:
slice-content://com.example.your.sliceuri
Clique em OK.
Abrir a ferramenta Slice Viewer pelo ADB (linha de comando)
Execute o app no Android Studio:
adb install -t -r <yourapp>.apk
Para visualizar seu Slice, execute este comando:
adb shell am start -a android.intent.action.VIEW -d slice-<your slice URI>
Slice Viewer mostrando um único Slice de Wi-Fi
Ver todos os Slices em um só lugar
Além de iniciar um único Slice, é possível ver uma lista persistente dos seus Slices.
- Use a barra de pesquisa para pesquisar manualmente seus Slices por meio do URI (por exemplo,
content://com.example.android.app/hello
). Sempre que você fizer isso, o Slice será adicionado à lista. - Todas as vezes que você iniciar a ferramenta Slice Viewer com um URI de Slice, o Slice será adicionado à lista.
- Você pode deslizar um Slice para removê-lo da lista.
- Toque no URI do Slice para ver uma página que contém apenas esse Slice. Essa ação tem o mesmo efeito que abrir o Slice Viewer com um URI de Slice.
Slice Viewer mostrando uma lista de Slices
Visualizar o Slice em modos diferentes
Um app que apresenta um Slice pode modificar o
SliceView#mode
durante a execução. Portanto, verifique se o Slice é exibido conforme o esperado em cada modo.
Selecione o ícone de menu no canto superior direito da página para mudar o modo.
Slice Viewer individual com modo definido como "pequeno"
Criar seu primeiro Slice
Para criar um Slice, abra o projeto do Android Studio, clique com o botão direito no pacote src
e selecione New… > Other > Slice Provider. Essa opção cria uma classe
que estende o SliceProvider
, adiciona
a entrada de provedor necessária ao AndroidManifest.xml
e modifica o
build.gradle
para adicionar as dependências de Slice necessárias.
A modificação para AndroidManifest.xml
é mostrada abaixo:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.app"> ... <application> ... <provider android:name="MySliceProvider" android:authorities="com.example.android.app" android:exported="true" > <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.app.slice.category.SLICE" /> </intent-filter> </provider> ... </application> </manifest>
As seguintes dependências são adicionadas ao build.gradle
:
Kotlin
dependencies { // ... implementation "androidx.slice:slice-builders-ktx:(latest version)" // ... }
Java
dependencies { // ... implementation "androidx.slice:slice-builders:(latest version)" // ... }
Cada Slice tem um URI associado. Quando uma superfície quer exibir um Slice, ela
envia uma solicitação de vinculação ao app com esse URI. Em seguida, o app processa
a solicitação e cria dinamicamente o Slice por meio do
método onBindSlice
. Então, a superfície poderá exibir o Slice sempre que apropriado.
Veja abaixo o exemplo de um método onBindSlice
que verifica o caminho do URI /hello
e retorna um Slice Hello World:
Kotlin
override fun onBindSlice(sliceUri: Uri): Slice? { val activityAction = createActivityAction() return if (sliceUri.path == "/hello") { list(context, sliceUri, ListBuilder.INFINITY) { row { primaryAction = activityAction title = "Hello World." } } } else { list(context, sliceUri, ListBuilder.INFINITY) { row { primaryAction = activityAction title = "URI not recognized." } } } }
Java
@Override public Slice onBindSlice(Uri sliceUri) { if (getContext() == null) { return null; } SliceAction activityAction = createActivityAction(); ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY); // Create parent ListBuilder. if ("/hello".equals(sliceUri.getPath())) { listBuilder.addRow(new ListBuilder.RowBuilder() .setTitle("Hello World") .setPrimaryAction(activityAction) ); } else { listBuilder.addRow(new ListBuilder.RowBuilder() .setTitle("URI not recognized") .setPrimaryAction(activityAction) ); } return listBuilder.build(); }
Use a configuração de execução slice criada na seção "Slice Viewer"
acima. Para isso, transmita o URI de Slice (por exemplo,
slice-content://com.android.example.slicesample/hello
) do Slice Hello World
para vê-lo no Slice Viewer.
Slices interativos
Assim como acontece com as notificações, você pode processar cliques no seu Slice anexando
objetos PendingIntent
que são
acionados por meio da interação do usuário. O exemplo abaixo inicia um
Activity
que pode receber e processar esses
intents:
Kotlin
fun createSlice(sliceUri: Uri): Slice { val activityAction = createActivityAction() return list(context, sliceUri, INFINITY) { row { title = "Perform action in app" primaryAction = activityAction } } } fun createActivityAction(): SliceAction { val intent = Intent(context, MainActivity::class.java) return SliceAction.create( PendingIntent.getActivity(context, 0, Intent(context, MainActivity::class.java), 0), IconCompat.createWithResource(context, R.drawable.ic_home), ListBuilder.ICON_IMAGE, "Enter app" ) }
Java
public Slice createSlice(Uri sliceUri) { if (getContext() == null) { return null; } SliceAction activityAction = createActivityAction(); return new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY) .addRow(new ListBuilder.RowBuilder() .setTitle("Perform action in app.") .setPrimaryAction(activityAction) ).build(); } public SliceAction createActivityAction() { if (getContext() == null) { return null; } return SliceAction.create( PendingIntent.getActivity( getContext(), 0, new Intent(getContext(), MainActivity.class), 0 ), IconCompat.createWithResource(getContext(), R.drawable.ic_home), ListBuilder.ICON_IMAGE, "Enter app" ); }
Os Slices também são compatíveis com outros tipos de entrada, como botões de alternância, que incluem o estado na intent enviada ao app.
Kotlin
fun createBrightnessSlice(sliceUri: Uri): Slice { val toggleAction = SliceAction.createToggle( createToggleIntent(), "Toggle adaptive brightness", true ) return list(context, sliceUri, ListBuilder.INFINITY) { row { title = "Adaptive brightness" subtitle = "Optimizes brightness for available light" primaryAction = toggleAction } inputRange { inputAction = (brightnessPendingIntent) max = 100 value = 45 } } } fun createToggleIntent(): PendingIntent { val intent = Intent(context, MyBroadcastReceiver::class.java) return PendingIntent.getBroadcast(context, 0, intent, 0) }
Java
public Slice createBrightnessSlice(Uri sliceUri) { if (getContext() == null) { return null; } SliceAction toggleAction = SliceAction.createToggle( createToggleIntent(), "Toggle adaptive brightness", true ); ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY) .addRow(new ListBuilder.RowBuilder() .setTitle("Adaptive brightness") .setSubtitle("Optimizes brightness for available light.") .setPrimaryAction(toggleAction) ).addInputRange(new ListBuilder.InputRangeBuilder() .setInputAction(brightnessPendingIntent) .setMax(100) .setValue(45) ); return listBuilder.build(); } public PendingIntent createToggleIntent() { Intent intent = new Intent(getContext(), MyBroadcastReceiver.class); return PendingIntent.getBroadcast(getContext(), 0, intent, 0); }
Então, o receptor pode verificar o estado recebido:
Kotlin
class MyBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (intent.hasExtra(Slice.EXTRA_TOGGLE_STATE)) { Toast.makeText(context, "Toggled: " + intent.getBooleanExtra( Slice.EXTRA_TOGGLE_STATE, false), Toast.LENGTH_LONG).show() } } companion object { const val EXTRA_MESSAGE = "message" } }
Java
public class MyBroadcastReceiver extends BroadcastReceiver { public static String EXTRA_MESSAGE = "message"; @Override public void onReceive(Context context, Intent intent) { if (intent.hasExtra(EXTRA_TOGGLE_STATE)) { Toast.makeText(context, "Toggled: " + intent.getBooleanExtra( EXTRA_TOGGLE_STATE, false), Toast.LENGTH_LONG).show(); } } }
Slices dinâmicos
Os Slices também podem apresentar conteúdo dinâmico. No exemplo a seguir, o Slice agora inclui o número de transmissões recebidas no conteúdo:
Kotlin
fun createDynamicSlice(sliceUri: Uri): Slice { return when (sliceUri.path) { "/count" -> { val toastAndIncrementAction = SliceAction.create( createToastAndIncrementIntent("Item clicked."), actionIcon, ListBuilder.ICON_IMAGE, "Increment." ) list(context, sliceUri, ListBuilder.INFINITY) { row { primaryAction = toastAndIncrementAction title = "Count: ${MyBroadcastReceiver.receivedCount}" subtitle = "Click me" } } } else -> { list(context, sliceUri, ListBuilder.INFINITY) { row { primaryAction = createActivityAction() title = "URI not found." } } } } }
Java
public Slice createDynamicSlice(Uri sliceUri) { if (getContext() == null || sliceUri.getPath() == null) { return null; } ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY); switch (sliceUri.getPath()) { case "/count": SliceAction toastAndIncrementAction = SliceAction.create( createToastAndIncrementIntent("Item clicked."), actionIcon, ListBuilder.ICON_IMAGE, "Increment." ); listBuilder.addRow( new ListBuilder.RowBuilder() .setPrimaryAction(toastAndIncrementAction) .setTitle("Count: " + MyBroadcastReceiver.sReceivedCount) .setSubtitle("Click me") ); break; default: listBuilder.addRow( new ListBuilder.RowBuilder() .setPrimaryAction(createActivityAction()) .setTitle("URI not found.") ); break; } return listBuilder.build(); } public PendingIntent createToastAndIncrementIntent(String s) { Intent intent = new Intent(getContext(), MyBroadcastReceiver.class) .putExtra(MyBroadcastReceiver.EXTRA_MESSAGE, s); return PendingIntent.getBroadcast(getContext(), 0, intent, 0); }
Neste exemplo, embora a contagem seja exibida, ela não é atualizada automaticamente. Para
modificar o broadcast receiver para notificar o sistema de que uma mudança aconteceu,
use
ContentResolver#notifyChange
.
Kotlin
class MyBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (intent.hasExtra(Slice.EXTRA_TOGGLE_STATE)) { Toast.makeText( context, "Toggled: " + intent.getBooleanExtra( Slice.EXTRA_TOGGLE_STATE, false ), Toast.LENGTH_LONG ).show() receivedCount++; context.contentResolver.notifyChange(sliceUri, null) } } companion object { var receivedCount = 0 val sliceUri = Uri.parse("content://com.android.example.slicesample/count") const val EXTRA_MESSAGE = "message" } }
Java
public class MyBroadcastReceiver extends BroadcastReceiver { public static int sReceivedCount = 0; public static String EXTRA_MESSAGE = "message"; private static Uri sliceUri = Uri.parse("content://com.android.example.slicesample/count"); @Override public void onReceive(Context context, Intent intent) { if (intent.hasExtra(EXTRA_TOGGLE_STATE)) { Toast.makeText(context, "Toggled: " + intent.getBooleanExtra( EXTRA_TOGGLE_STATE, false), Toast.LENGTH_LONG).show(); sReceivedCount++; context.getContentResolver().notifyChange(sliceUri, null); } } }
Modelos
Os Slices são compatíveis com vários modelos. Para mais detalhes sobre as opções e os comportamentos de modelo, consulte Modelos.