Le API android.media.projection
introdotte in Android 5 (livello API 21) ti consentono di acquisire i contenuti del display di un dispositivo sotto forma di stream multimediale che puoi riprodurre, registrare o trasmettere ad altri dispositivi, ad esempio le TV.
Android 14 (livello API 34) introduce la condivisione schermo delle app, che consente agli utenti di condividere una singola finestra dell'app invece dell'intero schermo del dispositivo, indipendentemente dalla modalità finestra. La condivisione schermo delle app esclude la barra di stato, la barra di navigazione, le notifiche e altri elementi dell'interfaccia utente di sistema dalla visualizzazione condivisa, anche quando viene utilizzata la condivisione schermo delle app per acquisire un'app a schermo intero. Vengono condivisi solo i contenuti dell'app selezionata.
La condivisione schermo delle app garantisce la privacy degli utenti, aumenta la produttività degli utenti e migliora il multitasking consentendo agli utenti di eseguire più app, ma limitando la condivisione dei contenuti a una sola app.
Tre rappresentazioni del display
Una proiezione multimediale acquisisce i contenuti del display di un dispositivo o della finestra dell'app, quindi proietta l'immagine acquisita su un display virtuale che esegue il rendering dell'immagine su un elemento Surface
.
![Display di un dispositivo reale proiettato su un display virtuale. Contenuti del display virtuale scritti nel "Surface" fornito dall'applicazione.](https://cdn.statically.io/img/developer.android.com/static/media/images/grow/media-projection.png?hl=it)
Surface
fornito dall'applicazione.
L'applicazione fornisce Surface
tramite un elemento
MediaRecorder
,
SurfaceTexture
o
ImageReader
, che consuma
i contenuti del display acquisito e consente di gestire le immagini visualizzate
su Surface
in tempo reale. Puoi salvare le immagini come registrazione o trasmetterle
alla TV o a un altro dispositivo.
Display reale
Avvia una sessione di proiezione multimediale ottenendo un token che conceda alla tua app la capacità di acquisire i contenuti del display o della finestra dell'app del dispositivo. Il token è rappresentato da un'istanza della classe MediaProjection
.
Utilizza il metodo getMediaProjection()
del servizio di sistema MediaProjectionManager
per creare un'istanza MediaProjection
quando inizi una nuova attività. Avvia l'attività con un intent dal metodo createScreenCaptureIntent()
per specificare un'operazione di acquisizione schermata:
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());
Display virtuale
Il fulcro di una proiezione multimediale è il display virtuale, che crei chiamando
createVirtualDisplay()
su un'istanza 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);
I parametri width
e height
specificano le dimensioni del display virtuale. Per ottenere i valori per larghezza e altezza, utilizza le API WindowMetrics
introdotte in Android 11 (livello API 30). Per maggiori dettagli, consulta la sezione Dimensioni proiezione contenuti multimediali.
Surface
Ridimensiona la superficie di proiezione dei contenuti multimediali per produrre un output con la risoluzione appropriata. Utilizza dimensioni grandi (bassa risoluzione) per la trasmissione dello schermo alle TV o ai monitor dei computer e dimensioni ridotte (alta risoluzione) per la registrazione dal display dei dispositivi.
A partire da Android 12L (livello API 32), durante il rendering dei contenuti acquisiti sulla superficie, il sistema scala i contenuti in modo uniforme, mantenendo le proporzioni, in modo che entrambe le dimensioni (larghezza e altezza) siano uguali o inferiori alle dimensioni corrispondenti della superficie. I contenuti acquisiti vengono quindi centrati sulla superficie.
L'approccio alla scalabilità di Android 12L migliora la trasmissione dello schermo ai televisori e ad altri display di grandi dimensioni massimizzando le dimensioni dell'immagine superficiale, garantendo al contempo le proporzioni corrette.
Autorizzazione per i servizi in primo piano
Se la tua app ha come target Android 14 o versioni successive, il file manifest dell'app deve includere una
dichiarazione delle autorizzazioni per il
tipo di servizio in primo piano 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>
Avvia il servizio di proiezione di contenuti multimediali con una chiamata a startForeground()
.
Se non specifichi il tipo di servizio in primo piano nella chiamata, per impostazione predefinita sarà un numero intero a bit dei tipi di servizio in primo piano definiti nel manifest. Se
il manifest non specifica alcun tipo di servizio, il sistema genera
MissingForegroundServiceTypeException
.
Consenso degli utenti
L'app deve richiedere il consenso dell'utente prima di ogni sessione di proiezione di contenuti multimediali. Per sessione si intende una singola chiamata a createVirtualDisplay()
. Un token MediaProjection
deve essere utilizzato una sola volta per effettuare la chiamata.
Su Android 14 o versioni successive, il metodo createVirtualDisplay()
genera SecurityException
se la tua app esegue una delle seguenti operazioni:
- Passa un'istanza
Intent
restituita dacreateScreenCaptureIntent()
agetMediaProjection()
più di una volta - Richiama
createVirtualDisplay()
più volte nella stessa istanzaMediaProjection
Dimensioni di proiezione dei contenuti multimediali
Una proiezione multimediale può acquisire l'intero display del dispositivo o una finestra dell'app indipendentemente dalla modalità windowing.
Dimensione iniziale
Con la proiezione di contenuti multimediali a schermo intero, l'app deve determinare le dimensioni dello schermo del dispositivo. Nella condivisione schermo dell'app, l'app non sarà in grado di determinare le dimensioni del display acquisito finché l'utente non avrà selezionato la regione di acquisizione. Quindi, le dimensioni iniziali di qualsiasi proiezione di contenuti multimediali corrispondono alle dimensioni dello schermo del dispositivo.
Utilizza il metodo della piattaforma WindowManager
getMaximumWindowMetrics()
per restituire un oggetto
WindowMetrics
per lo
schermo del dispositivo anche se l'app host per la proiezione di contenuti multimediali è in modalità
multi-finestra e occupa solo una parte del display.
Per una compatibilità fino al livello API 14, usa il metodo WindowMetricsCalculator
computeMaximumWindowMetrics()
della libreria Jetpack WindowManager
.
Richiama il metodo WindowMetrics
getBounds()
per ottenere la larghezza e l'altezza del display del dispositivo.
Modifiche alle dimensioni
Le dimensioni della proiezione di contenuti multimediali possono cambiare quando il dispositivo viene ruotato o quando l'utente seleziona una finestra dell'app come regione di acquisizione nella condivisione schermo dell'app. La proiezione dei contenuti multimediali potrebbe essere modificata se i contenuti acquisiti hanno dimensioni diverse rispetto alle metriche di finestra massima ottenute al momento della configurazione della proiezione multimediale.
Per assicurarti che la proiezione dei contenuti multimediali sia in linea con le dimensioni dei contenuti acquisiti per qualsiasi regione acquisita e nelle rotazioni dei dispositivi, utilizza il callback onCapturedContentResize()
per ridimensionare l'acquisizione. Per ulteriori
informazioni, consulta la sezione Personalizzazione, riportata di seguito.
Funzionalità di
La tua app può personalizzare l'esperienza utente di proiezione di contenuti multimediali con le seguenti API di MediaProjection.Callback
:
onCapturedContentVisibilityChanged()
: consente all'app host (l'app che ha avviato la proiezione di contenuti multimediali) di mostrare o nascondere i contenuti condivisi.Utilizza questo callback per personalizzare l'interfaccia utente della tua app a seconda che la regione acquisita sia visibile all'utente. Ad esempio, se l'app è visibile all'utente e mostra i contenuti acquisiti nell'interfaccia utente dell'app e l'app acquisita è visibile anche all'utente (come indicato tramite questo callback), l'utente vede gli stessi contenuti due volte. Utilizza il callback per aggiornare l'interfaccia utente dell'app in modo da nascondere i contenuti acquisiti e liberare spazio di layout nell'app per gli altri contenuti.
onCapturedContentResize()
: consente all'app host di modificare le dimensioni della proiezione di contenuti multimediali sul display virtuale e sulla proiezione di contenuti multimedialiSurface
in base alle dimensioni della regione di visualizzazione acquisita.Si attiva ogni volta che i contenuti acquisiti (una singola finestra dell'app o l'intero display del dispositivo) cambiano dimensione (a causa della rotazione del dispositivo o dell'ingresso dell'app acquisita in una modalità windowing diversa). Utilizza questa API per ridimensionare sia il display virtuale sia la superficie per assicurarti che le proporzioni corrispondano ai contenuti acquisiti e che l'acquisizione non sia letterbox.
Recupero delle risorse
La tua app deve registrare il callback MediaProjection
onStop()
per rilasciare risorse in possesso dell'app, ad esempio il display virtuale e
la superficie di proiezione.
Il callback viene chiamato quando termina la proiezione di contenuti multimediali o quando l'utente non concede il consenso per continuare una sessione di acquisizione.
Se la tua app non registra il callback e l'utente non concede il consenso alla
sessione di proiezione multimediale, le chiamate a createVirtualDisplay()
generano
IllegalStateException
.
Disattiva
Android 14 o versioni successive abilita la condivisione schermo delle app per impostazione predefinita. Ogni sessione di proiezione di contenuti multimediali offre agli utenti la possibilità di condividere una finestra dell'app o l'intero display.
La tua app può disattivare la condivisione schermo delle app chiamando il metodo createScreenCaptureIntent(MediaProjectionConfig)
con un argomento MediaProjectionConfig
restituito da una chiamata a createConfigForDefaultDisplay()
.
Una chiamata a createScreenCaptureIntent(MediaProjectionConfig)
con un argomento MediaProjectionConfig
restituito da una chiamata a createConfigForUserChoice()
equivale al comportamento predefinito, ovvero una chiamata a createScreenCaptureIntent()
.
App ridimensionabili
Rendi sempre ridimensionabili le app di proiezione di contenuti multimediali (resizeableActivity="true"
). Le app ridimensionabili supportano le modifiche alla configurazione del dispositivo e la modalità multi-finestra (vedi Supporto della modalità multi-finestra).
Se l'app non è ridimensionabile, deve eseguire una query sui limiti di visualizzazione dal contesto di una finestra e utilizzare getMaximumWindowMetrics()
per recuperare il valore WindowMetrics
dell'area di visualizzazione massima disponibile per l'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();
Risorse aggiuntive
Per ulteriori informazioni sulla proiezione di contenuti multimediali, consulta Acquisire la riproduzione video e audio.