Podgląd z aparatu

Uwaga: ta strona dotyczy pakietu Camera2. Jeśli aplikacja nie wymaga określonych, niskiego poziomu funkcji z Aparatu2, zalecamy użycie CameraX. Zarówno aplikacja CameraX, jak i Aparat 2 obsługują Androida 5.0 (poziom interfejsu API 21) i nowsze wersje.

Na urządzeniach z Androidem kamery i podglądy z kamery nie zawsze są wyświetlane w tej samej orientacji.

Kamera jest umieszczona w ustalonym położeniu na urządzeniu niezależnie od tego, czy jest to telefon, tablet czy komputer. Gdy orientacja urządzenia się zmienia, zmienia się orientacja aparatu.

W rezultacie aplikacje aparatu zwykle przyjmują stałą zależność między orientacją urządzenia a formatem obrazu podglądu aparatu. Gdy telefon jest w orientacji pionowej, zakładamy, że obraz z aparatu jest wyższy niż szerszy. Po obróceniu telefonu (i aparatu) do orientacji poziomej obraz z aparatu powinien być szerszy niż wysoki.

Te założenia kwestionują jednak nowe formaty, takie jak urządzenia składane i tryby wyświetlania, takie jak wiele okien i wiele wyświetlaczy. Urządzenia składane zmieniają rozmiar wyświetlacza i format obrazu bez zmiany orientacji. Tryb wielu okien ogranicza aplikacje aparatu do części ekranu, skalując podgląd kamery niezależnie od orientacji urządzenia. Tryb wielu wyświetlaczy umożliwia korzystanie z dodatkowych wyświetlaczy, które mogą być w innej orientacji niż wyświetlacz główny.

Orientacja aparatu

Definicja zgodności z Androidem określa, że czujnik obrazu w aparacie musi być ustawiony w taki sposób, aby jego długość była zgodna z długością ekranu. Oznacza to, że gdy urządzenie jest trzymane w orientacji poziomej, aparaty MUSZĄ robić zdjęcia w orientacji poziomej. Dotyczy to zarówno urządzeń w orientacji poziomej, jak i pionowej”.

Układ między aparatem a ekranem maksymalizuje obszar wyświetlania wizjera aparatu w aplikacji aparatu. Czujniki obrazu zazwyczaj przesyłają dane w orientacji poziomej, przy czym najczęściej jest to 4:3.

Czujnik telefonu i aparatu w orientacji pionowej.
Rysunek 1. Typowa orientacja telefonu i czujnika aparatu.

Naturalna orientacja czujnika aparatu to pozioma. Na ilustracji 1 czujnik przedniego aparatu (aparat skierowany w tym samym kierunku co wyświetlacz) jest obrócony o 270 stopni względem telefonu, aby zachować zgodność z definicją zgodności z Androidem.

Aby udostępnić obrót czujnika aplikacjom, interfejs API camera2 zawiera stałą SENSOR_ORIENTATION. W przypadku większości telefonów i tabletów urządzenie zgłasza orientację czujnika pod kątem 270 stopni w przypadku aparatów przednich i 90 stopni (perspektywy z tyłu urządzenia) w przypadku tylnych aparatów, co pozwala zbliżyć długą krawędź czujnika do długej krawędzi urządzenia. Kamery w laptopach zgłaszają zwykle orientację czujnika o wartości 0 lub 180 stopni.

Czujniki obrazu z aparatu przesyłają dane (bufor obrazu) w jego naturalnej orientacji (poziomej), dlatego bufor obrazu musi być obrócony o liczbę stopni określoną przez SENSOR_ORIENTATION, aby podgląd z aparatu był wyświetlany pionowo w naturalnej orientacji urządzenia. W przypadku aparatów przednich obrót odbywa się w lewo, a w przypadku tylnych aparatów – w prawo.

Na przykład w przypadku przedniego aparatu na ilustracji 1 bufor obrazu generowany przez czujnik w aparacie wygląda tak:

Czujnik aparatu został obrócony do orientacji poziomej z obrazem obróconym bokiem i w lewym górnym rogu.

Obraz musi być obrócony o 270 stopni w lewo, tak aby orientacja podglądu była zgodna z orientacją urządzenia:

Czujnik aparatu w orientacji pionowej, z obrazem pionowo.

Tylny aparat utworzy bufor obrazu o takiej samej orientacji jak bufor powyżej, ale SENSOR_ORIENTATION ma wartość 90 stopni. W efekcie bufor jest obrócony o 90 stopni w prawo.

Obracanie urządzenia

Obrót urządzenia to liczba stopni, o jaką urządzenie zostało obrócone względem naturalnej orientacji. Na przykład telefon w orientacji poziomej może obracać się o 90 lub 270 stopni w zależności od kierunku obrotu.

Aby podgląd kamery był widoczny pionowo, bufor obrazu czujnika aparatu musi być obrócony o tę samą liczbę stopni co obrót urządzenia (a nie tylko w odniesieniu do orientacji czujnika).

Obliczanie orientacji

Prawidłowa orientacja podglądu aparatu uwzględnia orientację czujnika i obrót urządzenia.

Ogólny obrót bufora obrazu czujnika można obliczyć za pomocą tego wzoru:

rotation = (sensorOrientationDegrees - deviceOrientationDegrees * sign + 360) % 360

gdzie sign to 1 – aparat przedni i -1 – tylny.

W przypadku aparatów przednich bufor obrazu jest obrócony w lewo (zgodnie z naturalną orientacją czujnika). W przypadku tylnych aparatów bufor obrazu czujnika jest obrócony w prawo.

Wyrażenie deviceOrientationDegrees * sign + 360 konwertuje obrót urządzenia w lewo na prawo w przypadku aparatów tylnych (np. konwertuje 270 stopni w lewo na 90 stopni w prawo). Operacja modulo skaluje wynik do mniej niż 360 stopni (np. skalowanie o 540 stopni obrotu do 180).

Różne interfejsy API raportują rotację urządzenia w różny sposób:

  • Display#getRotation() umożliwia obrót urządzenia w lewo (z punktu widzenia użytkownika). Ta wartość zostaje w niezmienionej postaci do powyższej formuły.
  • OrientationEventListener#onOrientationChanged() obraca urządzenie zgodnie z ruchem wskazówek zegara (z perspektywy użytkownika). Ustaw ujemną wartość na potrzeby formuły powyżej.

Przednie aparaty

Podgląd z aparatu i czujnik są w orientacji poziomej, czujniki są po prawej stronie do góry.
Rysunek 2. Podgląd z aparatu i czujnik z telefonem obróconym o 90 stopni do orientacji poziomej.

Oto bufor obrazu wygenerowany przez czujnik aparatu na ilustracji 2:

Czujnik aparatu w orientacji poziomej, obraz pionowo.

Aby dostosować orientację czujnika, trzeba obrócić bufor o 270 stopni w lewo (patrz Orientacja aparatu powyżej):

Czujnik aparatu został obrócony do orientacji pionowej, a obraz jest obrócony
            w prawym górnym rogu.

Następnie bufor jest obrócony o dodatkowe 90 stopni w lewo, aby uwzględnić obrócenie urządzenia. Efektem jest poprawna orientacja obrazu podglądu aparatu na ilustracji 2:

Czujnik aparatu został obrócony do orientacji poziomej.

Oto kamera obrócona w prawo do orientacji poziomej:

Podgląd z aparatu i czujnik są w orientacji poziomej, ale czujnik jest do góry nogami.
Rysunek 3. Podgląd z aparatu i czujnik z telefonem obróconym o 270 stopni (lub o 90 stopni) w orientację poziomą.

Oto bufor obrazów:

Czujnik aparatu został obrócony do orientacji poziomej, a obraz jest do góry nogami.

Aby dostosować orientację czujnika, trzeba obrócić bufor o 270 stopni w lewo.

Czujnik aparatu oceniony jako orientacja pionowa ze zdjęciem obróconym bokiem,
 w lewym górnym rogu.

Następnie bufor jest obrócony o kolejne 270 stopni w lewo, aby uwzględnić obrót urządzenia:

Czujnik aparatu został obrócony do orientacji poziomej.

Tylne aparaty

Tylne aparaty mają zwykle orientację 90 stopni (patrząc z tyłu urządzenia). Podczas orientowania podglądu z aparatu bufor obrazów z czujnika jest obracany w prawo zgodnie z obrotem czujnika (a nie w lewo jak w przypadku aparatów przednich), a następnie jest obrócony w lewo o wartość obrotu urządzenia.

Podgląd z aparatu i czujnik są w orientacji poziomej, ale czujnik jest do góry nogami.
Rysunek 4. Telefon z tylnym aparatem w orientacji poziomej (obrócony o 270 lub -90 stopni).

Oto bufor obrazu z czujnika aparatu na ilustracji 4:

Czujnik aparatu został obrócony do orientacji poziomej, a obraz jest do góry nogami.

Aby dostosować orientację czujnika, należy obrócić Bufor o 90 stopni w prawo:

Czujnik aparatu oceniony jako orientacja pionowa ze zdjęciem obróconym bokiem,
 w lewym górnym rogu.

Następnie bufor jest obrócony o 270 stopni w lewo, aby uwzględnić obrót urządzenia:

Czujnik aparatu został obrócony do orientacji poziomej.

Format obrazu

Format obrazu zmienia się, gdy orientacja urządzenia zmienia się, ale też podczas złożenia i rozłożenia urządzenia, zmiany rozmiaru okna w środowisku z wieloma oknami oraz gdy aplikacje są otwierane na dodatkowych wyświetlaczach.

Orientacja bufora obrazu czujnika aparatu musi być ustalona i skalowana tak, aby pasowała do orientacji i proporcji elementu interfejsu wizjera, ponieważ interfejs dynamicznie zmienia orientację – zarówno ze zmianą orientacji urządzenia, jak i bez niej.

W przypadku nowych formatów, środowisk z wieloma oknami lub z kilkoma wyświetlaczami, jeśli aplikacja zakłada, że podgląd z aparatu ma tę samą orientację co urządzenie (pionowa lub pozioma), może mieć nieprawidłową orientację lub skalę błędną skalę lub mieć obie te wartości.

Rozłożone urządzenie z podglądem aparatu w orientacji pionowej obrócone na boki.
Rysunek 5. Format składanego urządzenia zmienia się z pionowej na poziomą, ale czujnik aparatu pozostaje w orientacji pionowej.

Na ilustracji 5 aplikacja błędnie uznała, że urządzenie zostało obrócone o 90 stopni w lewo.

Rozłożone urządzenie składane z podglądem aparatu pionowo, ale ściśniętego ze względu na nieprawidłowe skalowanie.
Rysunek 6. Format składanego urządzenia zmienia się z pionowej na poziomą, ale czujnik aparatu pozostaje w orientacji pionowej.

Na ilustracji 6 aplikacja nie dostosowała współczynnika proporcji bufora obrazów, aby umożliwić jego prawidłowe skalowanie i dopasowywanie do nowych wymiarów interfejsu podglądu aparatu.

Aplikacje z aparatem o stałej orientacji zwykle mają problemy z urządzeniami składanymi i urządzeniami z dużym ekranem, takimi jak laptopy:

Podgląd z aparatu na laptopie jest ustawiony pionowo, ale interfejs aplikacji jest obrócony.
Rysunek 7. Aplikacja do obsługi orientacji pionowej na laptopie.

Na ilustracji 7 interfejs aplikacji Aparat jest obrócony, ponieważ jest ona ograniczona tylko do orientacji pionowej. Obraz w wizjerze ma prawidłową orientację względem matrycy.

Ustaw tryb portretowy

Aplikacje aparatu, które nie obsługują trybu wielu okien (resizeableActivity="false") i ograniczają orientację (screenOrientation="portrait" lub screenOrientation="landscape"), można na urządzeniach z dużym ekranem ustawić w orientacji pionowej, aby prawidłowo orientować się podgląd z aparatu.

Aplikacje w orientacji pionowej (wbudowane) w orientacji pionowej, mimo że format wyświetlacza ma format poziomy. W przypadku aplikacji w orientacji poziomej w orientacji poziomej będą stosowane czarne pasy, mimo że format obrazu jest wyświetlany w orientacji pionowej. Obraz z aparatu jest obrócony w celu dopasowania do interfejsu aplikacji, przycięty tak, by pasował do formatu obrazu podglądu z aparatu, a następnie skalowany w celu wypełnienia podglądu.

Tryb orientacja pionowa jest wywoływany, gdy proporcje obrazu matrycy w kamerze nie są zgodne z formatem obrazu głównego w aplikacji.

Podgląd aparatu i interfejs aplikacji w odpowiedniej orientacji pionowej na laptopie.
            Szeroki podgląd obrazu jest skalowany i przycinany do orientacji pionowej.
Rysunek 8. Aplikacja do orientacji pionowej w stałej orientacji pionowej na laptopie.

Na ilustracji 8 obrócono aplikację aparatu tylko do orientacji pionowej, tak aby interfejs na ekranie laptopa był ustawiony pionowo. Z powodu różnic pomiędzy formatem obrazu w aplikacji w orientacji poziomej a ekranem w orientacji poziomej. Obraz podglądu aparatu został obrócony, by skompensować obrócenie interfejsu aplikacji (ze względu na tryb pionowy). Obraz został przycięty i przeskalowany, by pasował do orientacji pionowej, co zmniejszyło pole widzenia.

Obracanie, przycinanie i skalowanie

Tryb wstawki jest wywoływany w przypadku aplikacji aparatu (tylko w orientacji pionowej) na ekranie o orientacji poziomej:

Podgląd z aparatu na laptopie jest ustawiony pionowo, ale interfejs aplikacji jest obrócony.
Rysunek 9. Aplikacja do obsługi orientacji pionowej na laptopie.

Aplikacja ma poziome pasy w orientacji pionowej:

Aplikacja została obrócona do orientacji pionowej z czarnymi pasami. Obraz jest obrócony, u góry po prawej.

Obraz z aparatu jest obrócony o 90 stopni, aby dostosować orientację aplikacji:

Obraz czujnika został obrócony o 90 stopni, aby ustawić się pionowo.

Obraz jest przycinany do formatu obrazu podglądu z aparatu, a następnie skalowany tak, by wypełnić podgląd (pole widzenia jest zmniejszone):

Przycięty obraz z aparatu został przeskalowany, aby wypełnić podgląd z aparatu.

Na urządzeniach składanych czujnik aparatu może mieć orientację pionową, a obraz wyświetlacza – w orientacji poziomej:

Podgląd aparatu i interfejs aplikacji obrócone na szeroki, rozłożony wyświetlacz.
Rysunek 10. Rozłożone urządzenie z aparatem obsługującym tylko orientację pionową oraz różnymi formatami obrazu z czujnika i wyświetlacza aparatu.

Podgląd aparatu jest obrócony w celu dopasowania do orientacji czujnika, więc obraz ma prawidłową orientację w wizjerze, a aplikacja tylko w orientacji pionowej jest obrócona.

Aby zapewnić prawidłową orientację podglądu aplikacji i aparatu, w orientacji pionowej trzeba będzie jedynie dodać do niej poziome pasy w orientacji pionowej:

Aplikacja w formacie Letterbox w orientacji pionowej z podglądem aparatu pionowo na urządzeniu składanym.

Interfejs API

Od Androida 12 (poziom interfejsu API 31) aplikacje mogą też bezpośrednio kontrolować tryb orientacji pionowej za pomocą właściwości SCALER_ROTATE_AND_CROP klasy CaptureRequest.

Wartość domyślna to SCALER_ROTATE_AND_CROP_AUTO, która umożliwia systemowi wywoływanie trybu portretowego. SCALER_ROTATE_AND_CROP_90 działa w trybie w orientacji pionowej zgodnie z opisem powyżej.

Nie wszystkie urządzenia obsługują wszystkie wartości parametru SCALER_ROTATE_AND_CROP. Listę obsługiwanych wartości znajdziesz, odwołanie się do CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES.

Aparat X

Dzięki bibliotece Jetpack CameraX utworzenie wizjera aparatu dostosowanego do orientacji czujnika i obracania urządzenia to proste zadanie.

Element układu PreviewView tworzy podgląd kamery, automatycznie dostosowując się do orientacji czujnika, obrotu urządzenia i skalowania. PreviewView zachowuje współczynnik proporcji obrazu z aparatu, stosując typ skalowania FILL_CENTER, który wyśrodkowuje obraz, ale może go przyciąć, aby pasował do wymiarów PreviewView. Aby ustawić obraz z aparatu w formacie letterbox, ustaw typ skali na FIT_CENTER.

Aby poznać podstawy tworzenia podglądu z aparatu za pomocą PreviewView, przeczytaj artykuł o implementowaniu podglądu.

Pełną przykładową implementację znajdziesz w repozytorium CameraXBasic na GitHubie.

Wizjer aparatu

Podobnie jak w przypadku opcji Podgląd, biblioteka Wizjer aparatu zawiera zestaw narzędzi ułatwiających tworzenie podglądu z aparatu. Nie wymaga ona oprogramowania CameraX Core, dzięki czemu można płynnie zintegrować go z istniejącą bazą kodu aparatu Camera2.

Zamiast bezpośrednio używać Surface, możesz użyć widżetu CameraViewfinder, aby wyświetlić obraz z kamery dla kamery 2.

CameraViewfinder używa wewnętrznie TextureView lub SurfaceView do wyświetlania obrazu z kamery i stosuje do nich wymagane przekształcenia, aby poprawnie wyświetlać wizjer. Wiąże się to z skorygowaniem współczynnika proporcji, skali i obrotu.

Aby poprosić o powierzchnię z obiektu CameraViewfinder, musisz utworzyć ViewfinderSurfaceRequest.

To żądanie zawiera wymagania dotyczące rozdzielczości powierzchni i informacji o aparacie od CameraCharacteristics.

Wywołanie requestSurfaceAsync() powoduje wysłanie żądania do dostawcy platformy, czyli TextureView lub SurfaceView, i otrzymuje ListenableFuture o wartości Surface.

Wywołanie markSurfaceSafeToRelease() powiadamia dostawcę platformy, że platforma nie jest potrzebna i mogą zostać zwolnione powiązane zasoby.

Kotlin


fun startCamera(){
    val previewResolution = Size(width, height)
    val viewfinderSurfaceRequest =
        ViewfinderSurfaceRequest(previewResolution, characteristics)
    val surfaceListenableFuture =
        cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest)

    Futures.addCallback(surfaceListenableFuture, object : FutureCallback<Surface> {
        override fun onSuccess(surface: Surface) {
            /* create a CaptureSession using this surface as usual */
        }
        override fun onFailure(t: Throwable) { /* something went wrong */}
    }, ContextCompat.getMainExecutor(context))
}

Java


    void startCamera(){
        Size previewResolution = new Size(width, height);
        ViewfinderSurfaceRequest viewfinderSurfaceRequest =
                new ViewfinderSurfaceRequest(previewResolution, characteristics);
        ListenableFuture<Surface> surfaceListenableFuture =
                cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest);

        Futures.addCallback(surfaceListenableFuture, new FutureCallback<Surface>() {
            @Override
            public void onSuccess(Surface result) {
                /* create a CaptureSession using this surface as usual */
            }
            @Override public void onFailure(Throwable t) { /* something went wrong */}
        },  ContextCompat.getMainExecutor(context));
    }

Widok powierzchni

SurfaceView to proste podejście do tworzenia podglądu z aparatu, gdy nie wymaga on przetwarzania i nie jest animowany.

SurfaceView automatycznie obraca bufor obrazu czujnika aparatu, aby dopasować go do orientacji wyświetlacza. Uwzględnia orientację czujnika i obrót urządzenia. Bufor obrazów jest jednak skalowany, aby pasował do wymiarów SurfaceView, bez uwzględniania współczynnika proporcji.

Musisz się upewnić, że współczynnik proporcji bufora obrazu odpowiada współczynnikowi proporcji elementu SurfaceView, co możesz uzyskać, skalując zawartość zasobu SurfaceView w metodzie onMeasure() komponentu:

(Kod źródłowy computeRelativeRotation() znajduje się poniżej w rotacji względnej).

Kotlin

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    val width = MeasureSpec.getSize(widthMeasureSpec)
    val height = MeasureSpec.getSize(heightMeasureSpec)

    val relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees)

    if (previewWidth > 0f && previewHeight > 0f) {
        /* Scale factor required to scale the preview to its original size on the x-axis. */
        val scaleX =
            if (relativeRotation % 180 == 0) {
                width.toFloat() / previewWidth
            } else {
                width.toFloat() / previewHeight
            }
        /* Scale factor required to scale the preview to its original size on the y-axis. */
        val scaleY =
            if (relativeRotation % 180 == 0) {
                height.toFloat() / previewHeight
            } else {
                height.toFloat() / previewWidth
            }

        /* Scale factor required to fit the preview to the SurfaceView size. */
        val finalScale = min(scaleX, scaleY)

        setScaleX(1 / scaleX * finalScale)
        setScaleY(1 / scaleY * finalScale)
    }
    setMeasuredDimension(width, height)
}

Java

@Override
void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);

    int relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees);

    if (previewWidth > 0f && previewHeight > 0f) {

        /* Scale factor required to scale the preview to its original size on the x-axis. */
        float scaleX = (relativeRotation % 180 == 0)
                       ? (float) width / previewWidth
                       : (float) width / previewHeight;

        /* Scale factor required to scale the preview to its original size on the y-axis. */
        float scaleY = (relativeRotation % 180 == 0)
                       ? (float) height / previewHeight
                       : (float) height / previewWidth;

        /* Scale factor required to fit the preview to the SurfaceView size. */
        float finalScale = Math.min(scaleX, scaleY);

        setScaleX(1 / scaleX * finalScale);
        setScaleY(1 / scaleY * finalScale);
    }
    setMeasuredDimension(width, height);
}

Więcej informacji o implementowaniu SurfaceView jako podglądu aparatu znajdziesz w sekcji Orientacje aparatu.

Widok tekstury

TextureView jest mniej wydajny od SurfaceView, ale wymaga więcej pracy, ale TextureView daje Ci maksymalną kontrolę nad podglądem z aparatu.

TextureView obraca bufor obrazu czujnika na podstawie orientacji czujnika, ale nie obsługuje obracania urządzenia ani skalowania podglądu.

Skalowanie i obrót można kodować w przekształceniu macierzy. Więcej informacji o prawidłowym skalowaniu i obracaniu obiektu TextureView znajdziesz w artykule Obsługa powierzchni, których rozmiar można zmieniać w aplikacji aparatu.

Rotacja względna

Względny obrót czujnika kamery to stopień obrotów wymagany do dopasowania danych wyjściowych czujnika kamery do orientacji urządzenia.

Komponenty takie jak SurfaceView i TextureView używają obrotu względnego do określania współczynników skalowania obrazu podglądu na osi x i y. Służy ono również do określania obrotu bufora obrazu czujnika.

Klasy CameraCharacteristics i Surface umożliwiają obliczenie względnego obrotu czujnika kamery:

Kotlin

/**
 * Computes rotation required to transform the camera sensor output orientation to the
 * device's current orientation in degrees.
 *
 * @param characteristics The CameraCharacteristics to query for the sensor orientation.
 * @param surfaceRotationDegrees The current device orientation as a Surface constant.
 * @return Relative rotation of the camera sensor output.
 */
public fun computeRelativeRotation(
    characteristics: CameraCharacteristics,
    surfaceRotationDegrees: Int
): Int {
    val sensorOrientationDegrees =
        characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION)!!

    // Reverse device orientation for back-facing cameras.
    val sign = if (characteristics.get(CameraCharacteristics.LENS_FACING) ==
        CameraCharacteristics.LENS_FACING_FRONT
    ) 1 else -1

    // Calculate desired orientation relative to camera orientation to make
    // the image upright relative to the device orientation.
    return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360
}

Java

/**
 * Computes rotation required to transform the camera sensor output orientation to the
 * device's current orientation in degrees.
 *
 * @param characteristics The CameraCharacteristics to query for the sensor orientation.
 * @param surfaceRotationDegrees The current device orientation as a Surface constant.
 * @return Relative rotation of the camera sensor output.
 */
public int computeRelativeRotation(
    CameraCharacteristics characteristics,
    int surfaceRotationDegrees
){
    Integer sensorOrientationDegrees =
        characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);

    // Reverse device orientation for back-facing cameras.
    int sign = characteristics.get(CameraCharacteristics.LENS_FACING) ==
        CameraCharacteristics.LENS_FACING_FRONT ? 1 : -1;

    // Calculate desired orientation relative to camera orientation to make
    // the image upright relative to the device orientation.
    return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360;
}

Dane dotyczące okien

Rozmiar ekranu nie powinien być używany do określania wymiarów wizjera w kamerze. Aplikacja aparatu może działać na części ekranu – w trybie wielu okien na urządzeniach mobilnych lub w trybie wolnym w ChromeOS.

WindowManager#getCurrentWindowMetrics() (dodany do poziomu interfejsu API 30) zwraca rozmiar okna aplikacji, a nie rozmiar ekranu. Metody biblioteki Jetpack WindowManager WindowMetricsCalculator#computeCurrentWindowMetrics() i WindowInfoTracker#currentWindowMetrics() zapewniają podobną obsługę wsteczną do interfejsu API na poziomie 14.

Obrót o 180 stopni

Obrót urządzenia o 180 stopni (np. z naturalnej orientacji do naturalnej do góry nogami) nie uruchamia wywołania zwrotnego onConfigurationChanged(). W związku z tym podgląd z aparatu może być do góry nogami.

Aby wykryć obrót o 180 stopni, wdróż narzędzie DisplayListener i sprawdź obrót urządzenia, wywołując metodę Display#getRotation() w wywołaniu zwrotnym onDisplayChanged().

Wyjątkowe materiały

Przed Androidem 10 tylko najwyżej widoczna aktywność w środowisku wielu okien miała stan RESUMED. Było to mylące dla użytkowników, ponieważ system nie zawierał informacji o tym, które działania zostały wznowione.

W Androidzie 10 (poziom interfejsu API 29) wprowadzono funkcję wielokrotnego wznawiania, gdy wszystkie widoczne aktywności mają stan RESUMED. Widoczne aktywności mogą nadal przechodzić w stan PAUSED, jeśli na przykład aktywność jest umieszczona nad nią przezroczystą lub nie można jej zaznaczyć, jak w trybie obraz w obrazie (patrz Obsługa funkcji obraz w obrazie).

Aplikacja korzystająca z kamery, mikrofonu lub jakichkolwiek zasobów specjalnych na poziomie API 29 lub wyższym musi obsługiwać wielokrotne wznawianie. Na przykład, jeśli do 3 wznawianych aktywności chce się używać kamery, dostęp do tego wyjątkowego zasobu będzie mieć tylko jedna z nich. Każde działanie musi zawierać wywołanie zwrotne onDisconnected(), które informuje o wywołaniu zapobiegawczym dostępu do kamery przez działanie o wyższym priorytecie.

Więcej informacji znajdziesz w artykule Wielokrotne wznawianie.

Dodatkowe materiały