O Modo Janela para Computador permite que os usuários executem vários apps simultaneamente em janelas redimensionáveis para uma experiência versátil semelhante à de um computador.
Na Figura 1, é possível conferir a organização da tela com o Modo Janela para Computador ativado. Observações:
- Os usuários podem executar vários apps lado a lado simultaneamente.
- A barra de tarefas está em uma posição fixa na parte de baixo da tela, mostrando os apps em execução. Os usuários podem fixar apps para acesso rápido.
- Uma nova barra de cabeçalho personalizável decora a parte de cima de cada janela com controles como minimizar e maximizar.
Por padrão, os apps são abertos em tela cheia em tablets Android. Para iniciar um app no modo janela para computador, tocar e pressionar a alça da janela na parte de cima da tela e arraste-a na interface, conforme mostrado na Figura 2.
Quando um app é aberto no Modo Janela para Computador, outros apps também são abertos em janelas.
Os usuários também podem invocar o Modo Janela para Computador no menu que aparece abaixo da alça da janela ao tocar ou clicar nela ou usar o atalho de teclado Meta key (Windows, Command, or Search) + Ctrl + Down.
Os usuários saem do Modo Janela para Computador fechando todas as janelas ativas ou pegando a alça da janela na parte de cima de uma janela e arrastando o app para a parte de cima da tela. O atalho de teclado Meta + H também sai do Modo Janela para Computador e executa os apps em tela cheia novamente.
Para retornar ao Modo Janela para Computador, toque ou clique no bloco de espaço de trabalho na tela "Recentes".
Otimizar o layout do app para um ambiente semelhante ao de um computador
O design para uma experiência de computador pode ser significativamente diferente do design para dispositivos móveis devido ao aumento do espaço da tela, à precisão da entrada do mouse e do teclado e à expectativa de alta produtividade.
O Jetpack WindowManager fornece uma API opinativa para ajudar os desenvolvedores a decidir quando mostrar uma interface de computador, que normalmente tem maior densidade de informações, padrões de navegação diferentes e interações otimizadas do mouse.
lifecycleScope.launch(Dispatchers.Main) { lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { windowInfoTracker.windowEngagementInfo(this@DesktopWindowingActivity) .collect { windowEngagementInfo -> if(windowEngagementInfo.hasEngagementMode(WindowEngagementInfo.EngagementMode.PRECISE_POINTER)){ showDesktopOptimizedUI() }else { showTouchOptimizedUI() } } } }
Para saber mais, consulte Design para computador.
Modo de redimensionamento e compatibilidade
No Modo Janela para Computador, os apps com orientação bloqueada podem ser redimensionados livremente. Isso significa que, mesmo que uma atividade esteja bloqueada para a orientação retrato, os usuários ainda podem redimensionar o app para uma janela de orientação paisagem.
Os apps declarados como não redimensionáveis (ou seja, resizeableActivity = false) têm
a interface dimensionada, mantendo a mesma proporção.
Os apps de câmera que bloqueiam a orientação ou são declarados como não redimensionáveis têm um tratamento especial para os visores da câmera: a janela é totalmente redimensionável, mas o visor mantém a mesma proporção. Ao presumir que os apps sempre são executados no modo retrato ou paisagem, eles codificam ou fazem outras suposições que levam a erros de cálculo da orientação ou proporção da imagem de visualização ou capturada, resultando em imagens esticadas, laterais ou de cabeça para baixo.
Até que os apps estejam prontos para implementar visores de câmera totalmente responsivos, o tratamento especial oferece uma experiência do usuário mais básica que atenua os efeitos que suposições erradas podem causar.
Para saber mais sobre o modo de compatibilidade para apps de câmera, consulte Modo de compatibilidade do dispositivo.
Inserções de cabeçalho personalizáveis
Todos os apps em execução no Modo Janela para Computador têm uma barra de cabeçalho, mesmo no modo imersivo. É possível personalizar essa barra para evitar que o conteúdo do app seja obscurecido e para desenhar elementos de interface personalizados diretamente no espaço do cabeçalho.
Implementação
Para desenhar conteúdo personalizado na barra de cabeçalho, a primeira etapa é deixar o fundo da barra de cabeçalho transparente. É possível fazer isso usando a
APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND flag com o
WindowInsetsController.
window.insetsController?.setSystemBarsAppearance( WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND, WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND )
Depois que a barra de cabeçalho estiver transparente, você poderá estilizar a área do cabeçalho para corresponder ao design do app. Use WindowInsets.isCaptionBarVisible para detectar se a barra está
presente e aplicar a altura ou o padding adequado ao layout.
@OptIn(ExperimentalLayoutApi::class) @Composable fun CaptionBar() { if (WindowInsets.isCaptionBarVisible) { Row( modifier = Modifier .windowInsetsTopHeight(WindowInsets.captionBar) .fillMaxWidth() .background(if (isSystemInDarkTheme()) Color.White else Color.Black), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { Text( text = "Caption Bar Title", style = MaterialTheme.typography.titleMedium, modifier = Modifier.padding(4.dp) ) } } }
setSystemBarsAppearance(appearance,mask): configura o estilo visual das barras de sistema. O primeiro parâmetro define as flags de aparência de destino, enquanto o segundo atua como uma máscara para controlar quais flags específicas são modificadas.windowInsetsTopHeight(): define automaticamente a altura do elemento combinável para corresponder à barra de cabeçalho do sistema, ajudando o plano de fundo personalizado a preencher a área da legenda sem codificar valores de pixel.WindowInsets.captionBar: fornece as dimensões dos controles do Modo Janela para Computador (Fechar, Maximizar etc.), permitindo que a interface seja dimensionada ou ocultada automaticamente ao entrar ou sair do Modo Janela para Computador.
Para mais informações, consulte Sobre inserções de janela. Além de um título, é possível mostrar outros elementos de interface na barra de legenda, como guias (como no Google Chrome), barras de pesquisa ou avatares de perfil.
Interface do usuário
Para evitar a sobreposição da interface com os botões do sistema, o Android 15 oferece o
WindowInsets#getBoundingRects() método. O método retorna uma lista de
Rect objetos que representam áreas ocupadas por elementos do sistema. Qualquer espaço restante na barra de legenda é uma zona de segurança em que você pode colocar conteúdo personalizado com segurança.
Alterne a aparência dos elementos de legenda do sistema para temas claros e escuros usando
APPEARANCE_LIGHT_CAPTION_BARS. Acesse as inserções usando
WindowInsets.Companion.captionBar() no Compose ou
WindowInsets.Type.captionBar() nas visualizações.
Para mais informações, consulte Sobre inserções de janela.
Suporte a multitarefas e várias instâncias
A multitarefa está no centro do Modo Janela para Computador, e permitir várias instâncias do app pode aumentar muito a produtividade dos usuários.
A partir do Android 15, é possível usar
PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI. Ao definir essa propriedade no AndroidManifest.xml, você especifica que a interface do sistema precisa fornecer opções (como um botão "Nova janela") para que o app seja iniciado em várias instâncias.
<application>
<property
android:name="android.window.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI"
android:value="true" />
</application>
Observação:no Modo Janela para Computador e em outros ambientes de várias janelas, novas tarefas são abertas em uma nova janela. Portanto, verifique o percurso do usuário sempre que o app iniciar várias tarefas.
Gerenciar instâncias de apps com gestos de arrastar
No modo de várias janelas, os usuários podem iniciar uma nova instância do app arrastando um elemento da interface (como uma guia ou um documento) para fora da janela do app. Os usuários também podem mover elementos entre diferentes instâncias do mesmo app.
Transferir dados com arrastar e soltar
Para configurar um elemento combinável como uma origem de arrastar para arrastar e soltar várias instâncias
permitindo que os usuários arrastem conteúdo para outra instância do app ou criem uma
nova instância soltando conteúdo em uma área vazia da tela, use o
dragAndDropSource modificador. Na lambda, retorne
DragAndDropTransferData, transmitindo o ClipData que contém os dados a serem
transferidos e as flags para configurar o comportamento de várias instâncias.
O Android 15 apresenta duas flags importantes para o Modo Janela para Computador e interações de várias instâncias:
DRAG_FLAG_GLOBAL_SAME_APPLICATION: indica que uma operação de arrastar pode cruzar os limites da janela (para várias instâncias do mesmo aplicativo). QuandostartDragAndDrop()é chamado com essa flag definida, apenas as janelas visíveis pertencentes ao mesmo aplicativo podem participar da operação de arrastar e receber o conteúdo arrastado.
Modifier.dragAndDropSource { _ -> DragAndDropTransferData( clipData = ClipData.newPlainText("label", "Your data"), flags = View.DRAG_FLAG_GLOBAL_SAME_APPLICATION ) }
DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG: permite que os usuários iniciem uma nova instância do app soltando o conteúdo arrastado em uma área vazia da tela, se nenhuma outra janela processar a soltura.- Ao usar essa flag, é necessário fornecer um
IntentSenderusandoClipData.Item.Builder#setIntentSender(), que o sistema usa para iniciar a nova atividade se uma soltura não processada ocorrer.
- Ao usar essa flag, é necessário fornecer um
Modifier.dragAndDropSource { _ -> val intent = Intent.makeMainActivity(activity.componentName).apply { putExtra("EXTRA_ITEM_ID", itemId) flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK or Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT } val pendingIntent = PendingIntent.getActivity( activity, 0, intent, PendingIntent.FLAG_IMMUTABLE ) val data = ClipData( "Item $itemId", arrayOf(ClipDescription.MIMETYPE_TEXT_INTENT), ClipData.Item.Builder().setIntentSender(pendingIntent.intentSender).build() ) DragAndDropTransferData( clipData = data, flags = View.DRAG_FLAG_GLOBAL_SAME_APPLICATION or View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG, ) }
Receber dados transferidos
Para aceitar dados de outra instância, use o dragAndDropTarget modificador.
É necessário solicitar permissões explicitamente se os dados vierem de uma instância ou app diferente.
Modifier.dragAndDropTarget( shouldStartDragAndDrop = { event -> event.toAndroidDragEvent().clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN) }, target = object : DragAndDropTarget { override fun onDrop(event: DragAndDropEvent): Boolean { requestDragAndDropPermissions(activity, event.toAndroidDragEvent()) val clipData = event.toAndroidDragEvent().clipData val item = clipData?.getItemAt(0)?.text if (item != null) { // Process the dropped text item here } return item != null } } )
Etapas principais :
- Filtrar: use
shouldStartDragAndDroppara verificar se os dados recebidos (tipo MIME) são compatíveis. - Permissões: chame
requestDragAndDropPermissions(event)para acessar os dados. - Processar: extraia os dados no
onDropcallback.
Otimizações adicionais
Personalize as inicializações de apps e faça a transição de apps do Modo Janela para Computador para tela cheia.
Especificar tamanho e posição padrão
Nem todos os apps, mesmo que redimensionáveis, precisam de uma janela grande para oferecer valor ao usuário. É possível usar o
método ActivityOptions#setLaunchBounds() para especificar um tamanho e uma posição padrão
quando uma atividade é iniciada.
Entrar em tela cheia no espaço de trabalho
Os apps podem entrar em tela cheia chamando Activity#requestFullScreenMode(). O método mostra o app em tela cheia diretamente do Modo Janela para Computador.