As APIs android.media.projection
introduzidas no Android 5 (nível 21 da API)
permitem capturar o conteúdo da tela de um dispositivo como um stream de mídia que
pode ser reproduzido, gravado ou transmitido para outros dispositivos, como TVs.
O Android 14 (nível 34 da API) apresenta o compartilhamento de tela do app, que permite que os usuários compartilhem uma única janela de app em vez de toda a tela do dispositivo, independente do modo de janela. O compartilhamento de tela do app exclui a barra de status, a barra de navegação, as notificações e outros elementos da interface do sistema da tela compartilhada, mesmo quando o compartilhamento de tela do app é usado para capturar um app em tela cheia. Somente o conteúdo do app selecionado é compartilhado.
O compartilhamento de tela do app garante a privacidade do usuário, aumenta a produtividade e melhora a multitarefa, permitindo que os usuários executem vários apps, mas restringem o compartilhamento de conteúdo a apenas um app.
Três representações de tela
Uma projeção de mídia captura o conteúdo de uma tela do dispositivo ou janela do app e
projeta a imagem capturada em uma tela virtual que renderiza a imagem em
uma Surface
.
O aplicativo fornece a Surface
usando uma MediaRecorder
,
SurfaceTexture
ou ImageReader
, que consome o conteúdo da
tela capturada e permite gerenciar imagens renderizadas na Surface
em
tempo real. Salve as imagens como uma gravação ou transmita para uma TV ou outro
dispositivo.
Tela real
Inicie uma sessão de projeção de mídia usando um token que conceda ao app a
capacidade de capturar o conteúdo da tela do dispositivo ou da janela do app. O token
é representado por uma instância da classe MediaProjection
.
Use o método getMediaProjection()
do serviço do sistema MediaProjectionManager
para criar uma instância de MediaProjection
ao iniciar uma nova
atividade. Inicie a atividade com uma intent do
método createScreenCaptureIntent()
para especificar uma operação de captura de tela:
Kotlin
val mediaProjectionManager = getSystemService(MediaProjectionManager::class.java) var mediaProjection : MediaProjection
val startMediaProjection = registerForActivityResult( StartActivityForResult() ) { result -> if (result.resultCode == RESULT_OK) { mediaProjection = mediaProjectionManager .getMediaProjection(result.resultCode, result.data!!) } }
startMediaProjection.launch(mediaProjectionManager.createScreenCaptureIntent())
Java
final MediaProjectionManager mediaProjectionManager = getSystemService(MediaProjectionManager.class); final MediaProjection[] mediaProjection = new MediaProjection[1];
ActivityResultLauncherstartMediaProjection = registerForActivityResult( new StartActivityForResult(), result -> { if (result.getResultCode() == Activity.RESULT_OK) { mediaProjection[0] = mediaProjectionManager .getMediaProjection(result.getResultCode(), result.getData()); } } );
startMediaProjection.launch(mediaProjectionManager.createScreenCaptureIntent());
Tela virtual
O centro de uma projeção de mídia é a tela virtual, que é criada
chamando o método createVirtualDisplay()
em uma instância MediaProjection
:
Kotlin
virtualDisplay = mediaProjection.createVirtualDisplay( "ScreenCapture", width, height, screenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, surface, null, null)
Java
virtualDisplay = mediaProjection.createVirtualDisplay( "ScreenCapture", width, height, screenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, surface, null, null);
Os parâmetros width
e height
especificam as dimensões da tela
virtual. Para conferir os valores de largura e altura, use as APIs WindowMetrics
introduzidas no Android 11 (nível 30 da API). Para mais detalhes, consulte a seção Tamanho da
projeção de mídia.
Superfície
Dimensione a superfície da projeção de mídia para produzir a saída na resolução adequada. Aumente a superfície (baixa resolução) para a transmissão da tela em TVs ou monitores de computador e diminua (alta resolução) para a gravação da tela do dispositivo.
A partir do Android 12L (nível 32 da API), ao renderizar o conteúdo capturado na plataforma, o sistema dimensiona o conteúdo de maneira uniforme, mantendo a proporção, de modo que as duas dimensões do conteúdo (largura e altura) sejam iguais ou menores do que as dimensões correspondentes da plataforma. O conteúdo capturado é centralizado na plataforma.
A abordagem de dimensionamento do Android 12L melhora a transmissão de tela para televisões e outras telas grandes, maximizando o tamanho da imagem da plataforma e garantindo a proporção adequada.
Permissão para serviços de primeiro plano
Se o app for destinado ao Android 14 ou mais recente, o manifesto do app precisará incluir uma
declaração de permissão para o tipo de serviço em primeiro plano
mediaProjection
:
<manifest ...>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
<application ...>
<service
android:name=".MyMediaProjectionService"
android:foregroundServiceType="mediaProjection"
android:exported="false">
</service>
</application>
</manifest>
Inicie o serviço de projeção de mídia com uma chamada para startForeground()
.
Se você não especificar o tipo de serviço em primeiro plano na chamada, o tipo será definido
como um número inteiro de bits dos tipos de serviço em primeiro plano definidos no manifesto. Se
o manifesto não especificar nenhum tipo de serviço, o sistema vai gerar uma
MissingForegroundServiceTypeException
.
Consentimento do usuário
O app precisa solicitar o consentimento do usuário antes de cada sessão de projeção de mídia. Uma
sessão é uma única chamada para createVirtualDisplay()
. Um token MediaProjection
precisa ser usado apenas uma vez para fazer a chamada.
No Android 14 ou mais recente, o método createVirtualDisplay()
gera uma
SecurityException
se o app fizer uma das seguintes ações:
- Transmite uma instância
Intent
retornada decreateScreenCaptureIntent()
paragetMediaProjection()
mais de uma vez - Chama
createVirtualDisplay()
mais de uma vez na mesma instância deMediaProjection
Tamanho da projeção de mídia
Uma projeção de mídia pode capturar toda a tela do dispositivo ou uma janela de app, independente do modo de janela.
Tamanho inicial
Com a projeção de mídia em tela cheia, o app precisa determinar o tamanho da tela do dispositivo. No compartilhamento de tela do app, o app não poderá determinar o tamanho da tela capturada até que o usuário selecione a região de captura. Portanto, o tamanho inicial de qualquer projeção de mídia é o tamanho da tela do dispositivo.
Use o método WindowManager
getMaximumWindowMetrics()
da plataforma para
retornar um objeto WindowMetrics
para a tela do dispositivo, mesmo que o app
host de projeção de mídia esteja no modo de várias janelas, ocupando apenas parte da
tela.
Para compatibilidade com o nível 14 da API e mais recentes, use o método
computeMaximumWindowMetrics()
do WindowMetricsCalculator
da biblioteca
WindowManager
do Jetpack.
Chame o método WindowMetrics
getBounds()
para receber a largura e a altura da
tela do dispositivo.
Mudanças de tamanho
O tamanho da projeção de mídia pode mudar quando o dispositivo é girado ou o usuário seleciona uma janela de app como a região de captura no compartilhamento de tela do app. A projeção de mídia pode ser letterbox se o conteúdo capturado for de um tamanho diferente das métricas de janela máxima obtidas quando a projeção de mídia foi configurada.
Para garantir que a projeção de mídia seja alinhada com precisão ao tamanho do conteúdo
capturado para qualquer região capturada e em todas as rotações do dispositivo, use o
callback onCapturedContentResize()
para redimensionar a captura. Para mais
informações, consulte a seção Personalização a seguir.
Personalização
Seu app pode personalizar a experiência do usuário de projeção de mídia com as seguintes
APIs MediaProjection.Callback
:
onCapturedContentVisibilityChanged()
: permite que o app host (o app que iniciou a projeção de mídia) mostre ou oculte o conteúdo compartilhado.Use esse callback para personalizar a interface do app com base na visibilidade da região capturada para o usuário. Por exemplo, se o app estiver visível para o usuário e exibir o conteúdo capturado na interface do app, e o app capturado também estiver visível para o usuário (conforme indicado por esse callback), o usuário vai ver o mesmo conteúdo duas vezes. Use o callback para atualizar a interface do app e ocultar o conteúdo capturado, liberando espaço de layout para outro conteúdo.
onCapturedContentResize()
: permite que o app host mude o tamanho da projeção de mídia na tela virtual e a projeção de mídiaSurface
com base no tamanho da região de exibição capturada.É acionado sempre que o conteúdo capturado, uma única janela do app ou a tela inteira do dispositivo, muda de tamanho (por causa da rotação do dispositivo ou do app capturado entrar em um modo de janela diferente). Use essa API para redimensionar a tela virtual e a plataforma para garantir que a proporção corresponda ao conteúdo capturado e que a captura não seja letterbox.
Recuperação de recursos
O app precisa registrar o callback MediaProjection
onStop()
para ser
informado quando a sessão de projeção de mídia for interrompida e se tornar inválida. Quando
a sessão for interrompida, o app precisará liberar os recursos que ele tem,
como a tela virtual e a superfície de projeção. Uma sessão de projeção de mídia
interrompida não pode mais criar uma nova tela virtual, mesmo que o app não tenha
criado uma tela virtual para essa projeção de mídia.
O sistema invoca o callback quando a projeção de mídia é encerrada. Essa rescisão pode ocorrer por vários motivos, como:
- o usuário interromper a sessão usando a interface do app ou o chip da barra de status de projeção de mídia do sistema;
- a tela está sendo bloqueada
- outra sessão de projeção de mídia é iniciada
- o processo do app é encerrado
Se o app não registrar o callback, qualquer chamada para createVirtualDisplay()
gerará IllegalStateException
.
Desativar
O Android 14 ou mais recente ativa o compartilhamento de tela do app por padrão. Cada sessão de projeção de mídia oferece aos usuários a opção de compartilhar uma janela de app ou toda a tela.
Seu app pode desativar o compartilhamento de tela chamando o
método createScreenCaptureIntent(MediaProjectionConfig)
com um
argumento MediaProjectionConfig
retornado de uma chamada para
createConfigForDefaultDisplay()
.
Uma chamada para createScreenCaptureIntent(MediaProjectionConfig)
com um
argumento MediaProjectionConfig
retornado de uma chamada para
createConfigForUserChoice()
é igual ao comportamento padrão, ou seja,
uma chamada para createScreenCaptureIntent()
.
Apps redimensionáveis
Sempre crie apps de projeção de mídia que possam ser redimensionados
(resizeableActivity="true"
). Os apps redimensionáveis oferecem suporte a mudanças de configuração
do dispositivo e do modo de várias janelas. Consulte Suporte a várias janelas.
Se o app não for redimensionável, ele precisará consultar os limites da tela em um contexto de janela
e usar getMaximumWindowMetrics()
para extrair as WindowMetrics
da
área máxima de exibição disponível para o app :
Kotlin
val windowContext = context.createWindowContext(context.display!!, WindowManager.LayoutParams.TYPE_APPLICATION, null) val projectionMetrics = windowContext.getSystemService(WindowManager::class.java) .maximumWindowMetrics
Java
Context windowContext = context.createWindowContext(context.getDisplay(), WindowManager.LayoutParams.TYPE_APPLICATION, null); WindowMetrics projectionMetrics = windowContext.getSystemService(WindowManager.class) .getMaximumWindowMetrics();
Ícone da barra de status e parada automática
As explorações de projeção de tela expõem dados privados do usuário, como informações financeiras, porque os usuários não percebem que a tela do dispositivo está sendo compartilhada.
O Android 15 (nível 35 da API) e versões mais recentes mostram um ícone grande e proeminente na barra de status para alertar os usuários sobre qualquer projeção de tela em andamento. Os usuários podem tocar no ícone para impedir que a tela seja compartilhada, transmitida ou gravada. Além disso, a projeção de tela é interrompida automaticamente quando a tela do dispositivo é bloqueada.
Teste a disponibilidade do ícone da barra de status da projeção de mídia iniciando o compartilhamento de tela, a transmissão ou a gravação. O ícone vai aparecer na barra de status.
Para garantir que o app libere recursos e atualize a interface quando a projeção de tela for interrompida pela interação do usuário com o ícone da barra de status ou pela ativação da tela de bloqueio, faça o seguinte:
Crie uma instância de
MediaProjection.Callback
.Implemente o método de callback
onStop()
. O método é chamado quando a projeção de tela é interrompida. Libere todos os recursos que o app está segurando e atualize a interface do app conforme necessário.
Para testar o callback, toque no ícone da barra de status ou bloqueie a tela do dispositivo para interromper
a projeção. Verifique se o método onStop()
é chamado e se o app
responde conforme o esperado.
Outros recursos
Para saber mais sobre projeção de mídia, consulte Capturar reproduções de vídeo e áudio.