O android.media.projection
As APIs introduzidas no Android 5 (nível 21 da API) permitem capturar o conteúdo
de uma tela de dispositivo como um stream de mídia que pode ser reproduzido, gravado ou transmitido
outros dispositivos, como TVs.
O Android 14 (nível 34 da API) apresenta o compartilhamento de tela de apps, que permite aos usuários compartilhar uma única janela do app em vez da tela inteira do dispositivo, independentemente o modo de janelamento. O compartilhamento de tela do app exclui a barra de status, a barra de navegação notificações e outros elementos da interface do sistema pela tela compartilhada, mesmo quando o compartilhamento de tela é usado para capturar um app em tela cheia. Somente o conteúdo do app selecionado é compartilhado.
O compartilhamento de tela de app garante a privacidade do usuário, aumenta a produtividade do usuário e melhora a multitarefa ao permitir que os usuários executem vários aplicativos, mas com restrições o compartilhamento de conteúdo em apenas um app.
Três representações de exibição
Uma projeção de mídia captura o conteúdo de uma tela de dispositivo ou janela de app e
e projeta a imagem capturada em uma tela virtual que renderiza a imagem no
Surface
![Tela do dispositivo real projetada em exibição virtual. Conteúdo da
tela virtual gravada para a "Superfície" fornecida pelo aplicativo.](https://developer.android.com/static/media/images/grow/media-projection.png?authuser=9&hl=pt)
Surface
:
O aplicativo fornece o Surface
usando uma
MediaRecorder
,
SurfaceTexture
ou
ImageReader
, que consome
o conteúdo da tela capturada e permite que você gerencie as imagens renderizadas
na Surface
em tempo real. Você pode salvar as imagens como uma gravação ou uma transmissão
para uma TV ou outro dispositivo.
Exibição real
Inicie uma sessão de projeção de mídia obtendo um token que concede ao app o
a capacidade de capturar o conteúdo da tela do dispositivo ou da janela do app. O token
é representada por uma instância
MediaProjection
.
Use o método getMediaProjection()
da
Serviço do sistema MediaProjectionManager
para criar uma instância MediaProjection
ao iniciar uma nova atividade. Inicie a atividade com uma intent no
Método createScreenCaptureIntent()
para especificar uma tela.
captura:
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 do ambiente
exibição. Para obter os valores de largura e altura, use o método
As APIs WindowMetrics
foram lançadas
no Android 11 (nível 30 da API). Para mais detalhes, consulte
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 da forma correta e resolução. Deixe a superfície grande (baixa resolução) para transmissão de tela em TVs ou monitores de computador e pequeno (alta resolução) para gravação de telas do dispositivo.
No Android 12L (nível 32 da API), ao renderizar conteúdo capturado no o sistema dimensiona o conteúdo de maneira uniforme, mantendo a proporção, para que as duas dimensões do conteúdo (largura e altura) sejam iguais ou menores que as dimensões correspondentes da superfície. O conteúdo capturado é centralizada na superfície.
A abordagem de escalonamento do Android 12L melhora a transmissão de tela para televisões e outras telas grandes maximizando o tamanho da imagem da superfície e, ao mesmo tempo, garantir a proporção adequada.
Permissão para serviços de primeiro plano
Caso o app seja destinado ao Android 14 ou versões mais recentes, o manifesto dele vai precisar incluir uma
declaração de permissão para o
Tipo de serviço em primeiro plano do 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á o padrão
como um número inteiro bit a bit dos tipos de serviço em primeiro plano definidos no manifesto. Se
o manifesto não especificar nenhum tipo de serviço, o sistema emitirá
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. Um
sessão é uma única chamada para createVirtualDisplay()
. Um token MediaProjection
deve ser usado apenas uma vez para fazer a chamada.
No Android 14 ou em versões mais recentes, o método createVirtualDisplay()
gera uma
SecurityException
se as
app realiza uma das seguintes ações:
- Transmite uma instância
Intent
retornada decreateScreenCaptureIntent()
paragetMediaProjection()
mais de uma vez - Liga
createVirtualDisplay()
mais de uma vez no mesmoMediaProjection
instância
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 seja qual for o modo de janelamento.
Tamanho inicial
Com a projeção de mídia em tela cheia, o app precisa determinar o tamanho na tela do dispositivo. No compartilhamento de tela, o app não poderá determinar o tamanho da tela capturada até que o usuário selecione a região. Portanto, o tamanho inicial de qualquer projeção de mídia é o tamanho da tela do dispositivo.
Usar a plataforma WindowManager
getMaximumWindowMetrics()
para retornar um
Objeto WindowMetrics
do
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 WindowMetricsCalculator
computeMaximumWindowMetrics()
da biblioteca WindowManager
do Jetpack.
Chame o método WindowMetrics
getBounds()
para ver a largura e a altura da tela do dispositivo.
Alterações de tamanho
O tamanho da projeção de mídia pode mudar quando o dispositivo é girado ou o usuário seleciona uma janela do app como região de captura no compartilhamento de tela do app. A projeção de mídia poderá ter efeito letterbox se o conteúdo capturado for uma tamanho diferente das métricas máximas da janela geradas quando a mídia projeção foi configurada.
Para garantir que a projeção de mídia se alinhe com precisão ao tamanho do
conteúdo para qualquer região capturada e entre rotações de dispositivos, use o
Callback onCapturedContentResize()
para redimensionar a captura. Para mais
informações do produto, consulte a seção Personalização, a seguir).
Personalização
Seu app pode personalizar a experiência do usuário da projeção de mídia com o seguinte:
APIs do MediaProjection.Callback
:
onCapturedContentVisibilityChanged()
: Permite que o app host (o app que iniciou a projeção de mídia) mostre ou e ocultar o conteúdo compartilhado.Use esse callback para personalizar a interface do app com base na captura ou não fica visível para o usuário. Por exemplo, se o app estiver visível para e está exibindo o conteúdo capturado na interface do usuário do aplicativo, e o aplicativo capturado também é visível para o usuário (como indicado por este ), ele verá o mesmo conteúdo duas vezes. Usar o callback para atualizar interface do app para ocultar o conteúdo capturado e liberar espaço de layout na para outros conteúdos.
onCapturedContentResize()
: Permite que o app host altere o tamanho da projeção de mídia na VM exibição e projeção de mídiaSurface
com base no tamanho dos região de exibição.Acionado sempre que o conteúdo capturado (uma única janela do app ou tela do dispositivo: muda de tamanho (devido à rotação do dispositivo ou ao entrar em um modo de janelamento diferente). Use essa API para redimensionar tela e superfície virtuais para garantir que a proporção corresponda ao tamanho conteúdo sem o efeito letterbox.
Recuperação de recursos
Seu app precisa registrar o MediaProjection
onStop()
para ser informado quando a sessão de projeção de mídia for interrompida e se tornar
inválido. Quando a sessão é interrompida, seu aplicativo deve liberar os recursos que
ela mantém, como a tela virtual e a superfície de projeção. A parou
sessão de projeção de mídia não poderá mais criar uma tela virtual, mesmo se
o app não tiver criado anteriormente uma tela virtual para essa projeção de mídia.
O callback é chamado quando a projeção de mídia é encerrada, seja porque o o usuário interrompe manualmente a sessão ou porque o sistema interrompe a sessão por por algum motivo.
Caso o app não registre o callback, qualquer chamada para createVirtualDisplay()
lança
IllegalStateException
.
Desativar
O Android 14 ou versões mais recentes ativam o compartilhamento de tela de apps por padrão. Cada mídia de projeção oferece aos usuários a opção de compartilhar uma janela de aplicativo ou a 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 uma
Argumento MediaProjectionConfig
retornado de uma chamada para
createConfigForUserChoice()
é o mesmo
como comportamento padrão, ou seja, uma chamada para
createScreenCaptureIntent()
.
Apps redimensionáveis
Sempre crie apps de projeção de mídia que podem ser redimensionados (resizeableActivity="true"
). Redimensionável
os apps são compatíveis com mudanças de configuração do dispositivo e com o modo de várias janelas. Consulte
suporte a várias janelas).
Se o app não for redimensionável, ele vai precisar consultar os limites da tela em uma janela.
contexto e usar getMaximumWindowMetrics()
para recuperar o WindowMetrics
do
a á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();
Outros recursos
Para saber mais sobre projeção de mídia, consulte Capturar reproduções de vídeo e áudio.