Podgląd z aparatu

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

Podglądy aparatów i aparatów nie zawsze mają tę samą orientację na Androidzie urządzenia.

Aparat ma ustaloną pozycję na urządzeniu, niezależnie od tego, czy jest to telefon, tablet czy komputer. Gdy zmienia się orientacja urządzenia, zmienia się też orientacja kamery.

W związku z tym aplikacje aparatu zwykle przyjmują stałą relację między od orientacji urządzenia i formatu obrazu podglądu z aparatu. Gdy telefonu jest w orientacji pionowej, podgląd aparatu zakłada, że jest wyższy. niż ma szerokość. Gdy telefon (i kamera) jest obrócony w poziomie, podgląd aparatu powinien być szerszy niż wyższy.

Te założenia podważają jednak nowe formaty, takie jak urządzenia składane , i trybów wyświetlania, takich jak wiele okien oraz Wiele ekranów. Urządzenia składane zmieniają rozmiar wyświetlacza i format obrazu bez zmian orientacji ekranu. Tryb wielu okien ogranicza aplikacje aparatu do części na ekranie, skalując podgląd z aparatu niezależnie od orientacji urządzenia. Tryb wielu ekranów umożliwia korzystanie z dodatkowych ekranów, które mogą mieć inną orientację niż ekran główny.

Orientacja aparatu

Definicja zgodności z Androidem określa, że czujnik obrazu aparatu „MUSI być ustawiony tak, aby dłuższy wymiar aparatu był zgodny z dłuższym wymiarem ekranu. Oznacza to, że gdy urządzenie jest ustawione poziomo, aparat MUSI robić zdjęcia do orientacji poziomej. Dotyczy to niezależnie od naturalnej orientacji urządzenia, czyli zarówno urządzeń z główną orientacją poziomą, jak i z główną orientacją pionową”.

Układ kamery i ekranu maksymalizuje obszar wyświetlania kamery wizjer w aplikacji aparatu. Ponadto czujniki obrazu zwykle zapisują dane w format obrazu w orientacji poziomej, gdzie najczęściej jest używany format 4:3.

Telefon i czujnik aparatu w orientacji pionowej.
Rysunek 1. Typowa relacja orientacji telefonu i czujnika aparatu

Czujnik aparatu ma naturalną orientację poziomą. Na ilustracji 1 czujnik przedniego aparatu (skieruj aparat w tym samym kierunku co wyświetlacza) jest obracany o 270 stopni względem telefonu, aby zapewnić Definicja zgodności z Androidem.

Aby udostępnić aplikacjom obrót czujnika, Interfejs API camera2 obejmuje SENSOR_ORIENTATION jest stała. W przypadku większości telefonów i tabletów urządzenie zgłasza orientację czujnika. 270 stopni dla przedniego aparatu i 90 stopni dla tylnej części urządzenia, aby zapewnić jej dłuższą krawędź. przylegaj do czujnika dłuższą krawędzią urządzenia. Kamery w laptopach zwykle raportują orientację czujnika 0 lub 180 stopni.

Czujniki obrazu z aparatu zapisują dane (bufor obrazu) w w naturalnej orientacji czujnika (poziomo), bufor obrazu należy obracać liczba stopni określonej przez SENSOR_ORIENTATION na podgląd z aparatu wyświetlają się pionowo w naturalnej orientacji. W przypadku aparatów przednich obraca się w lewo. dla aparatów z tyłu, w prawo.

Na przykład w przypadku przedniego aparatu na rysunku 1 bufor obrazu wygenerowany przez czujnik aparatu wygląda tak:

Czujnik aparatu został obrócony do orientacji poziomej ze zdjęciem
            bokiem w lewym górnym rogu.

Obraz musi być obrócony o 270 stopni w przeciwnym kierunku do ruchu wskazówek zegara, aby orientacja podglądu odpowiadała orientacji urządzenia:

Czujnik aparatu w orientacji pionowej z obrazem w poziomie.

Z aparatu tylnego pochodzi bufor obrazu o tej samej orientacji jak bufor powyżej, ale SENSOR_ORIENTATION to 90 stopni. W rezultacie jest obrócony o 90 stopni w prawo.

Obracanie urządzenia

Obrót urządzenia to liczba stopni obrócenia urządzenia orientacji ekranu. Na przykład telefon w orientacji poziomej o 90 lub 270 stopni, w zależności od kierunku obrotu.

Bufor obrazu z czujnika aparatu musi być obrócony o taką samą liczbę stopni jak obrotu urządzenia (oprócz stopni pochylenia czujnika) w by podgląd z aparatu był ustawiony pionowo.

Obliczanie orientacji

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

Ogólny obrót bufora obrazu czujnika można obliczyć za pomocą funkcji następujący wzór:

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

gdzie sign to 1 dla aparatów przednich, a -1 dla aparatów tylnych.

W przypadku przednich aparatów bufor obrazu jest obracany w przeciwnym kierunku niż wskazówki zegara (w stosunku do naturalnej orientacji czujnika). W przypadku aparatów tylnych bufor obrazu jest obrócony w prawo.

Wyrażenie deviceOrientationDegrees * sign + 360 zmienia obrót urządzenia z przeciwnego do wskazówek zegara na zgodny z wskazówkami zegara w przypadku tylnych kamer (np. z 270 stopni w przeciwnym do wskazówek zegara na 90 stopni w zgodnym z wskazówkami zegara). Operacja modulo powoduje, że wynik jest mniejszy niż 360 stopni (np. skalowanie 540 stopni obrotu do 180).

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

  • Display#getRotation() pozwala na obrót urządzenia w przeciwnym kierunku niż wskazówki zegara (z perspektywy użytkownika). Ta wartość zostaje dodana do powyższej formuły w niezmienionej formie.
  • OrientationEventListener#onOrientationChanged()zwraca obrót urządzenia zgodnie z kierunkiem ruchu wskazówek zegara (z perspektywy użytkownika). Odwrotna wartość do użycia w formule powyżej.

Przednie aparaty

Podgląd aparatu i czujnik w orientacji poziomej, czujnik skierowany w górę.
Rysunek 2. Podgląd z kamery i czujnika przy telefonie obróconym o 90 stopni do orientacji poziomej

Oto bufor obrazu utworzony przez czujnik aparatu na rysunku 2:

Czujnik aparatu w orientacji poziomej z obrazem pionowo.

Aby dostosować bufor do orientacji czujnika, należy obrócić go o 270° w przeciwnym kierunku do ruchu wskazówek zegara (patrz Orientacja kamery powyżej):

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

Następnie bufor jest obrócony o dodatkowe 90 stopni w lewo, biorąc pod uwagę obrót urządzenia, co spowoduje uzyskanie prawidłowej orientacji podgląd aparatu na ilustracji 2:

Czujnik aparatu został obrócony do orientacji poziomej ze zdjęciem
            pionowo.

Oto kamera obrócona w prawo, aby uzyskać orientację poziomą:

Podgląd z aparatu i czujnik są w orientacji poziomej, ale
            jest do góry nogami.
Rysunek 3. Podgląd z kamery i czujnika przy obrocie telefonu o 270 stopni (lub o -90 stopni) do orientacji poziomej.

Oto bufor obrazu:

Czujnik aparatu został obrócony do orientacji poziomej z obrazem do góry
            w dół.

Aby dostosować go do orientacji czujnika, bufor musi zostać obrócony o 270 stopni w przeciwnym kierunku do ruchu wskazówek zegara:

Czujnik aparatu w orientacji pionowej z obrazem 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 ze zdjęciem
            pionowo.

Tylne aparaty

Tylne aparaty mają zazwyczaj orientację 90 stopni widoczne z tyłu urządzenia). Podczas ustawiania podglądu z aparatu funkcja bufor obrazu czujnika jest obrócony w prawo zgodnie z intensywnością obrotu czujnika (a nie w lewo, jak w przypadku przednich aparatów), a następnie obraz bufor jest obrócony w lewo zgodnie z obrotem urządzenia.

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

Na ilustracji 4 widać bufor obrazu z czujnika aparatu:

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

Aby dostosować orientację czujnika, bufor musi zostać obrócony o 90 stopni w prawo:

Czujnik aparatu przeznaczony do orientacji w pionie z obrazem poziomym w lewym górnym rogu.

Następnie bufor obraca się o 270 stopni w lewo, by uwzględnić rotacja:

Czujnik aparatu został obrócony do orientacji poziomej ze zdjęciem
            pionowo.

Format obrazu

Format obrazu zmienia się, gdy zmienia się orientacja urządzenia, ale także wtedy, gdy składane urządzenia są składane i rozkładane, gdy zmienia się rozmiar okien w otoczeniu z wieloma oknami oraz gdy aplikacje otwierają się na ekranach dodatkowych.

Bufor obrazu z czujnika aparatu musi być zorientowany i przeskalowany tak, aby orientacja i współczynnik proporcji elementu interfejsu wizjera. dynamicznie zmienia orientację – niezależnie od tego, czy zmienia się urządzenie orientacji ekranu.

W przypadku nowych formatów, trybów wielu okien lub wyświetlaczy, jeśli aplikacja przyjmuje, że podgląd z aparatu ma taką samą orientację jak urządzenie (pionowej lub poziomej) podgląd może mieć nieprawidłową orientację lub przeskalowanie nieprawidłowo lub jedno i drugie.

Rozłożone urządzenie składane z podglądem aparatu w orientacji poziomej
Rysunek 5. Składane urządzenie przechodzi z orientacji pionowej na poziomą, ale czujnik aparatu pozostaje w orientacji pionowej.

Na rysunku 5 aplikacja błędnie założyła, że urządzenie zostało obrócone o 90 stopni w przeciwnym kierunku ruchu wskazówek zegara, więc obróciła podgląd o ten sam kąt.

Rozłożone urządzenie składane z podglądem aparatu w poziomie, ale zniekształconym z powodu nieprawidłowego skalowania.
Rysunek 6. Składane urządzenie przechodzi z orientacji pionowej na poziomą, ale czujnik aparatu pozostaje w orientacji pionowej.

Na ilustracji 6 aplikacja nie dostosowała formatu obrazu bufora do włącz jego odpowiednie skalowanie, aby pasowało do nowych wymiarów interfejsu podglądu aparatu. .

W aplikacjach o stałej orientacji ekranu zazwyczaj występują problemy na urządzeniach składanych i na innych urządzeniach z dużym ekranem, takich jak laptopy:

Podgląd z kamery na laptopie jest w poziomie, ale interfejs aplikacji jest w poziomie.
Rysunek 7. Aplikacja do orientacji pionowej na laptopie.

Na rysunku 7 interfejs aplikacji aparatu jest wyświetlany w poziomie, ponieważ orientacja aplikacji jest ograniczona tylko do orientacji poziomej. Obraz w wizjerze jest poprawnie ustawiony. względem czujnika aparatu.

Tryb wstawki w orientacji pionowej

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

W trybie pionowym wyświetlaj aplikacje tylko w orientacji pionowej w ramce (w przycisku) nawet wtedy, gdy współczynnik proporcji wyświetlacza jest w orientacji poziomej. W przypadku aplikacji tylko w orientacji poziomej są wyświetlane czarne pasy, mimo że format obrazu jest pionowy. Obraz z kamery jest obracany, aby dopasować go do interfejsu aplikacji, przycięty, aby dopasować go do współczynnika proporcji podglądu z kamery, a następnie przeskalowany, aby wypełnić podgląd.

Tryb wstawki w orientacji pionowej jest wyzwalany po wybraniu formatu obrazu z aparatu z czujnikiem i współczynnikiem proporcji głównej aktywności aplikacji nie są zgodne.

Podgląd z aparatu i interfejs aplikacji na laptopie w prawidłowej orientacji pionowej.
            Szeroki obraz podglądu jest skalowany i przycięty, aby pasował do orientacji pionowej
            orientacji ekranu.
Rysunek 8. Aplikacja do orientacji pionowej w orientacji pionowej i włączona laptopa.

Na ilustracji 8 obrócono aplikację aparatu w orientacji pionowej, aby wyświetlić interfejs. pionowo na wyświetlaczu laptopa. W aplikacji pojawiają się czarne pasy z powodu różnicy proporcje między aplikacją w orientacji pionowej a ekranem w orientacji poziomej. Obraz podglądu w aparacie został obrócony, aby zrównoważyć obrót interfejsu aplikacji (z powodu wbudowanego trybu portretowego). Obraz został przycięty i pomniejszony, aby pasował do orientacji pionowej, co zmniejszyło pole widzenia.

Obrót, przycinanie, skalowanie

Tryb wstawki w orientacji pionowej jest wywoływany w przypadku aplikacji aparatu przeznaczonego tylko do wyświetlania w orientacji pionowej na ekranie w orientacji poziomej:

Podgląd z kamery na laptopie jest w poziomie, ale interfejs aplikacji jest w poziomie.
Rysunek 9. Aplikacja w orientacji pionowej na laptopie.

Aplikacja ma poziome pasy w orientacji pionowej:

Aplikacja obrócona do orientacji pionowej i w ramce. Obraz jest obrócony, góra po prawej stronie.

Obraz z kamery jest obrócony o 90 stopni, aby dostosować aplikacja:

Obraz czujnika został obrócony o 90 stopni, aby był w poziomie.

Obraz jest przycinany do formatu podglądu z aparatu, a następnie skalowany wypełnij podgląd (pole widzenia jest ograniczone):

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

Na składanych urządzeniach orientacja czujnika aparatu może być pionowa, a format wyświetlacza poziomy:

Podgląd z aparatu i interfejs aplikacji na rozłożonym wyświetlaczu.
Rysunek 10. Rozłożone urządzenie z aplikacją aparatu tylko do zdjęć portretowych i różne formaty obrazu czujnika aparatu i ekranu.

Podgląd z aparatu jest obracany w celu dostosowania się do orientacji czujnika, Zdjęcie jest właściwie zorientowane w wizjerze, ale aplikacja tylko do wyświetlania w orientacji pionowej jest obrócone.

Wbudowany tryb pionowy wymaga tylko dodania czarnych pasów do aplikacji w orientacji pionowej aby zapewnić prawidłową orientację aplikacji i podglądu z aparatu:

Aplikacja w ramce nakładki w orientacji pionowej z podglądem aparatu na urządzeniu składanym w pozycji pionowej.

Interfejs API

Od Androida 12 (poziom interfejsu API 31) aplikacje mogą też bezpośrednio sterować wbudowaną obrazem w orientacji pionowej. za pomocą SCALER_ROTATE_AND_CROP właściwość CaptureRequest zajęcia.

Wartością domyślną jest SCALER_ROTATE_AND_CROP_AUTO, która umożliwia systemowi wywołanie trybu w formacie portretowym. SCALER_ROTATE_AND_CROP_90 to zachowanie w trybie portretowym z wstawionym obrazem, jak opisano powyżej.

Nie wszystkie urządzenia obsługują wszystkie wartości SCALER_ROTATE_AND_CROP. Aby uzyskać listę obsługiwanych wartości, odwołanie CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES

Aparat X

biblioteka Jetpack CameraX, umożliwia stworzenie wizjera aparatu pasującego do orientacji czujnika to proste zadanie.

Element układu PreviewView tworzy podgląd z aparatu, automatycznie dostosowując się do orientacji czujnika, obracania i skalowania urządzenia. PreviewView zachowuje proporcje obrazu z kamery, stosując typ skalowania FILL_CENTER, który umieszcza obraz na środku, ale może go przyciąć, aby dopasować do wymiarów PreviewView. Aby na obrazie z aparatu ustawić czarne pasy, ustaw typ skali na FIT_CENTER

Podstawowe informacje na temat tworzenia podglądu z kamery w PreviewView znajdziesz w tych artykułach: Zaimplementuj podgląd.

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

CameraViewfinder

Podobnie jak w przypadku korzystania z funkcji Podgląd biblioteka CameraViewfinder udostępnia zestaw narzędzi, które upraszczają tworzenie podglądu z kamery. Nie zależy ona od CameraX Core, więc możesz ją łatwo zintegrować z dotychczasową bazą kodu Camera2.

Zamiast używać bezpośrednio aplikacji Surface możesz wyświetlić obraz z kamery Camera2 za pomocą widżetu CameraViewfinder.

CameraViewfinder używa wewnętrznie obiektu TextureView lub SurfaceView do wyświetlania obrazu z kamery i zmienia go w wymagany sposób, aby poprawnie wyświetlać wizjer. Obejmuje to korektę formatu obrazu, skali i obrotu.

Aby poprosić o powierzchnię z obiektu CameraViewfinder, musisz utwórz element ViewfinderSurfaceRequest.

Ta prośba zawiera wymagania dotyczące rozdzielczości powierzchni i informacji o aparacie z CameraCharacteristics.

Dzwonię pod numer requestSurfaceAsync() wysyła żądanie do dostawcy powierzchni, którym jest TextureView lub SurfaceView i otrzymuje ListenableFuture o wartości Surface.

Dzwonię pod numer markSurfaceSafeToRelease() powiadamia dostawcę powierzchni, że nie jest ona potrzebna i jest powiązana zasobów, które można zwolnić.

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

SurfaceView

SurfaceView to do podglądu z aparatu, jeśli podgląd wymagają przetworzenia i nie jest animowany.

SurfaceView automatycznie obraca bufor obrazu czujnika aparatu, aby dopasować go do orientacji wyświetlacza, uwzględniając zarówno orientację czujnika, jak i urządzenia. Bufor obrazu jest jednak skalowany tak, aby pasował do: SurfaceView bez uwzględniania formatu obrazu.

Musisz się upewnić, że format bufora obrazu jest zgodny z formatem współczynnika SurfaceView, którą można uzyskać, skalując zawartość z SurfaceView w komponencie onMeasure() :

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

KotlinJava
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)
}
@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 wdrażaniu SurfaceView jako podglądu aparatu znajdziesz w artykule Ustawienia orientacji kamery.

TextureView

TextureView jest mniej wydajny niż SurfaceView (i wymaga więcej pracy), ale TextureView zapewnia maksymalną kontrolę nad podglądem kamery.

TextureView obraca bufor obrazu czujnika w zależności od jego orientacji, ale nie obsługuje obracania urządzenia ani skalowania podglądu.

Skalowanie i obrót można zakodować Transformacja matrycy. Aby dowiedzieć się, jak prawidłowo skalować i obracać TextureView, zapoznaj się z artykułem Obsługa powierzchni o zmiennym rozmiarze w aplikacji Aparat.

Rotacja względna

Odchylenie względne czujnika aparatu to kąt obrotu wymagany do dopasowania sygnału z czujnika aparatu do orientacji urządzenia.

Obrót względny jest używany przez komponenty takie jak SurfaceView i TextureView w celu określenia współczynników skalowania x i y dla obrazu podglądu. Służy ona też do określenia rotacji bufora obrazu czujnika.

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

KotlinJava
/**
 * 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
}
/**
 * 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 aparatu. Aplikacja aparatu może działać na części ekranu, w trybie wielu okien na urządzeniach mobilnych lub w trybie swobodnym w ChromeOS.

WindowManager#getCurrentWindowMetrics() (dodane na poziomie interfejsu API 30) zwraca rozmiar okna aplikacji, a nie do rozmiaru ekranu. Metody biblioteki Jetpack WindowManager WindowMetricsCalculator#computeCurrentWindowMetrics() oraz WindowInfoTracker#currentWindowMetrics() zapewniają podobną pomoc dzięki zgodności wstecznej z interfejsem API poziomu 14.

Obrót o 180 stopni

Obrót urządzenia o 180 stopni (na przykład z orientacji naturalnej do naturalnej orientacji do góry nogami) nie powoduje onConfigurationChanged() oddzwanianie. W związku z tym podgląd z aparatu może być do góry nogami.

Aby wykryć obrót o 180 stopni, zaimplementuj funkcję DisplayListener i sprawdź obrót urządzenia za pomocą wywołania funkcji Display#getRotation() w połączeniu z wywołaniem onDisplayChanged().

Wyjątkowe materiały

Przed Androidem 10 tylko najbardziej widoczna aktywność w trybie wielu okien było w stanie RESUMED. Było to mylące dla użytkowników, ponieważ system nie wskaże, która aktywność została wznowiona.

Android 10 (poziom interfejsu API 29) wprowadziło wielozadaniowość, w której wszystkie widoczne działania są w stanie RESUMED. Widoczne aktywności nadal mogą trafiać do pola PAUSED jeśli na przykład nad działaniem znajduje się przezroczysta aktywność lub aktywności nie można zaznaczyć, na przykład w trybie obrazu w obrazie (patrz Obsługa funkcji obraz w obrazie).

Aplikacja używająca kamery, mikrofonu lub dowolnych bądź innych zasób singleton na poziomie API 29 lub wyższym musi obsługiwać wielokrotne wznawianie. Jeśli na przykład 3 wznowione aktywności chcą korzystać z kamery, tylko jedna z nich może uzyskać dostęp do tego zasobu. Każde działanie musi implementować onDisconnected() wywołanie zwrotne, aby zwracać uwagę na zapobiegawczy dostęp do kamery przez wyższy priorytet działania.

Więcej informacji znajdziesz w artykule Wznawianie zadań.

Dodatkowe materiały