Pratinjau kamera

Catatan: Halaman ini merujuk ke paket Camera2. Kecuali aplikasi Anda memerlukan fitur tingkat rendah tertentu dari Camera2, sebaiknya gunakan CameraX. CameraX dan Camera2 mendukung Android 5.0 (level API 21) dan versi yang lebih baru.

Kamera dan pratinjau kamera tidak selalu dalam orientasi yang sama di Android perangkat.

Kamera berada pada posisi tetap pada suatu perangkat, terlepas dari apakah perangkat tersebut adalah ponsel, tablet, atau komputer. Saat orientasi perangkat berubah, perubahan orientasi kamera.

Akibatnya, aplikasi kamera umumnya mengasumsikan hubungan tetap antara orientasi perangkat dan rasio aspek pratinjau kamera. Ketika seorang ponsel dalam orientasi potret, pratinjau kamera diasumsikan lebih tinggi daripada lebarnya. Saat ponsel (dan kamera) diputar ke lanskap, pratinjau kamera diharapkan lebih lebar daripada tingginya.

Namun, asumsi ini mulai tidak berlaku lagi akibat munculnya beragam faktor bentuk baru seperti perangkat foldable, dan mode tampilan layar baru seperti multi-aplikasi dan multi-layar. Perangkat foldable mengubah ukuran layar dan rasio aspek tanpa mengubah orientasi. Mode multi-aplikasi membatasi aplikasi kamera ke sebagian layar, menskalakan pratinjau kamera terlepas dari orientasi perangkat. Mode multi-tampilan memungkinkan penggunaan layar sekunder yang mungkin tidak dalam orientasi yang sama dengan tampilan utama.

Orientasi kamera

Tujuan Definisi Kompatibilitas Android menetapkan bahwa sensor gambar kamera "HARUS diorientasikan sehingga panjang kamera sejajar dengan dimensi panjang layar. Artinya, ketika saat perangkat dipegang dalam orientasi lanskap, kamera HARUS mengambil gambar dalam orientasi lanskapnya. Hal ini berlaku terlepas dari orientasi alami perangkat; yaitu, berlaku untuk perangkat utama lanskap serta perangkat utama potret."

Pengaturan kamera ke layar memaksimalkan area tampilan jendela bidik kamera di aplikasi kamera. Selain itu, sensor gambar biasanya menghasilkan data dalam rasio aspek lanskap, dengan 4:3 sebagai yang paling umum.

Sensor ponsel dan kamera dalam orientasi potret.
Gambar 1. Hubungan umum antara sensor ponsel dan kamera orientasi.

Orientasi alami sensor kamera adalah lanskap. Pada gambar 1, sensor dari kamera yang menghadap ke depan (kamera menunjuk ke arah yang sama dengan layar) diputar 270 derajat relatif terhadap ponsel untuk mematuhi Definisi Kompatibilitas Android.

Untuk mengekspos rotasi sensor ke aplikasi, camera2 API menyertakan konstanta SENSOR_ORIENTATION. Untuk sebagian besar ponsel dan tablet, perangkat melaporkan orientasi sensor 270 derajat untuk kamera depan dan 90 derajat (titik pandang dari bagian belakang perangkat) untuk kamera belakang, yang menyelaraskan tepi panjang sensor dengan tepi panjang perangkat. Kamera laptop umumnya melaporkan orientasi sensor 0 atau 180 derajat.

Karena sensor gambar kamera menghasilkan datanya (buffer gambar) dalam orientasi alami sensor (lanskap), buffer gambar harus diputar sejumlah derajat yang ditentukan oleh SENSOR_ORIENTATION agar pratinjau kamera muncul tegak dalam orientasi alami perangkat. Untuk kamera depan, rotasi dilakukan berlawanan arah jarum jam; untuk kamera belakang, searah jarum jam.

Misalnya, untuk kamera depan pada gambar 1, buffering gambar yang dihasilkan oleh sensor kamera terlihat seperti ini:

Sensor kamera diputar ke orientasi lanskap dengan gambar
            miring, kiri atas.

Gambar harus diputar 270 derajat berlawanan arah jarum jam agar pratinjau orientasinya sesuai dengan orientasi perangkat:

Sensor kamera dalam orientasi potret dengan gambar tegak.

Kamera belakang akan menghasilkan buffering gambar dengan orientasi yang sama seperti buffer di atas, tetapi SENSOR_ORIENTATION adalah 90 derajat. Hasilnya, buffer diputar 90 derajat searah jarum jam.

Rotasi perangkat

Rotasi perangkat adalah jumlah derajat perangkat diputar dari orientasi naturalnya. Misalnya, ponsel dalam orientasi lanskap memiliki perangkat rotasi 90 atau 270 derajat, tergantung pada arah rotasi.

Buffer gambar sensor kamera harus diputar dengan jumlah derajat yang sama dengan rotasi perangkat (selain derajat orientasi sensor) untuk pratinjau kamera agar terlihat tegak.

Penghitungan orientasi

Orientasi pratinjau kamera yang tepat mempertimbangkan orientasi sensor dan rotasi perangkat.

Rotasi keseluruhan buffering gambar sensor dapat dihitung menggunakan formula berikut:

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

dengan sign adalah 1 untuk kamera depan, -1 untuk kamera belakang.

Untuk kamera depan, buffer gambar diputar berlawanan arah jarum jam (dari orientasi alami sensor). Untuk kamera belakang, sensor buffer gambar diputar searah jarum jam.

Ekspresi deviceOrientationDegrees * sign + 360 mengonversi rotasi perangkat dari berlawanan arah jarum jam untuk kamera belakang (misalnya, mengubah 270 derajat berlawanan arah jarum jam menjadi 90 derajat searah jarum jam). Modulus menskalakan hasilnya hingga kurang dari 360 derajat (misalnya, menskalakan 540 derajat rotasi ke 180).

API yang berbeda melaporkan rotasi perangkat secara berbeda:

  • Display#getRotation() menyediakan rotasi perangkat berlawanan arah jarum jam (dari sudut pandang pengguna). Nilai ini dimasukkan ke dalam rumus di atas sebagaimana adanya.
  • OrientationEventListener#onOrientationChanged() menampilkan rotasi searah jarum jam perangkat (dari sudut pandang pengguna). Menegasikan nilai untuk digunakan dalam formula di atas.

Kamera depan

Pratinjau kamera dan sensor dalam orientasi lanskap, sensor
            adalah sisi kanan atas.
Gambar 2. Pratinjau dan sensor kamera dengan ponsel diputar 90 derajat ke orientasi lanskap.

Berikut adalah buffer gambar yang dihasilkan oleh sensor kamera pada gambar 2:

Sensor kamera dalam orientasi lanskap dengan gambar tegak.

Buffer harus diputar 270 derajat berlawanan arah jarum jam untuk menyesuaikan orientasi sensor (lihat Orientasi kamera di atas):

Sensor kamera diputar ke orientasi potret dengan gambar menyamping,
            kanan atas.

Kemudian {i>buffer<i} diputar tambahan 90 derajat berlawanan arah jarum jam untuk memperhitungkan rotasi perangkat, sehingga menghasilkan orientasi yang benar dari pratinjau kamera di gambar 2:

Sensor kamera diputar ke orientasi lanskap dengan gambar
            tegak lurus.

Berikut ini kamera yang diputar ke kanan ke orientasi lanskap:

Pratinjau kamera dan sensor keduanya dalam orientasi lanskap, tetapi
            sensor terbalik.
Gambar 3. Pratinjau dan sensor kamera dengan ponsel diputar 270 derajat (atau -90 derajat) ke orientasi lanskap.

Berikut buffer gambar:

Sensor kamera diputar ke orientasi lanskap dengan gambar terbalik
            ke bawah.

Buffer harus diputar 270 derajat berlawanan arah jarum jam untuk menyesuaikan sensor orientasi:

Sensor kamera diberi rating untuk orientasi potret dengan gambar menyamping,
            kiri atas.

Kemudian {i>buffer<i} diputar 270 derajat lainnya berlawanan arah jarum jam untuk memperhitungkan rotasi perangkat:

Sensor kamera diputar ke orientasi lanskap dengan gambar
            tegak.

Kamera belakang

Kamera yang menghadap ke belakang biasanya memiliki orientasi sensor 90 derajat (seperti dilihat dari bagian belakang perangkat). Saat mengorientasikan pratinjau kamera, buffer gambar sensor diputar searah jarum jam berdasarkan jumlah rotasi sensor (bukan berlawanan arah jarum jam seperti kamera depan), lalu gambar buffer diputar berlawanan arah jarum jam berdasarkan jumlah rotasi perangkat.

Pratinjau dan sensor kamera dalam orientasi lanskap, tetapi
            sensor terbalik.
Gambar 4. Ponsel dengan kamera belakang dalam orientasi lanskap (berubah ke 270 atau -90 derajat).

Berikut adalah buffer gambar dari sensor kamera pada gambar 4:

Sensor kamera diputar ke orientasi lanskap dengan gambar terbalik
            ke bawah.

Buffer harus diputar 90 derajat searah jarum jam untuk menyesuaikan sensor orientasi:

Sensor kamera yang diberi nilai orientasi potret dengan gambar miring,
            kiri atas.

Kemudian, buffer diputar 270 derajat berlawanan arah jarum jam untuk memperhitungkan perangkat rotasi:

Sensor kamera diputar ke orientasi lanskap dengan gambar
            tegak lurus.

Rasio aspek

Rasio aspek layar berubah saat orientasi perangkat berubah, tetapi juga saat perangkat foldable dilipat dan dibentangkan, saat jendela diubah ukurannya di lingkungan multi-aplikasi, dan saat aplikasi terbuka di layar sekunder.

Buffer gambar sensor kamera harus diorientasikan dan diskalakan agar cocok dengan orientasi dan rasio aspek elemen UI jendela bidik saat UI mengubah orientasi secara dinamis—dengan atau tanpa perangkat mengubah orientasi.

Pada faktor bentuk baru atau di lingkungan multi-aplikasi atau multi-tampilan, jika aplikasi berasumsi bahwa pratinjau kamera memiliki orientasi yang sama dengan perangkat (potret atau lanskap) pratinjau Anda mungkin tidak diorientasikan dengan benar, diskalakan salah, atau keduanya.

Perangkat foldable yang dibentangkan dengan pratinjau kamera potret diputar
            ke samping.
Gambar 5. Perangkat foldable bertransisi dari rasio aspek potret ke lanskap, tetapi sensor kamera tetap dalam orientasi potret.

Pada Gambar 5, aplikasi keliru mengasumsikan bahwa perangkat diputar 90 kali derajat berlawanan arah jarum jam; Jadi, aplikasi memutar pratinjau dengan jumlah yang sama.

Perangkat foldable yang dibentangkan dengan pratinjau kamera tegak, tetapi terhimpit
            karena penskalaan yang salah.
Gambar 6. Perangkat foldable bertransisi dari rasio aspek potret ke lanskap, tetapi sensor kamera tetap dalam orientasi potret.

Pada gambar 6, aplikasi tidak menyesuaikan rasio aspek buffer gambar ke memungkinkannya melakukan penskalaan dengan benar agar sesuai dengan dimensi baru UI pratinjau kamera .

Aplikasi kamera berorientasi tetap biasanya mengalami masalah pada perangkat foldable dan perangkat layar besar lainnya seperti laptop:

Pratinjau kamera di laptop tegak, tetapi UI aplikasi miring.
Gambar 7. Aplikasi potret orientasi tetap di komputer laptop.

Dalam gambar 7, UI aplikasi kamera miring karena orientasi aplikasi dibatasi untuk potret saja. Gambar jendela bidik diorientasikan dengan benar relatif terhadap sensor kamera.

Mode potret inset

Aplikasi kamera yang tidak mendukung mode multi-aplikasi (resizeableActivity="false") dan membatasi orientasinya (screenOrientation="portrait" atau screenOrientation="landscape") dapat ditempatkan dalam mode potret inset di perangkat layar besar untuk mengorientasikan pratinjau kamera dengan benar.

Menambahkan letterbox mode potret (inset) pada aplikasi khusus potret dalam orientasi potret meskipun rasio aspek layarnya adalah lanskap. Aplikasi khusus lanskap memiliki tampilan lebar dalam orientasi lanskap rasio aspek tampilan adalah potret. Gambar kamera diputar untuk menyejajarkan dengan UI aplikasi, yang dipangkas agar sesuai dengan rasio aspek pratinjau kamera, dan kemudian diskalakan untuk mengisi pratinjau.

Mode potret inset dipicu saat rasio aspek gambar kamera sensor dan rasio aspek aktivitas utama aplikasi tidak cocok.

Pratinjau kamera dan UI aplikasi dalam orientasi potret yang tepat di laptop.
            Gambar pratinjau lebar diskalakan dan dipangkas agar sesuai dengan potret
            orientasi.
Gambar 8. Aplikasi potret orientasi tetap dalam mode potret inset aktif laptop Anda.

Pada gambar 8, aplikasi kamera khusus potret telah diputar untuk menampilkan UI di layar laptopnya. Aplikasi ini memiliki tampilan lebar karena perbedaannya dalam rasio aspek antara aplikasi potret dan tampilan lanskap. Kamera gambar pratinjau telah diputar untuk mengimbangi rotasi UI aplikasi (karena mode potret inset), dan gambar telah dipangkas dan diskalakan agar sesuai dengan orientasi potret, yang mengurangi ruang pandang.

Putar, pangkas, skalakan

Mode potret inset dipanggil untuk aplikasi kamera khusus potret di layar yang memiliki rasio aspek lanskap:

Pratinjau kamera di laptop tegak, tetapi UI aplikasi miring.
Gambar 9. Aplikasi potret berorientasi tetap di laptop.

Aplikasi memiliki tampilan lebar dalam orientasi potret:

Aplikasi diputar ke orientasi potret dan tampilan lebar. Gambar adalah
            miring, dari atas ke kanan.

Gambar kamera diputar 90 derajat untuk menyesuaikan reorientasi aplikasi:

Gambar sensor diputar 90 derajat agar tegak lurus.

Gambar dipangkas ke rasio aspek pratinjau kamera, lalu diskalakan untuk mengisi pratinjau (ruang pandang dikurangi):

Gambar kamera yang dipangkas diskalakan untuk mengisi pratinjau kamera.

Pada perangkat foldable, orientasi sensor kamera dapat berupa potret sedangkan rasio aspek layar adalah lanskap:

Pratinjau kamera dan UI aplikasi memutar ke samping layar lebar dan dibentangkan.
Gambar 10. Perangkat yang dibentangkan dengan aplikasi kamera khusus potret dan rasio aspek sensor dan layar kamera yang berbeda.

Karena pratinjau kamera diputar untuk menyesuaikan orientasi sensor, gambar diorientasikan dengan benar di jendela bidik, tetapi aplikasi khusus potret diputar ke samping.

Mode potret inset hanya perlu membuat tampilan lebar aplikasi dalam orientasi potret untuk mengorientasikan pratinjau aplikasi dan kamera dengan benar:

Aplikasi dengan format lebar tinggi dalam orientasi potret dengan pratinjau kamera
            tegak di perangkat foldable.

API

Mulai dari Android 12 (API level 31), aplikasi juga dapat secara eksplisit mengontrol potret inset melalui SCALER_ROTATE_AND_CROP properti CaptureRequest .

Nilai defaultnya adalah SCALER_ROTATE_AND_CROP_AUTO, yang memungkinkan sistem memanggil mode potret inset. SCALER_ROTATE_AND_CROP_90 adalah perilaku mode potret inset seperti yang dijelaskan di atas.

Tidak semua perangkat mendukung semua nilai SCALER_ROTATE_AND_CROP. Untuk mendapatkan daftar nilai yang didukung, referensi CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES

CameraX

Library Jetpack CameraX membuat pembuatan jendela bidik kamera yang mengakomodasi orientasi sensor dan rotasi perangkat menjadi tugas yang sederhana.

Elemen tata letak PreviewView membuat pratinjau kamera, yang secara otomatis menyesuaikan orientasi sensor, rotasi perangkat, dan penskalaan. PreviewView mempertahankan rasio aspek gambar kamera dengan menerapkan jenis skala FILL_CENTER, yang memusatkan gambar, tetapi dapat memangkasnya agar sesuai dengan dimensi PreviewView. Untuk membuat gambar kamera menjadi lebar, tetapkan jenis skala ke FIT_CENTER.

Untuk mempelajari dasar-dasar pembuatan pratinjau kamera dengan PreviewView, lihat Mengimplementasikan pratinjau.

Untuk mengetahui contoh implementasi lengkap, lihat repositori CameraXBasic di GitHub.

Jendela Bidik Kamera

Serupa dengan kasus penggunaan Pratinjau, library CameraViewfinder menyediakan serangkaian alat untuk menyederhanakan pembuatan pratinjau kamera. CameraX Extensions tidak bergantung pada CameraX Core, sehingga Anda dapat mengintegrasikannya dengan lancar ke dalam codebase Camera2 yang ada.

Daripada menggunakan Surface secara langsung, Anda dapat menggunakan CameraViewfinder untuk menampilkan feed kamera untuk Camera2.

CameraViewfinder secara internal menggunakan TextureView atau SurfaceView untuk menampilkan feed kamera, dan menerapkan transformasi yang diperlukan pada menampilkan jendela bidik dengan benar. Hal ini termasuk koreksi rasio aspek, skala, dan rotasi.

Untuk meminta platform dari objek CameraViewfinder, Anda harus membuat ViewfinderSurfaceRequest.

Permintaan ini berisi persyaratan untuk resolusi permukaan dan perangkat kamera informasi dari CameraCharacteristics.

Memanggil requestSurfaceAsync() akan mengirim permintaan ke penyedia platform, yang merupakan TextureView atau SurfaceView dan mendapatkan ListenableFuture dari Surface.

Menelepon markSurfaceSafeToRelease() memberi tahu penyedia platform bahwa platform tidak diperlukan dan terkait resource dapat dilepaskan.

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 adalah pendekatan sederhana untuk membuat pratinjau kamera jika pratinjau tidak memerlukan pemrosesan dan tidak dianimasikan.

SurfaceView otomatis memutar buffering gambar sensor kamera agar cocok dengan orientasi layar, dengan mempertimbangkan orientasi sensor dan rotasi perangkat. Namun, buffer gambar diskalakan agar sesuai dengan SurfaceView dimensi tanpa pertimbangan rasio aspek.

Anda harus memastikan bahwa rasio aspek buffer gambar cocok dengan rasio aspek SurfaceView, yang dapat Anda lakukan dengan menskalakan konten SurfaceView dalam metode onMeasure() komponen:

(Kode sumber computeRelativeRotation() ada dalam Rotasi relatif di bawah.)

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

Untuk mengetahui detail selengkapnya tentang cara menerapkan SurfaceView sebagai pratinjau kamera, lihat Orientasi kamera.

TextureView

TextureView memiliki performa yang lebih rendah daripada SurfaceView—dan lebih banyak pekerjaan—tetapi TextureView memberi Anda kontrol maksimum atas pratinjau kamera.

TextureView memutar buffering gambar sensor berdasarkan orientasi sensor, tetapi tidak menangani rotasi perangkat atau penskalaan pratinjau.

Penskalaan dan rotasi dapat dienkode dalam Transformasi Matriks. Untuk mempelajari cara menskalakan dan memutar TextureView dengan benar, lihat Mendukung platform yang dapat diubah ukurannya di aplikasi kamera Anda

Rotasi relatif

Rotasi relatif sensor kamera adalah jumlah rotasi yang diperlukan untuk menyesuaikan output sensor kamera dengan orientasi perangkat.

Rotasi relatif digunakan oleh komponen seperti SurfaceView dan TextureView untuk menentukan faktor penskalaan x dan y untuk gambar pratinjau. Ini juga digunakan untuk menentukan rotasi buffering gambar sensor.

Class CameraCharacteristics dan Surface memungkinkan penghitungan rotasi relatif sensor kamera:

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

Metrik jendela aplikasi

Ukuran layar tidak boleh digunakan untuk menentukan dimensi jendela bidik kamera; aplikasi kamera mungkin berjalan di sebagian layar, baik dalam mode multi-aplikasi di perangkat seluler maupun mode bebas di ChromeOS.

WindowManager#getCurrentWindowMetrics() (ditambahkan di API level 30) menampilkan ukuran jendela aplikasi, bukan ukuran layar. Metode library Jetpack WindowManager WindowMetricsCalculator#computeCurrentWindowMetrics() dan WindowInfoTracker#currentWindowMetrics() menyediakan dukungan serupa dengan kompatibilitas mundur ke API level 14.

Rotasi 180 derajat

Rotasi perangkat 180 derajat (misalnya, dari orientasi alami ke orientasi alami terbalik) tidak memicu callback onConfigurationChanged(). Akibatnya, pratinjau kamera mungkin terbalik.

Untuk mendeteksi rotasi 180 derajat, terapkan DisplayListener dan periksa rotasi perangkat dengan panggilan ke Display#getRotation() di onDisplayChanged() .

Referensi eksklusif

Sebelum Android 10, hanya aktivitas yang paling terlihat dalam multi-aplikasi lingkungan dalam status RESUMED. Hal ini membingungkan pengguna karena sistem tidak memberikan indikasi aktivitas mana yang dilanjutkan.

Android 10 (API level 29) memperkenalkan multi-lanjutan dengan semua aktivitas yang terlihat berada dalam status RESUMED. Aktivitas yang terlihat tetap dapat memasuki PAUSED jika, misalnya, aktivitas transparan berada di atas aktivitas atau aktivitas tidak dapat difokuskan, seperti dalam mode picture-in-picture (lihat Dukungan picture-in-picture).

Aplikasi yang menggunakan kamera, mikrofon, atau resource eksklusif atau singleton di API level 29 atau yang lebih tinggi harus mendukung multi-resume. Misalnya, jika tiga aktivitas yang dilanjutkan ingin menggunakan kamera, hanya satu yang dapat mengakses resource eksklusif ini. Setiap aktivitas harus mengimplementasikan onDisconnected() untuk mengetahui akses preemptive ke kamera dengan prioritas yang lebih tinggi aktivitas Anda.

Untuk informasi selengkapnya, lihat Multi-resume.

Referensi lainnya