Medienprojektion

Mit den in Android 5 (API-Level 21) eingeführten android.media.projection APIs kannst du den Inhalt einer Geräteanzeige als Medienstream erfassen, den du abspielen, aufnehmen oder auf andere Geräte wie Fernseher streamen kannst.

Mit Android 14 (API-Level 34) wird die App-Bildschirmfreigabe eingeführt. Damit können Nutzer unabhängig vom Fenstermodus ein einzelnes App-Fenster statt des gesamten Gerätebildschirms teilen. Bei der App-Bildschirmfreigabe sind Statusleiste, Navigationsleiste, Benachrichtigungen und andere Elemente der System-UI vom gemeinsam genutzten Bildschirm ausgeschlossen – auch dann, wenn die App-Bildschirmfreigabe verwendet wird, um eine App im Vollbildmodus aufzunehmen. Nur die Inhalte der ausgewählten App werden geteilt.

Die App-Bildschirmfreigabe sorgt für Datenschutz, steigert die Produktivität der Nutzer und verbessert das Multitasking, da Nutzer mehrere Apps ausführen können, die Freigabe von Inhalten aber auf eine einzige App beschränkt ist.

Drei Displaydarstellungen

Eine Medienprojektion erfasst den Inhalt eines Gerätedisplays oder App-Fensters und projiziert das aufgenommene Bild auf einen virtuellen Bildschirm, der das Bild auf einem Surface rendert.

Eine echte Geräteanzeige wird auf ein virtuelles Display projiziert. Inhalte der virtuellen Anzeige, die in der von der Anwendung bereitgestellten „Surface“ geschrieben wurde.
Abbildung 1: Ein echter Gerätebildschirm oder ein echtes App-Fenster, das auf eine virtuelle Anzeige projiziert wird. Virtuelle Anzeige, die in die von der Anwendung bereitgestellte Surface geschrieben wird.

Die Anwendung stellt die Surface über MediaRecorder, SurfaceTexture oder ImageReader bereit, die den Inhalt des aufgenommenen Displays nutzt und es dir ermöglicht, auf dem Surface gerenderte Bilder in Echtzeit zu verwalten. Sie können die Bilder als Aufnahme speichern oder auf einen Fernseher oder ein anderes Gerät streamen.

Echte Displayanzeige

Starten Sie eine Sitzung zur Medienprojektion. Rufen Sie dazu ein Token ab, mit dem Ihre App den Inhalt der Geräteanzeige oder des App-Fensters erfassen kann. Das Token wird durch eine Instanz der Klasse MediaProjection dargestellt.

Verwenden Sie die Methode getMediaProjection() des Systemdienstes MediaProjectionManager, um beim Starten einer neuen Aktivität eine MediaProjection-Instanz zu erstellen. Starten Sie die Aktivität mit einem Intent aus der Methode createScreenCaptureIntent(), um einen Bildschirmerfassungsvorgang 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<Intent> 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 Medienprojektion ist die virtuelle Anzeige, die Sie erstellen, indem Sie auf einer MediaProjection-Instanz createVirtualDisplay() aufrufen:

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 der virtuellen Anzeige an. Werte für Breite und Höhe kannst du mit den WindowMetrics APIs erhalten, die in Android 11 (API-Level 30) eingeführt wurden. Weitere Informationen finden Sie im Abschnitt Größe der Medienprojektion.

Surface

Passen Sie die Größe der Projektionsfläche an, um die Ausgabe in der richtigen Auflösung zu produzieren. Gestalten Sie die Oberfläche für das Streamen von Bildschirmen auf Fernseher oder Computerbildschirme groß (niedrige Auflösung) und klein (hohe Auflösung) für die Aufzeichnung des Gerätebildschirms.

Ab Android 12L (API-Level 32) skaliert das System beim Rendern erfasster Inhalte auf der Oberfläche den Inhalt gleichmäßig unter Beibehaltung des Seitenverhältnisses, sodass beide Abmessungen des Inhalts (Breite und Höhe) gleich oder kleiner als die entsprechenden Abmessungen der Oberfläche sind. Der aufgenommene Inhalt wird dann auf der Oberfläche zentriert.

Der Skalierungsansatz von Android 12L verbessert die Bildschirmübertragung auf Fernsehgeräte und andere große Bildschirme, indem die Größe des Oberflächenbilds maximiert und gleichzeitig das richtige Seitenverhältnis sichergestellt 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 Diensttyp mediaProjection 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 Medienprojektionsdienst mit einem Aufruf von startForeground().

Wenn Sie im Aufruf keinen Diensttyp im Vordergrund angeben, wird standardmäßig eine bitweise Ganzzahl der Typen von Diensten im Vordergrund verwendet, die im Manifest definiert sind. Wenn im Manifest keine Diensttypen angegeben sind, gibt das System MissingForegroundServiceTypeException aus.

Ihre App muss vor jeder Sitzung der Medienprojektion 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 gibt die Methode createVirtualDisplay() ein SecurityException aus, wenn Ihre App eine der folgenden Aktionen ausführt:

  • Übergibt eine von createScreenCaptureIntent() zurückgegebene Intent-Instanz mehrmals an getMediaProjection()
  • Ruft createVirtualDisplay() mehrmals in derselben MediaProjection-Instanz auf

Größe der Medienprojektion

Eine Medienprojektion kann unabhängig vom Windowing-Modus den gesamten Bildschirm des Geräts oder ein App-Fenster erfassen.

Anfangsgröße

Bei der Medienprojektion im Vollbildmodus muss Ihre App die Größe des Gerätebildschirms bestimmen. Bei der App-Bildschirmfreigabe kann die App die Größe des aufgenommenen Displays erst dann ermitteln, wenn der Nutzer den Aufnahmebereich ausgewählt hat. Die anfängliche Größe einer Medienprojektion entspricht also der Größe des Gerätebildschirms.

Verwenden Sie die Methode WindowManager getMaximumWindowMetrics() der Plattform, um ein WindowMetrics-Objekt für den Gerätebildschirm zurückzugeben, auch wenn sich die Host-App für die Medienprojektion im Mehrfenstermodus befindet und nur einen Teil des Bildschirms einnimmt.

Verwenden Sie für die Kompatibilität bis hin zu API-Level 14 die Methode WindowMetricsCalculator computeMaximumWindowMetrics() aus der Jetpack-Bibliothek WindowManager.

Rufen Sie die Methode WindowMetrics getBounds() auf, um die Breite und Höhe des Gerätedisplays zu erhalten.

Größenänderungen

Die Größe der Medienprojektion kann sich ändern, wenn das Gerät gedreht wird oder der Nutzer bei der App-Bildschirmfreigabe ein App-Fenster als Aufnahmebereich auswählt. Die Medienprojektion kann im Letterbox-Format dargestellt werden, wenn der erfasste Inhalt eine andere Größe als die Messwerte für das maximale Fenster hat, die bei der Einrichtung der Medienprojektion ermittelt wurden.

Damit die Medienprojektion für jede erfasste Region und über Geräterotationen hinweg genau mit der Größe des erfassten Inhalts übereinstimmt, verwenden Sie den onCapturedContentResize()-Callback, um die Größe der Aufnahme anzupassen. Weitere Informationen finden Sie im nachfolgenden Abschnitt Anpassung.

Anpassbare

Ihre App kann die Medienprojektion über die folgenden MediaProjection.Callback APIs anpassen:

  • onCapturedContentVisibilityChanged(): Dadurch kann die Host-App, also die App, die die Medienprojektion gestartet hat, geteilte Inhalte ein- oder ausblenden.

    Mit diesem Callback können Sie die UI Ihrer App abhängig davon anpassen, ob der erfasste Bereich für den Nutzer sichtbar ist. Wenn Ihre Anwendung beispielsweise für den Nutzer sichtbar ist und den aufgenommenen Inhalt in der Benutzeroberfläche der Anwendung anzeigt und die erfasste Anwendung auch für den Nutzer sichtbar ist (wie durch diesen Callback angegeben), sieht der Nutzer denselben Inhalt zweimal. Verwende den Callback, um die Benutzeroberfläche deiner App zu aktualisieren, um die aufgenommenen Inhalte auszublenden und Layoutbereich in deiner App für andere Inhalte freizugeben.

  • onCapturedContentResize(): Ermöglicht der Host-App, die Größe der Medienprojektion auf dem virtuellen Display und der Medienprojektion Surface basierend auf der Größe des erfassten Anzeigebereichs zu ändern.

    Wird ausgelöst, wenn sich die Größe des aufgenommenen Inhalts – eines einzelnen App-Fensters oder einer vollständigen Geräteanzeige – ändert (aufgrund der Gerätedrehung oder wenn die erfasste App in einen anderen Windowing-Modus wechselt). Mit dieser API können Sie die Größe des virtuellen Displays und der Oberfläche anpassen. So sorgen Sie dafür, dass das Seitenverhältnis dem erfassten Inhalt entspricht und die Aufnahme nicht im Letterbox-Format dargestellt wird.

Ressourcenwiederherstellung

Ihre App sollte den MediaProjection onStop()-Callback registrieren, um die von der App bereitgestellten Ressourcen freizugeben, z. B. die virtuelle Anzeige und die Projektionsoberfläche.

Der Callback wird aufgerufen, wenn die Medienprojektion beendet wird oder wenn der Nutzer keine Einwilligung zum Fortsetzen einer Erfassungssitzung erteilt.

Wenn Ihre App den Callback nicht registriert und der Nutzer der Medienprojektionssitzung nicht zustimmt, lösen createVirtualDisplay()-Aufrufe IllegalStateException aus.

Widerrufen

Unter Android 14 oder höher ist die App-Bildschirmfreigabe standardmäßig aktiviert. Bei jeder Sitzung zur Medienprojektion haben Nutzer die Möglichkeit, ein App-Fenster oder den gesamten Bildschirm zu teilen.

Ihre App kann die App-Bildschirmfreigabe deaktivieren. Dazu rufen Sie die Methode createScreenCaptureIntent(MediaProjectionConfig) mit dem Argument MediaProjectionConfig auf, das von einem Aufruf an createConfigForDefaultDisplay() zurückgegeben wird.

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

Apps mit anpassbarer Größe

Achten Sie darauf, dass die Größe Ihrer Apps zur Projektion von Mediendateien immer angepasst werden kann (resizeableActivity="true"). Apps mit anpassbarer Größe unterstützen Gerätekonfigurationsänderungen und den Mehrfenstermodus. Weitere Informationen finden Sie unter Unterstützung des Mehrfenstermodus.

Wenn die Größe Ihrer App nicht geändert werden kann, muss sie die Anzeigegrenzen aus einem Fensterkontext abfragen und getMaximumWindowMetrics() verwenden, um den 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();

Weitere Informationen

Weitere Informationen zur Medienprojektion finden Sie unter Video- und Audiowiedergabe aufnehmen.