Introdução ao Conceito de Window
No ecossistema Android, cada elemento visual interativo apresentado na tela é gerenciado por uma abstração denominada Window. Componentes como a barra de status, barras de navegação, painéis de volume, Activities, Diálogos e Toasts são, em essência, janelas ou estão anexados a elas. O WindowManager atua como o controlador direto dessas janelas, sendo o responsável por orquestrar como as Views são renderizadas e interagem com o sistema.
Implementação Prática: View Flutuante
Para compreender a atuação do WindowManager, é possível observar a criação de um elemento flutuante que permanece sobreposto a outras aplicações e responde a eventos de toque.
private void renderFloatingWidget() {
requestOverlayPermission();
WindowManager wmService = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Button floatingAction = new Button(this);
floatingAction.setText("Ação");
WindowManager.LayoutParams windowConfig = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT);
windowConfig.gravity = Gravity.TOP | Gravity.START;
windowConfig.x = 200;
windowConfig.y = 200;
wmService.addView(floatingAction, windowConfig);
floatingAction.setOnTouchListener((view, motionEvent) -> {
if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
windowConfig.x = (int) motionEvent.getRawX();
windowConfig.y = (int) motionEvent.getRawY();
wmService.updateViewLayout(floatingAction, windowConfig);
}
return true;
});
}
private void requestOverlayPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivity(intent);
}
}
Para que o código funcione em versões modernas do Android, é mandatório declarar a permissão no AndroidManifest.xml:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
Neste cenário, o elemento não é inflado via setContentView em uma Activity, mas sim injetado diretamente na hierarquia de janelas do sistema através de addView. A movimentação é tratada atualizando as coordenadas no LayoutParams e chamando updateViewLayout.
Propriedades e Classificação de Janelas
O comportamento e a posição de uma Window são definidos através de seu LayoutParams.
Flags (Bandeiras)
As flags controlam características de interação e exibição, como a capacidade de receber foco, capturar eventos de toque ou permanecer visível sobre a tela de bloqueio.
Types (Tipos) e Z-Order
O sistema classifica as janelas em três categorias principais, o que determina sua posição no eixo Z (profundidade da tela). Quanto maior o valor do tipo, mais acima a janela será renderizada na pilha visual:
- Janelas de Aplicação (1 - 99): Associadas a uma Activity. Formam a base da interface do aplicativo.
- Sub-janelas (1000 - 1999): Não podem existir de forma independente. Devem estar ancoradas a uma janela pai (ex: Dialogs, Popups).
- Janelas de Sistema (2000 - 2999): Exigem permissões privilegiadas. Incluem a barra de status, teclado virtual e Toasts. São renderizadas no topo da pilha.
Hierarquia de Classes do WindowManager
A obtenção do WindowManager via getSystemService(Context.WINDOW_SERVICE) retorna, na verdade, uma instância de WindowManagerImpl. A arquitetura segue o padrão Bridge, delegando operações complexas para classes internas.
public interface ViewManager {
void addView(View view, ViewGroup.LayoutParams params);
void updateViewLayout(View view, ViewGroup.LayoutParams params);
void removeView(View view);
}
public interface WindowManager extends ViewManager {
// Métodos específicos de janela
}
public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal globalManager = WindowManagerGlobal.getInstance();
@Override
public void addView(View view, ViewGroup.LayoutParams params) {
globalManager.addView(view, params, mContext.getDisplay(), mParentWindow);
}
// Demais métodos delegam para globalManager
}
O WindowManagerGlobal é um Singleton que atua como o verdadeiro cérebro das operações. Ele mantém quatro listas fundamentais para o ciclo de vida das janelas:
activeViews: Armazena as instâncias deView.viewRoots: Armazena os objetosViewRootImplcorrespondentes.layoutParamsList: Armazena osLayoutParamsde cada janela.dyingViews: Controla as Views que estão em processo de remoção assíncrona.
Mecanismos Internos de Manipulação
Adição de Views (addView)
O processo de adição valida se a View já existe, cria um novo ViewRootImpl (o elo entre a View e o sistema de renderização) e popula as listas internas. O passo crucial é a chamada root.setView(), que dispara o primeiro ciclo de layout (requestLayout) e realiza uma chamada IPC (Inter-Process Communication) para o WindowManagerService (WMS) através do mWindowSession.addToDisplay().
Atualização de Layout (updateViewLayout)
A atualização é uma operação mais direta. O WindowManagerGlobal localiza a View, substitui o LayoutParams antigo na lista e notifica o ViewRootImpl. Isso aciona scheduleTraversals(), forçando o sistema a recalcular e redesenhar a janela com as novas propriedades.
Remoção de Views (removeView)
O sistema oferece duas abordagens para remoção:
- removeView: Assíncrona. Envia uma mensagem (
MSG_DIE) para a Handler doViewRootImpl, garantindo que a remoção ocorra apenas após a conclusão de traversals pendentes, evitando inconsistências de estado. - removeViewImmediate: Síncrona. Executa o método
doDie()instantaneamente, limpando recursos e removendo a janela do WMS sem aguardar a fila de mensagens.
Em ambos os casos, o método doDie() é o responsável por desconectar a View (dispatchDetachedFromWindow), liberar recursos e notificar o WMS para destruir a estrutura da janela no lado do servidor.
O Papel do WindowManagerService (WMS)
Todas as operações críticas do WindowManagerGlobal culminam no WindowManagerService, um serviço de sistema essencial que opera no processo system_server. O WMS é responsável por:
- Gerenciamento de Janelas: Controla o ciclo de vida, dimensões, empilhamento (Z-Order) e visibilidade de todas as janelas no dispositivo.
- Animações de Transição: Orquestra as animações de entrada, saída e mudança de estado das janelas através do subsistema
WindowAnimator. - Roteamento de Entrada: Atua como intermediário para o
InputManagerService, determinando qual janela deve receber eventos de toque com base na posição e na pilha Z. - Alocação de Surfaces: Janelas não desenham diretamente na tela; elas solicitam buffers de desenho. O WMS gerencia a criação e a composição dessas Surfaces via
SurfaceFlinger.
O WMS é inicializado durante a sequência de boot do Android. No processo SystemServer, o método startOtherServices() instancia o WindowManagerService em uma thread dedicada (DisplayThread) e o registra no ServiceManager, tornando-o acessível globalmente para todos os processos de aplicação através do mecanismo Binder.