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
elas 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 de 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]; ActivityResultLauncher<Intent> startMediaProjection = 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 de hospedagem 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 WindowMetricsCalculator
computeMaximumWindowMetrics()
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 completa do dispositivo, muda de tamanho (devido à rotação do dispositivo ou ao app capturado entrar em um modo de janela diferente). Use essa API para redimensionar a tela e a superfície virtuais e garantir que a proporção corresponda ao conteúdo capturado e que a captura não tenha efeito 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 precisa liberar os recursos que
ele contém, 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 da 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 do app ou a tela inteira.
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()
é o mesmo
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 de dispositivos 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 QPR1 do Android 15 (nível 35 da API) apresenta um novo ícone da barra de status grande e destacado, que alerta 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.
No Android 15 QPR1 e versões mais recentes, a projeção da tela é interrompida automaticamente quando a tela do dispositivo é bloqueada.
Outros recursos
Para saber mais sobre projeção de mídia, consulte Capturar reproduções de vídeo e áudio.