Wyświetlanie multimediów

android.media.projection Interfejsy API wprowadzone w Androidzie 5 (poziom API 21) umożliwiają przechwytywanie treści wyświetlacza urządzenia jako strumienia multimediów, na który można odtwarzać, nagrywać lub przesyłać na innych urządzeniach, takich jak telewizory.

Android 14 (poziom interfejsu API 34) wprowadza udostępnianie ekranu aplikacji, udostępniać okno aplikacji zamiast całego ekranu urządzenia niezależnie od tego, w trybie okien. Udostępnianie ekranu aplikacji nie obejmuje paska stanu, paska nawigacyjnego, powiadomień i innych elementów interfejsu systemu ze wspólnego wyświetlacza – nawet gdy udostępnianie ekranu aplikacji jest używane do przechwytywania jej na pełnym ekranie. Udostępniana jest tylko zawartość wybranej aplikacji.

Udostępnianie ekranu aplikacji zapewnia prywatność użytkowników, zwiększa produktywność usprawnia wielozadaniowość, umożliwiając użytkownikom uruchamianie wielu aplikacji, udostępnianie treści tylko w jednej aplikacji.

Trzy sposoby wyświetlania

W ramach wyświetlania multimediów rejestruje się zawartość wyświetlacza urządzenia lub okna aplikacji a następnie rzutuje zarejestrowany obraz na wyświetlacz wirtualny, na którym jest on wyświetlany Surface.

Wyświetlacz rzeczywistego urządzenia wyświetlany na wyświetlaczu wirtualnym. Zawartość
              wyświetlacz wirtualny zapisany w usłudze „Surface” udostępnionej przez aplikację.
Rysunek 1. Ekran prawdziwego urządzenia lub okno aplikacji wyświetlane na wirtualny wyświetlacz. Wyświetlacz wirtualny zapisany w udostępnionym przez aplikację Surface

Aplikacja udostępnia Surface za pomocą MediaRecorder SurfaceTexture lub ImageReader, która zużywa zawartości rejestrowanego ekranu i umożliwia zarządzanie wyrenderowanymi obrazami na urządzeniu Surface w czasie rzeczywistym. Możesz zapisać obrazy jako nagranie lub przesyłanie na telewizor lub inne urządzenie.

Prawdziwa reklama displayowa

Rozpocznij sesję wyświetlania multimediów, uzyskując token, który przyzna Twojej aplikacji możliwość rejestrowania zawartości wyświetlacza urządzenia lub okna aplikacji. Token jest reprezentowana przez wystąpienie MediaProjection zajęcia.

Użyj metody getMediaProjection() do usługa systemowa MediaProjectionManager, aby utworzyć instancję MediaProjection gdy rozpoczynasz nową aktywność. Rozpocznij aktywność od intencji z Metoda createScreenCaptureIntent() określająca ekran operacja przechwytywania:

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

Wyświetlacz wirtualny

Podstawą wyświetlania multimediów jest wyświetlacz wirtualny, Połączenie createVirtualDisplay() w instancji 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);

Parametry width i height określają wymiary obiektu wirtualnego wyświetlacz. Aby uzyskać wartości szerokości i wysokości, użyj funkcji Wprowadzone interfejsy API WindowMetrics w Androidzie 11 (poziom API 30). (Aby dowiedzieć się więcej, zobacz Rozmiar wyświetlania multimediów).

Natynkowe

Dobierz odpowiedni rozmiar powierzchni projekcji multimediów, i ich rozwiązania. Ustaw dużą powierzchnię (niską rozdzielczość), aby umożliwić przesyłanie ekranu na telewizory. z małymi monitorami (w wysokiej rozdzielczości) do nagrywania na wyświetlaczu urządzenia.

Od Androida 12L (poziom interfejsu API 32) w przypadku renderowania przechwyconych treści system równomiernie skaluje treści z zachowaniem współczynnika proporcji. aby oba wymiary treści (szerokość i wysokość) były równe lub mniejsze niż analogiczne wymiary powierzchni. Przechwycona zawartość jest następnie jest wyśrodkowany na powierzchni.

Skalowanie Androida 12L poprawia przesyłanie ekranu na telewizory na innych dużych ekranach, maksymalizując rozmiar obrazu powierzchni, jednocześnie z odpowiednim współczynnikiem proporcji.

Uprawnienia usługi na pierwszym planie

Jeśli Twoja aplikacja jest kierowana na Androida 14 lub nowszego, plik manifestu musi zawierać deklaracja uprawnień dla mediaProjection Typ usługi na pierwszym planie:

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

Uruchom usługę wyświetlania multimediów, wywołując metodę startForeground().

Jeśli w wywołaniu nie określisz typu usługi na pierwszym planie, domyślnie zostanie określony typ do bitowej liczby całkowitej typów usług na pierwszym planie zdefiniowanych w pliku manifestu. Jeśli w pliku manifestu nie określono żadnych typów usług, system generuje MissingForegroundServiceTypeException.

Twoja aplikacja musi prosić użytkownika o zgodę przed każdą sesją wyświetlania multimediów. O sesja to pojedyncze wywołanie do funkcji createVirtualDisplay(). Token MediaProjection należy użyć tylko raz w celu nawiązania połączenia.

W Androidzie 14 lub nowszym metoda createVirtualDisplay() generuje błąd SecurityException, jeśli wykonuje jedną z tych czynności:

  • Przekazuje instancję Intent zwrócona z createScreenCaptureIntent() do getMediaProjection() więcej niż raz
  • Dzwoni do createVirtualDisplay() więcej niż raz w tym samym urządzeniu MediaProjection instancja

Rozmiar wyświetlania multimediów

W ramach wyświetlania multimediów można rejestrować cały wyświetlacz urządzenia lub okno aplikacji bez względu na tryb okna.

Rozmiar początkowy

W przypadku wyświetlania multimediów na pełnym ekranie aplikacja musi określić rozmiar ekranu urządzenia. Podczas udostępniania ekranu aplikacji aplikacja nie jest w stanie określić wielkości wyświetlanego obrazu do czasu, aż użytkownik wybierze region przechwytywania. Początkowy rozmiar każdego projekcji multimediów jest więc rozmiarem ekranu urządzenia.

Skorzystaj z platformy WindowManager metody getMaximumWindowMetrics(), która zwraca WindowMetrics dla ekranu urządzenia, nawet jeśli aplikacja hostująca wyświetlanie multimediów działa w trybie wielu okien. zajmuje tylko część ekranu.

Aby uzyskać zgodność do poziomu interfejsu API 14, użyj interfejsu WindowMetricsCalculator computeMaximumWindowMetrics() z biblioteki Jetpack WindowManager.

Wywołaj metodę WindowMetrics getBounds(), aby uzyskać szerokość i wysokość wyświetlacza urządzenia.

Zmiany rozmiaru

Rozmiar projekcji multimediów może się zmieniać, gdy obrócisz urządzenie lub użytkownik wybiera okno aplikacji jako region zrzutu ekranu podczas udostępniania ekranu aplikacji. Na obrazie mogą być widoczne czarne pasy, jeśli przechwycony materiał jest rozmiar inny niż maksymalne wskaźniki okna uzyskane, gdy – skonfigurowano projekcję.

Aby projekcja multimediów była dokładnie dopasowana do dla dowolnego przechwyconego regionu i obrotu urządzenia, użyj onCapturedContentResize() wywołanie zwrotne w celu zmiany rozmiaru zapisu. (Więcej więcej informacji znajdziesz w sekcji Dostosowywanie poniżej).

Dostosowywanie

Aplikacja może dostosować środowisko wyświetlania multimediów za pomocą tych opcji: Interfejsy API MediaProjection.Callback:

  • onCapturedContentVisibilityChanged(): Umożliwia wyświetlanie lub wyświetlanie w aplikacji hostującej (aplikacji, która rozpoczęła wyświetlanie multimediów) ukryć udostępnioną treść.

    To wywołanie zwrotne pozwala dostosować interfejs aplikacji zależnie od tego, czy przechwycony region jest widoczny dla użytkownika. Jeśli na przykład Twoja aplikacja jest widoczna dla: użytkownika i wyświetla przechwyconą zawartość w interfejsie aplikacji, przechwycona aplikacja jest również widoczna dla użytkownika (zgodnie z tym wywołania zwrotnego), użytkownik zobaczy tę samą treść dwukrotnie. Aby zaktualizować, użyj wywołania zwrotnego UI aplikacji, aby ukryć zapisane treści i zwolnić miejsce w przypadku innych treści.

  • onCapturedContentResize(): Pozwala aplikacji hostującej zmieniać rozmiar projekcji multimediów w środowisku wirtualnym i wyświetlanie multimediów Surface w zależności od rozmiaru przechwyconych region wyświetlania.

    Wywoływane za każdym razem, gdy przechwycona zawartość – pojedyncze okno aplikacji lub pełne wyświetlacz urządzenia – zmienia rozmiar (pod wpływem obrotu urządzenia lub przejście w inny tryb okna). Za pomocą tego interfejsu API możesz zmienić rozmiar wirtualnego wyświetlacza i powierzchni, aby zapewnić zgodność współczynnika proporcji na zdjęciu nie ma czarnych pasów bądź zdjęcie.

Odzyskiwanie zasobów

Aplikacja powinna rejestrować MediaProjection onStop(). wywołanie zwrotne, aby otrzymać informację, kiedy sesja wyświetlania multimediów zostanie zatrzymana i staje się jest nieprawidłowa. Po zatrzymaniu sesji aplikacja powinna zwolnić zasoby, które takich jak wirtualny wyświetlacz i powierzchnia projekcji. Zatrzymano A w trakcie sesji wyświetlania multimediów nie można już utworzyć nowego wyświetlacza wirtualnego, aplikacja nie utworzyła wcześniej wyświetlacza wirtualnego dla tego projekcji multimediów.

Wywołanie zwrotne jest wywoływane po zakończeniu wyświetlania multimediów, ponieważ użytkownik ręcznie zatrzymasz sesję lub system zatrzyma ją z jakiegoś powodu.

Jeśli aplikacja nie zarejestruje wywołania zwrotnego, każde wywołanie createVirtualDisplay() rzuty IllegalStateException.

Zrezygnuj

Android 14 lub nowszy włącza udostępnianie ekranu aplikacji domyślnie. Każdy plik multimedialny sesja projekcji umożliwia użytkownikom udostępnienie okna aplikacji lub cały ekran.

Możesz zrezygnować z udostępniania ekranu aplikacji, wywołując metodę Metoda createScreenCaptureIntent(MediaProjectionConfig) z argumentem MediaProjectionConfig zwróconym z wywołania do createConfigForDefaultDisplay().

Połączenie z numerem createScreenCaptureIntent(MediaProjectionConfig) i Zwrócono MediaProjectionConfig argument z wywołania do createConfigForUserChoice() jest identyczne jako domyślne działanie, czyli wywołanie createScreenCaptureIntent()

Aplikacje z możliwością zmiany rozmiaru

Zawsze zmieniaj rozmiar aplikacji do wyświetlania multimediów (resizeableActivity="true"). Możliwość zmiany rozmiaru aplikacje obsługują zmiany w konfiguracji urządzenia oraz tryb wielu okien (patrz Obsługa wielu okien).

Jeśli aplikacji nie można zmienić, musi ona wysyłać zapytania do granic wyświetlania z poziomu okna i użyj polecenia getMaximumWindowMetrics(), aby pobrać WindowMetrics maksymalny obszar wyświetlania dostępny dla aplikacji :

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

Dodatkowe materiały

Więcej informacji na temat wyświetlania multimediów znajdziesz w artykule Nagrywanie dźwięku i obrazu.