Medienprojektion

Mit den android.media.projection APIs, die in Android 5 (API-Level 21) eingeführt wurden, können Sie die Inhalte eines Gerätedisplays als Media-Stream erfassen, den Sie wiedergeben, aufzeichnen oder auf andere Geräte wie Fernseher übertragen können.

In Android 14 (API-Level 34) wurde die App-Bildschirmfreigabe eingeführt. Damit können Nutzer ein einzelnes App-Fenster anstelle des gesamten Gerätedisplays freigeben, unabhängig vom Fenstermodus. Bei der App-Bildschirmfreigabe werden die Statusleiste, die Navigationsleiste, Benachrichtigungen und andere System-UI-Elemente aus der freigegebenen Anzeige ausgeschlossen – auch wenn die App-Bildschirmfreigabe verwendet wird, um eine App im Vollbildmodus zu erfassen. Es werden nur die Inhalte der ausgewählten App freigegeben.

Die App-Bildschirmfreigabe schützt die Privatsphäre der Nutzer, steigert die Produktivität und verbessert das Multitasking, da Nutzer mehrere Apps ausführen, die Freigabe von Inhalten aber auf eine einzelne App beschränken können.

Drei Darstellungen

Bei einer Projektion von Medieninhalten werden die Inhalte eines Gerätedisplays oder App-Fensters erfasst und dann auf ein virtuelles Display projiziert, das das Bild auf einem Surface rendert.

Die Anzeige des echten Geräts wird auf das virtuelle Display projiziert. Inhalte des virtuellen Displays, die in die von der Anwendung bereitgestellte „Surface“ geschrieben werden.
Abbildung 1 Gerätedisplay oder App-Fenster, das auf ein virtuelles Display projiziert wird. Virtuelles Display, das in eine von der Anwendung bereitgestellte Surface geschrieben wird.

Die Anwendung stellt die Surface über einen MediaRecorder, SurfaceTexture oder ImageReader bereit, der die Inhalte des erfassten Displays verwendet und Ihnen ermöglicht, Bilder, die auf der Surface gerendert werden, in Echtzeit zu verwalten. Sie können die Bilder als Aufzeichnung speichern oder auf einen Fernseher oder ein anderes Gerät übertragen.

Gerätedisplay

Starten Sie eine Projektion von Medieninhalten, indem Sie ein Token abrufen, mit dem Ihre App die Inhalte des Gerätedisplays oder App-Fensters erfassen kann. Das Token wird durch eine Instanz der MediaProjection Klasse dargestellt.

Verwenden Sie die getMediaProjection() Methode des MediaProjectionManager Systemdienstes, um eine MediaProjection Instanz zu erstellen, wenn Sie eine neue Aktivität starten. Starten Sie die Aktivität mit einem Intent aus der createScreenCaptureIntent() Methode, um eine Bildschirmaufnahme anzugeben:

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 startMediaProjection = registerForActivityResult( new StartActivityForResult(), result -> { if (result.getResultCode() == Activity.RESULT_OK) { mediaProjection[0] = mediaProjectionManager .getMediaProjection(result.getResultCode(), result.getData()); } } );
startMediaProjection.launch(mediaProjectionManager.createScreenCaptureIntent());

Virtuelles Display

Das Herzstück einer Projektion von Medieninhalten ist das virtuelle Display, das Sie durch Aufrufen von createVirtualDisplay() für eine MediaProjection Instanz erstellen:

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);

Die Parameter width und height geben die Abmessungen des virtuellen Displays an. Verwenden Sie die WindowMetrics APIs eingeführten in Android 11 (API-Level 30), um Werte für Breite und Höhe zu erhalten. Weitere Informationen finden Sie im Abschnitt Größe der Projektion von Medieninhalten.

Surface

Passen Sie die Größe der Oberfläche für die Projektion von Medieninhalten an, um eine Ausgabe mit der entsprechenden Auflösung zu erzeugen. Machen Sie die Oberfläche groß (niedrige Auflösung) für die Bildschirmübertragung auf Fernseher oder Computermonitore und klein (hohe Auflösung) für die Aufzeichnung des Gerätedisplays.

Ab Android 12L (API-Level 32) skaliert das System beim Rendern erfasster Inhalte auf der Oberfläche die Inhalte einheitlich, wobei das Seitenverhältnis beibehalten wird, sodass beide Abmessungen der Inhalte (Breite und Höhe) kleiner oder gleich den entsprechenden Abmessungen der Oberfläche sind. Die erfassten Inhalte werden dann auf der Oberfläche zentriert.

Der Skalierungsansatz von Android 12L verbessert die Bildschirmübertragung auf Fernseher und andere große Displays, indem die Größe des Oberflächenbilds maximiert wird und gleichzeitig das richtige Seitenverhältnis beibehalten wird.

Berechtigung für Dienste im Vordergrund

Wenn Ihre App auf Android 14 oder höher ausgerichtet ist, muss das App-Manifest eine Berechtigungserklärung für den mediaProjection Diensttyp im Vordergrund enthalten:

<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>

Starten Sie den Dienst zur Projektion von Medieninhalten mit einem Aufruf von startForeground().

Wenn Sie den Diensttyp im Vordergrund nicht im Aufruf angeben, wird standardmäßig eine bitweise Ganzzahl der im Manifest definierten Diensttypen im Vordergrund verwendet. Wenn im Manifest keine Diensttypen angegeben sind, löst das System MissingForegroundServiceTypeException aus.

Ihre App muss vor jeder Projektion von Medieninhalten die Nutzereinwilligung einholen. Eine Sitzung ist ein einzelner Aufruf von createVirtualDisplay(). Ein MediaProjection-Token darf nur einmal für den Aufruf verwendet werden.

Unter Android 14 oder höher löst die createVirtualDisplay() Methode eine SecurityException aus, wenn Ihre App eine der folgenden Aktionen ausführt:

  • Übergibt eine Intent-Instanz, die von createScreenCaptureIntent() an getMediaProjection() zurückgegeben wurde, mehr als einmal.
  • Ruft createVirtualDisplay() mehr als einmal für dieselbe MediaProjection-Instanz auf.

Größe der Medienprojektion

Eine Projektion von Medieninhalten kann das gesamte Gerätedisplay oder ein App-Fenster erfassen, unabhängig vom Fenstermodus.

Anfangsgröße

Bei der Vollbild-Projektion von Medieninhalten muss Ihre App die Größe des Gerätedisplays ermitteln. Bei der App-Bildschirmfreigabe kann Ihre App die Größe des erfassten Displays erst ermitteln, nachdem der Nutzer den Erfassungsbereich ausgewählt hat. Die Anfangsgröße einer Projektion von Medieninhalten entspricht also der Größe des Gerätedisplays.

Verwenden Sie die Methode WindowManager getMaximumWindowMetrics(), um ein WindowMetrics-Objekt für das Gerätedisplay zurückzugeben, auch wenn die Host-App für die Medienprojektion im Multifenster-Modus ausgeführt wird und nur einen Teil des Displays einnimmt.

Für die Kompatibilität bis API-Level 14 verwenden Sie die WindowMetricsCalculator computeMaximumWindowMetrics() Methode aus der Jetpack WindowManager Bibliothek.

Rufen Sie die WindowMetrics getBounds()-Methode auf, um die Breite und Höhe von dem Gerätedisplay zu erhalten.

Größenänderungen

Die Größe der Projektion von Medieninhalten kann sich ändern, wenn das Gerät gedreht wird oder der Nutzer bei der App-Bildschirmfreigabe ein App-Fenster als Erfassungsbereich auswählt. Die Projektion von Medieninhalten kann Letterboxing aufweisen, wenn die Größe des erfassten Inhalts von den maximalen Fensterabmessungen abweicht, die bei der Einrichtung der Projektion von Medieninhalten ermittelt wurden.

Verwenden Sie den Callback onCapturedContentResize(), um die Größe der Erfassung anzupassen, damit die Projektion von Medieninhalten für jeden erfassten Bereich und bei jeder Drehung des Geräts genau an die Größe des erfassten Inhalts angepasst wird. Weitere Informationen finden Sie im folgenden Abschnitt Anpassung.

Anpassung

Ihre App kann die Nutzererfahrung bei der Projektion von Medieninhalten mit den folgenden MediaProjection.Callback APIs anpassen:

  • onCapturedContentVisibilityChanged(): Ermöglicht der Host-App (der App, die die Projektion von Medieninhalten gestartet hat), die freigegebenen Inhalte ein- oder auszublenden.

    Verwenden Sie diesen Callback, um die UI Ihrer App anzupassen, je nachdem, ob der erfasste Bereich für den Nutzer sichtbar ist. Wenn Ihre App beispielsweise für den Nutzer sichtbar ist und die erfassten Inhalte in der UI der App angezeigt werden und die erfasste App auch für den Nutzer sichtbar ist (wie durch diesen Callback angegeben), sieht der Nutzer dieselben Inhalte zweimal. Verwenden Sie den Callback, um die UI Ihrer App zu aktualisieren, damit die erfassten Inhalte ausgeblendet werden und in Ihrer App Platz für andere Inhalte geschaffen wird.

  • onCapturedContentResize(): Ermöglicht der Host-App, die Größe der Projektion von Medieninhalten auf dem virtuellen Display und der Surface für die Projektion von Medieninhalten basierend auf der Größe des erfassten Displaybereichs zu ändern.

    Wird immer dann ausgelöst, wenn sich die Größe des erfassten Inhalts ändert – entweder ein einzelnes App-Fenster oder das gesamte Gerätedisplay (z. B. aufgrund einer Drehung des Geräts oder weil die erfasste App in einen anderen Fenstermodus wechselt). Verwenden Sie diese API, um sowohl das virtuelle Display als auch die Oberfläche anzupassen, damit das Seitenverhältnis dem erfassten Inhalt entspricht und die Erfassung kein Letterboxing aufweist.

Ressourcenwiederherstellung

Ihre App sollte den MediaProjection onStop()-Callback registrieren, um benachrichtigt zu werden, wenn die Projektion von Medieninhalten-Sitzung beendet wird und ungültig wird. Wenn die Sitzung beendet wird, sollte Ihre App die von ihr gehaltenen Ressourcen freigeben, z. B. das virtuelle Display und die Projektionsoberfläche. Bei einer beendeten Projektion von Medieninhalten-Sitzung kann kein neues virtuelles Display erstellt werden, auch wenn Ihre App zuvor kein virtuelles Display für diese Projektion von Medieninhalten erstellt hat.

Das System ruft den Callback auf, wenn die Projektion von Medieninhalten beendet wird. Das kann verschiedene Ursachen haben, z. B.:

  • Der Nutzer beendet die Sitzung über die UI der App oder das Chip in der Statusleiste für die Medien projektion des Systems.
  • Der Bildschirm wird gesperrt.
  • Eine weitere Projektion von Medieninhalten wird gestartet.
  • Der App-Prozess wird beendet.

Wenn Ihre App den Callback nicht registriert, löst jeder Aufruf von createVirtualDisplay() IllegalStateException aus.

Deaktivieren

Unter Android 14 oder höher ist die App-Bildschirmfreigabe standardmäßig aktiviert. Bei jeder Medienprojektionssitzung können Nutzer ein App-Fenster oder das gesamte Display freigeben.

Ihre App kann die App-Bildschirmfreigabe deaktivieren, indem sie die createScreenCaptureIntent(MediaProjectionConfig) Methode mit einem MediaProjectionConfig Argument aufruft, das von einem Aufruf an createConfigForDefaultDisplay() zurückgegeben wird.

Ein Aufruf von createScreenCaptureIntent(MediaProjectionConfig) mit einem MediaProjectionConfig Argument, das von einem Aufruf von createConfigForUserChoice() zurückgegeben wird, entspricht dem Standardverhalten, d. h. einem Aufruf von createScreenCaptureIntent().

Größenänderbare Apps

Machen Sie Ihre Apps zur Projektion von Medieninhalten immer größenänderbar (resizeableActivity="true"). Größenänderbare Apps unterstützen Änderungen an der Gerätekonfiguration und den Mehrfenstermodus (siehe Mehrfenster-Unterstützung).

Wenn Ihre App nicht größenänderbar ist, muss sie die Displaygrenzen aus einem Fenster kontext abfragen und getMaximumWindowMetrics() verwenden, um die WindowMetrics des maximalen Anzeigebereichs abzurufen, der für die App verfügbar ist :

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();

Chip in der Statusleiste und automatische Beendigung

Bei Ausnutzung von Bildschirmprojektion werden personenbezogene Nutzerdaten wie Finanzinformationen offengelegt, da Nutzer nicht wissen, dass ihr Gerätebildschirm geteilt wird.

Bei Apps, die auf Geräten mit Android 15 QPR1 oder höher ausgeführt werden, werden Nutzer über einen großen und gut sichtbaren Chip in der Statusleiste über eine laufende Bildschirmprojektion informiert. Nutzer können auf den Chip tippen, um zu verhindern, dass ihr Bildschirm geteilt, gestreamt oder aufgezeichnet wird. Außerdem wird die Bildschirmprojektion automatisch beendet, wenn das Display des Geräts gesperrt wird.

Abbildung 2 Chip in der Statusleiste für Bildschirmfreigabe, Übertragung und Aufzeichnung.

Testen Sie die Verfügbarkeit des Chips in der Statusleiste für die Projektion von Medieninhalten, indem Sie die Bildschirmfreigabe, die Übertragung oder die Aufzeichnung starten. Der Chip sollte in der Statusleiste angezeigt werden.

So sorgen Sie dafür, dass Ihre App Ressourcen freigibt und die UI aktualisiert, wenn die Bildschirmprojektion durch Nutzerinteraktion mit dem Chip in der Statusleiste oder durch Aktivierung des Sperrbildschirms beendet wird:

  • Erstellen Sie eine Instanz von MediaProjection.Callback.

  • Implementieren Sie die Callback onStop() Methode. Die Methode wird aufgerufen, wenn die Bildschirmprojektion beendet wird. Geben Sie alle Ressourcen frei, die Ihre App verwendet, und aktualisieren Sie die App-UI nach Bedarf.

Wenn Sie den Callback testen möchten, tippen Sie auf den Chip in der Statusleiste oder sperren Sie das Gerätedisplay, um die Bildschirmprojektion zu beenden. Prüfen Sie, ob die Methode onStop() aufgerufen wird und Ihre App wie beabsichtigt reagiert.

Zusätzliche Ressourcen

Weitere Informationen zur Projektion von Medieninhalten finden Sie unter Video- und Audiowiedergabe erfassen.