
Belum lama ini, saya sibuk dengan mesin robot saya, mencoba untuk menempatkan smartphone ANDROID di atasnya. Tugas saya adalah tugas saya untuk membuat gerobak maju secara evolusioner. Sehingga dia, sehingga bisa dikatakan, bisa merasakan dunia dengan sensornya, memandangnya dengan mata (kamera), mendengar dengan mikrofon dan bersumpah di speakerphone. Sumber daya AVR, tentu saja, tidak cukup untuk hal ini, sehingga mikrokontroler yang ada di kereta bergerak ke tingkat yang lebih rendah, di suatu tempat di sumsum tulang belakang untuk mengendalikan motor dan berbagai refleks tanpa syarat.
Tapi anehnya, ketika saya mulai menulis aplikasi untuk smartphone, IDE ANDROID STUDIO yang buruk mulai terus mencoret kode saya dan menyebutnya usang.
kamera =
Kamera. open ();
Terutama, seperti yang Anda lihat, di bagian-bagian tempat saya mencoba bekerja dengan kamera. Itu sangat mengecewakan karena saya membaca di Internet dan belajar banyak pelajaran tentang bekerja dengan android dan kamera di
sini , di
sini , di
sini dan bahkan di
sini . Tidak ada yang dicoret di sana. Dan itu disebut API Kamera. Semua yang ada di sana sederhana dan logis. Tapi Google dengan keras kepala mendorong saya ke semacam
API Camera2 .
Saya melihat ke sana dan mengalami masalah dengan jumlah callback, builder, handler, dan looper yang berbeda untuk setiap baris kode demo. Itu benar-benar tidak bisa dipahami cara untuk mendekati ini jika Anda seorang amatir biasa, bukan pengembang android. Selain itu, bahkan ada beberapa artikel tentang Camera2 API di jaringan hari ini, meskipun pembaruan ini tampaknya seperti empat tahun lalu. Tapi yang saya temukan adalah sebuah artikel di Hacker pada tahun 2016, sebuah pos dalam tiga bagian dari saudara-saudara Ukraina pada tahun yang sama, sebuah pos ganda tentang Habré pada tahun 2017 dan sebuah artikel Memahami Camera2 dari megaphone Jepang Tomoaki Imai. Dan ini saya juga maksudkan beberapa informasi terstruktur dan formal, dan bukan potongan kode seperti "lihat bagaimana saya bisa" dan lembaran dalam gaya "lihat kode pliz, tidak ada yang bekerja untuk saya" yang tersebar di Internet.
Dan sekarang, jika Anda masih bertanya-tanya mengapa saya perlu memotong posting saya tentang topik ini
sudah tahun 2019, lalu selamat datang ke kucing.
Sebenarnya, saya suka artikel dari Hacker karena itu memberi saya setidaknya gambaran mengapa paradigma baru bekerja dengan kamera diperkenalkan. Juga menjadi jelas mengapa beberapa metode baru diperlukan yang tidak ada dalam API sebelumnya. Tetapi untuk menulis program kerja untuk artikel ini sama sekali tidak mungkin, karena penulis, tampaknya, seperti peretas sejati, hanya mengutip nama-nama metode, well, mungkin masih ada beberapa baris kode tambahan. Tapi ini jelas tidak cukup bagi saya.
Posting tentang Habré bagus, saya tidak berpendapat, dan saya bahkan mengerti beberapa paragraf pertama, tapi itu intinya, karena penulis posting mengalahkan kamera menggunakan RxJava2, yang secara otomatis mengecualikan saya dari jumlah pembaca lebih lanjut. Saya biasanya berurusan dengan OOP, tetapi di sini ada semacam pemrograman reaktif.
Artikel Jepang bahkan lebih baik, bahkan jika dia tidak menulis dalam bahasa aslinya. Tetapi saya juga tidak mengenal Kotlin, meskipun saya, tentu saja, senang dengan pengembang dalam negeri dan menghargai singkatnya sintaksisnya, berbeda dengan bihun JAVA yang ada di halaman pengembang Google (omong-omong, dengan halaman ini, juga jelas bagi saya bahwa ada jelas tidak banyak).
Artikel terakhir yang memberi saya manfaat praktis adalah pos tiga bagian dari persaudaraan Ukraina. Saya bahkan meluncurkan sesuatu di sana dan melihat sesuatu di sana. Namun sayangnya, di bagian ketiga, penulis artikel itu sangat lelah dan juga mulai mengeluarkan kode dalam fragmen yang tidak menambah keseluruhan kerja saya. Selain itu, pada akhirnya, penulis benar-benar kesal, karena ia mendapatkan gambar palet warna yang salah yang ia hitung.

Katakanlah, ini karena versi Lollipop adalah 5.0, dan ada bug. Anda perlu meningkatkan ke Lollipop 5.1 dan semuanya akan baik-baik saja. Tapi entah kenapa belum. Dan juga Ukraina yang berbahaya diikat ke artikel JAVA SCRIPT, dan ketika menyalin kode, sejumlah besar sampah dituangkan ke dalam teks program. Guys, well, Anda tidak bisa melakukan itu ... Saya harus menginstal plug-in khusus di Firefox.
Karena itu, saya harus mengambil spanduk yang jatuh dan menyelesaikan pekerjaan sampai akhir, yang tentu saja, memerlukan upaya mental yang sangat besar. Dan karena entah bagaimana disayangkan untuk puas hanya dengan kesadaran bahwa hasil kerja diperoleh, saya ingin membaginya dengan teko amatir. Apalagi ini masih jauh dari akhir cerita. Saya masih perlu belajar bagaimana mentransfer video langsung dari kamera android ke komputer (robot robot harus dikembangkan, ini adalah hukum evolusi) dan tidak berkeping-keping, seperti saya buta, tetapi lancar. Dan ada hambatan seperti Mont Blanc dalam bentuk codec media dan hal-hal lain yang hanya pelat timah.
Tetapi di sisi lain, semuanya mungkin berakhir dengan kekecewaan total. Dan bukan karena mereka tidak akan bisa memanjat Mont Blanc.
Dan karena sekarang produsen smartphone sedang mengembangkan pendekatan yang benar-benar baru untuk pembuatan kamera.Sebulan yang lalu, desas-desus bocor tentang smartphone Nokia dengan lima kamera utama. Bagaimana berhubungan dengan ini? Sebuah rumor yang menarik dan menjanjikan atau hal aneh lainnya? Tidak peduli betapa uniknya desain seperti itu, Nokia pasti tidak akan dapat menjadi pelopor dalam memperkenalkan sejumlah lensa dan sensor yang tidak biasa ke dalam perangkat yang ringkas. Kamera Light L16 sudah dilengkapi dengan 16 lensa pada tahun 2015, dan perusahaan, jelas, memiliki prototipe baru dalam operasi. Di atas Anda dapat melihat bagaimana itu berpotensi terlihat.
Setelah tiga kamera muncul di Huawei P20 Pro, transisi ke smartphone dengan lima kamera tidak lagi terdengar semanis mungkin beberapa tahun yang lalu. Namun, pertanyaan utamanya tetap - apa gunanya?
Apa yang harus dilakukan dengan begitu banyak lensa?
Hal pertama yang terlintas dalam pikiran adalah berbagai jenis sensor kamera yang tersedia di pasar smartphone modern, dan kemampuan untuk menambahkan lebih banyak. Mengapa memilih antara sudut lebar, telefoto, potret dengan bokeh atau monokrom, jika Anda bisa mendapatkan semua ini dalam satu perangkat?
Secara teori dimungkinkan, desain seperti itu akan cukup canggung untuk digunakan. Perangkat lunak harus beralih di antara mode secara otomatis atau menawarkan serangkaian opsi yang rumit kepada pengguna. Selain itu, pengembangan desain seperti itu akan sangat mahal untuk semua keuntungan yang meragukan dari solusi semacam itu. Setiap kamera akan berfungsi sebagian besar secara independen, dan pembeli tidak mungkin menggunakan sejumlah besar mode. Dan tidak jelas berapa banyak mereka bersedia membayar untuk fungsi tersebut. Jadi kamera dengan banyak modul harus bisa berbuat lebih banyak untuk menarik pengguna.
Huawei P20 Pro sudah menawarkan versinya tentang bagaimana beberapa modul kamera dapat bekerja bersama untuk memberikan hasil yang menarik. Kita berbicara tentang teknologi dari Huawei, seperti Monochrome dan Hybrid Zoom. Yang pertama meningkatkan jangkauan dinamis dari frame standar dengan menggabungkan data RGB biasa dengan sensor hitam putih fotosensitif. Dan Hybrid Zoom menjanjikan lebih banyak lagi: ini menggabungkan data dari beberapa kamera untuk meningkatkan resolusi gambar untuk zoom yang lebih baik. Hasilnya, pada P20 Pro 8 MP, sensor lensa telefoto memungkinkan Anda memotret dalam resolusi 10 MP pada 3x dan 5x zoom.
Resolusi Tinggi - Lebih Banyak Fleksibilitas
Kamera Light L16 pertama bekerja dengan cara yang sama, menggunakan cermin periskop agar sesuai dengan modul kamera ke dalam tubuh yang ringkas. Kamera mengambil data dari beberapa modul pada 28, 70 dan 150 mm, tergantung pada tingkat zoom. Hasilnya adalah bidikan besar 52 MP yang diambil dari 10 sudut yang sedikit berbeda tersedia pada tingkat pembesaran hingga 5x. Konsep model baru, yang dikembangkan untuk smartphone, bekerja dengan 5-9 lensa. Modul kamera tersebut mampu mengambil gambar 64 megapiksel besar.
Gagasan beberapa pemotretan ini juga menambah manfaat saat memotret dalam cahaya rendah dan HDR dengan beberapa lubang. Efek berkualitas tinggi dari kedalaman bingkai juga tersedia karena emulasi perangkat lunak simultan dan penggunaan beberapa focal length.
Light L16 membawa kekecewaan, tetapi gagasan itu sendiri menjanjikan. Dan generasi berikutnya yang sukses mungkin terbukti menjadi sesuatu yang berharga. Perusahaan mengklaim bahwa smartphone akan diumumkan pada akhir tahun ini, di mana solusi terbaru mereka dengan banyak lensa akan dipasang.
Gagasan yang sama dapat ditelusuri kembali ke pengalaman Nokia dalam mengimplementasikan beberapa kamera, mengingat kisah lama berinvestasi dalam Pelican Imaging pada 2013. Tidak seperti Light, sensor di sini jauh lebih kecil. Meski begitu, teknologi ini menjanjikan keuntungan yang sangat mirip, termasuk perubahan fokus perangkat lunak, pengukuran kedalaman, dan peningkatan ukuran gambar akhir. Sayangnya, Tessera membeli perusahaan pada tahun 2016, tetapi gagasan itu sendiri mungkin tidak meninggalkan pikiran insinyur Nokia.
Zeiss, mitra foto Nokia saat ini, memiliki paten untuk zoom yang dapat diubah, tetapi kami belum pernah mendengar apa pun dari mereka tentang desain multi-lensa. Mungkin mitra Nokia lainnya, FIH Mobile, terlihat lebih menjanjikan. Perusahaan ini dimiliki oleh Foxconn, meluncurkan ponsel Nokia dan juga berinvestasi di Light pada tahun 2015, memberinya lisensi untuk menggunakan teknologi tersebut.
Dan jika Anda berpikir kebocoran Nokia dan prototipe Cahaya memiliki kesamaan, ini bukan kebetulan. Menghubungkan kedua perusahaan Foxconn. Jadi, apakah smartphone Nokia akan menjadi yang pertama menggunakan teknologi dari Light?
Jadi ini masa depan?
Resolusi ultra-tinggi bukanlah konsep baru. Pada tahun 2014, Oppo Find 7 menggunakan prinsip yang sama, dan Zoom Hybrid Huawei memungkinkan teknologi untuk bekerja dengan beberapa kamera. Secara historis, masalah utama teknologi adalah persyaratan kinerja tinggi, kualitas algoritma, dan konsumsi daya. Namun di sisi smartphone modern, prosesor pemrosesan sinyal yang lebih kuat, chip DSP yang hemat energi, dan bahkan kemampuan yang ditingkatkan dari jaringan saraf, yang secara bertahap mengurangi pentingnya masalah tersebut.
Detail tinggi, kemampuan zoom optikal dan efek bokeh khusus berada di atas daftar persyaratan kamera untuk smartphone modern, dan teknologi multi-kamera dapat membantu mencapainya. Alih-alih melakukan fungsi yang berbeda dengan kamera terpisah, masa depan fotografi seluler adalah menggabungkan beberapa kamera untuk memberikan kemampuan yang lebih canggih dan fleksibel.
Masih ada pertanyaan tentang teknologi Cahaya, terutama tentang menempelkan gambar dengan panjang fokus berbeda. Kita hanya bisa menunggu - kita akan melihat apa yang akan berubah menjadi lebih baik pada teknologi generasi kedua.

Tidak akan mudah untuk mengkonfigurasi perakitan seperti itu dari kamera dengan pegangan dalam program. Mungkin lingkaran akan ditutup dan untuk mengambil gambar, kita harus menulis lagi maksud eksplisit, dengan konten, seperti, "kamera, silakan ambil gambar sendiri yang Anda bisa, tapi indah, dan kembalikan kepada saya dalam aktivitas saya".
Namun untuk saat ini, meski sedikit masih kami miliki. Karena itu, kami segera melanjutkan.
Mengapa semua ini perlu google?Sepertinya semuanya multithreading aman dan tepat (dan juga memungkinkan untuk melakukan segala macam efek dan filter secara langsung). Sekarang, jika di vanilla JAVA, jika perlu, Anda perlu mendorong mutex, sinkronisasi, dan semaphore dengan kompeten di mana-mana, maka di sini Google mengambil alih hampir semuanya. Anda hanya perlu mendaftarkan panggilan balik dalam teks program, yang akan dipanggil jika perlu. Misalnya, Anda mengirim permintaan untuk menghidupkan kamera:
mCameraManager.openCamera()
Tapi ini bukan tim, ini permintaan. Anda tidak dapat segera mulai bekerja dengan kamera. Pertama, dia perlu waktu untuk menghidupkan, dan kedua, android memiliki begitu banyak hal penting untuk dilakukan, dan keinginan Anda dimasukkan ke dalam antrian yang agak besar. Tapi kemudian kita tidak perlu menunggu kamera untuk membuka dalam satu loop di utas utama, menutup seluruh aplikasi (kita masih ingat apa yang bisa dilakukan dalam aliran UI dan apa yang tidak). Oleh karena itu, kami mengirimkan permintaan kami dan sementara kami menjalankan bisnis kami, membuka pandangan, menulis "halo dunia", mengkonfigurasi penangan tombol dan sejenisnya.
Sementara itu, setelah puluhan dan ratusan milidetik, sistem operasi akhirnya mencapai tangan kamera dan menginisialisasinya. Dan segera setelah kamera siap, panggilan balik yang sama dipicu (kecuali tentu saja Anda mendaftarkannya di muka)
private CameraDevice.StateCallback mCameraCallback = new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice camera) { mCameraDevice = camera; createCameraPreviewSession(); ….. }
Artinya, kamera sekarang terbuka dan dapat melakukan sesuatu di sana: menampilkan gambar dari kamera pada tampilan, meneruskannya lebih lanjut untuk disimpan, dan sebagainya.
Akibatnya, semua bekerja dengan kamera, pada kenyataannya, bermuara pada resep semua jenis panggilan balik. Tetapi dalam keinginan mulia mereka, pengembang Google sedikit melangkah terlalu jauh dan, sebagaimana dicatat oleh kawan Jepang itu dengan benar:
Salah satu alasan mengapa Camera2 bingung adalah berapa banyak panggilan balik yang perlu Anda gunakan untuk mengambil satu pemotretan.
Tetapi ini tidak cukup. Skema lengkap dari kamera memiliki tampilan luar biasa ini

Tapi untungnya, sebagai permulaan, ini dapat direduksi menjadi gambar yang jauh lebih menarik.

Meskipun semuanya dalam bahasa Inggris di sana, tetapi seperti yang mereka katakan, jelas tanpa kata-kata. Sebagai permulaan, kami memiliki cukup desain ini. Kami akan membuka kamera, menampilkan gambar pada layar smartphone, mengambil gambar dan segera setelah siap (panggilan balik lagi), pendengar acara ini akan bekerja dan menulis gambar ke file.
Mulai membuat kodeKami akan membuat proyek baru di Android Studio IDE, pilih versi minimum SDK 22 untuk menghindari gambar hijau dan memesan Aktivitas kosong (atau bahkan lebih baik, ambil versi 23, jika tidak masalah dapat terjadi dengan izin). Cukup awal. Bahkan izin dalam manifes belum perlu dilakukan.
Kami mulai dengan membuat turunan dari kelas CameraManager. Ini adalah manajer layanan sistem yang memungkinkan Anda menemukan kamera yang tersedia, mendapatkan karakteristiknya yang Anda perlukan untuk bekerja dan mengatur pengaturan pemotretan untuk kamera.
Dan kita akan melihat karakteristik berikut:
pengidentifikasi kamera (0, 1, 2 ....)
arah kemana arah kamera (maju, mundur)
resolusi kamera
Pertama, kita mendapatkan daftar kamera dalam bentuk array string, dan kemudian mencetak karakteristik yang diperlukan dalam satu lingkaran dan menuliskannya ke log.
package com.example.camera; import android.content.Context; import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; import android.graphics.ImageFormat; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraManager; import android.hardware.camera2.params.StreamConfigurationMap; import android.os.Build; import android.os.Bundle; import android.util.Log; import android.util.Size; public class MainActivity extends AppCompatActivity { public static final String LOG_TAG = "myLogs"; String[] myCameras = null; private CameraManager mCameraManager = null; @RequiresApi(api = Build.VERSION_CODES.M) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try{
Log akan mendapatkan sesuatu seperti ini: 2019-09-13 10:56:31.489 11130-11130/? I/myLogs: cameraID: 0 2019-09-13 10:56:31.504 11130-11130/? I/myLogs: Camera with: ID 0 is BACK CAMERA 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:4000 h:3000 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:4000 h:2250 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:3840 h:2160 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:2592 h:1944 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:2592 h:1940 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:2048 h:1536 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:1920 h:1080 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:1600 h:1200 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:1440 h:1080 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:1440 h:720 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:1280 h:960 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:1280 h:768 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:1280 h:720 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:1280 h:480 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:1280 h:400 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:800 h:480 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:720 h:480 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:640 h:480 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:480 h:640 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:480 h:360 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:480 h:320 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:352 h:288 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:320 h:240 2019-09-13 10:56:31.506 11130-11130/? I/myLogs: w:240 h:320 2019-09-13 10:56:31.507 11130-11130/? I/myLogs: w:176 h:144 2019-09-13 10:56:31.507 11130-11130/? I/myLogs: w:144 h:176 2019-09-13 10:56:31.507 11130-11130/? I/myLogs: cameraID: 1 2019-09-13 10:56:31.514 11130-11130/? I/myLogs: Camera with ID: 1 is FRONT CAMERA 2019-09-13 10:56:31.515 11130-11130/? I/myLogs: w:4224 h:3136 2019-09-13 10:56:31.515 11130-11130/? I/myLogs: w:4224 h:2376 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:4160 h:3120 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:4160 h:2340 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:4000 h:3000 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:4000 h:2250 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:3840 h:2160 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:2592 h:1944 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:2592 h:1940 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:2048 h:1536 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:1920 h:1080 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:1600 h:1200 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:1440 h:1080 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:1440 h:720 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:1280 h:960 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:1280 h:768 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:1280 h:720 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:1280 h:480 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:1280 h:400 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:800 h:480 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:720 h:480 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:640 h:480 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:480 h:640 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:480 h:360 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:480 h:320 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:352 h:288 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:320 h:240 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:240 h:320 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:176 h:144 2019-09-13 10:56:31.516 11130-11130/? I/myLogs: w:144 h:176
Kami, pada prinsipnya, tidak benar-benar membutuhkan informasi ini, teko apa pun bahkan oleh API sebelumnya sudah tahu bahwa kamera memiliki pengidentifikasi dari nol dan seterusnya, bahwa Anda tidak akan mengejutkan siapa pun dengan resolusi 1920 oleh 1080, dan terlebih lagi dengan format JPEG. Faktanya, data ini sudah dibutuhkan oleh aplikasi “dewasa” yang siap untuk diproduksi dan yang, pada dasarnya, akan membuat menu pilihan untuk pengguna dan seterusnya. Dalam kasus kami yang paling sederhana, secara umum, semuanya jelas. Tetapi karena semua artikel dimulai dengan ini, maka kita akan mulai.
Setelah memastikan bahwa kamera depan memiliki nomor pengenal "1" dan belakang "0" (untuk beberapa alasan mereka ditentukan dalam format String), dan juga bahwa resolusi 1920 x 1080 dan menyimpan file JPG tersedia untuk kami, kami akan melanjutkan serangan.
Kami mendapatkan izin yang diperlukanAwalnya, kita perlu khawatir tentang sejumlah izin. Untuk melakukan ini, manifes harus menulis yang berikut ini:
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Yang pertama dapat dimengerti untuk kamera, yang kedua adalah untuk menulis gambar ke file (dan ini bukan kartu memori eksternal, karena mungkin terlihat dari arti kata EKSTERNAL, tetapi cukup memori sendiri smartphone)
Tetapi Android juga peduli dengan kita, oleh karena itu, dimulai dengan versi Lollipop, izin yang ditentukan dalam manifes tidak lagi cukup. Sekarang diperlukan bahwa pena pengguna menyetujui persetujuannya untuk membuka kamera dan menulis data ke memori.
Untuk melakukan ini, dalam kasus paling sederhana, Anda perlu menambahkan ini:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ……... if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED || (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) ) { requestPermissions(new String[]{Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); } …..
Kenapa yang paling sederhana? Karena itu tidak perlu melakukan hal-hal seperti itu dalam aliran UI. Pertama, utas menggantung sementara pengguna menusuk layar dengan jari-jarinya yang canggung, dan kedua, jika Anda membuat kamera diinisialisasi lebih lanjut, aplikasi umumnya dapat macet. Dalam kasus demo ini, semuanya baik-baik saja, tetapi umumnya disarankan untuk menggunakan jenis panggilan balik yang diinginkan untuk kasus ini:
@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == MY_REQUEST_CODE_FOR_CAMERA) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { startCameraActivity();
Meskipun saya sebelumnya tidak mengetahui semua ini, saya meluncurkan Aktivitas yang diinginkan melalui AsyncTask, dan bahkan sebelumnya saya hanya membuat Utas baru, seperti di Jawa.
Memasak kameraUntuk kenyamanan, kami akan mengeluarkan segala sesuatu yang terkait dengan kamera di kelas terpisah atas saran orang pintar dan membuat kelas CameraService. Di sana kita akan menempatkan inisialisasi kamera dan kemudian menuliskan semua panggilan balik yang diperlukan.
….. CameraService[] myCameras = null; private CameraManager mCameraManager = null; private final int CAMERA1 = 0; private final int CAMERA2 = 1; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ….. } public class CameraService { private String mCameraID; private CameraDevice mCameraDevice = null; private CameraCaptureSession mCaptureSession; public CameraService(CameraManager cameraManager, String cameraID) { mCameraManager = cameraManager; mCameraID = cameraID; } public boolean isOpen() { if (mCameraDevice == null) { return false; } else { return true; } } public void openCamera() { try { if (checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { mCameraManager.openCamera(mCameraID,mCameraCallback,null); } } catch (CameraAccessException e) { Log.i(LOG_TAG,e.getMessage()); } } public void closeCamera() { if (mCameraDevice != null) { mCameraDevice.close(); mCameraDevice = null; } } }
Di utas utama, buat instance dari mCameraManager dan gunakan untuk mengisi array objek myCameras. Dalam hal ini, hanya ada dua - kamera depan dan selfie.
mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try{
Dalam metode openCamera void publik (), Anda dapat melihat baris:
mCameraManager.openCamera(mCameraID,mCameraCallback,null);
itu dari sini bahwa jalan menuju panggilan balik pertama dari
status kamera
CameraDevice. StateCallback. Dia akan memberi tahu kami jika kamera terbuka, tertutup atau mungkin tidak ada sama sekali di sana dan akan memberikan kesalahan. Kami akan menulisnya dalam metode kelas CameraService.
private CameraDevice.StateCallback mCameraCallback = new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice camera) { mCameraDevice = camera; Log.i(LOG_TAG, "Open camera with id:"+mCameraDevice.getId()); createCameraPreviewSession(); } @Override public void onDisconnected(CameraDevice camera) { mCameraDevice.close(); Log.i(LOG_TAG, "disconnect camera with id:"+mCameraDevice.getId()); mCameraDevice = null; } @Override public void onError(CameraDevice camera, int error) { Log.i(LOG_TAG, "error! camera id:"+camera.getId()+" error:"+error); } };
Dengan demikian, jika kamera tersedia untuk operasi (public void onOpened (CameraDevice camera) {} metode telah bekerja), maka kami menulis tindakan lebih lanjut di sana, misalnya, memanggil metode createCameraPreviewSession (). Ini akan membantu membawa kita gambar dari kamera ke tampilan dan bekerja lebih jauh.
BuatCameraPreviewSessionDi sini kami mencoba untuk menampilkan gambar (aliran data) pada tekstur mImageView, yang sudah ditentukan dalam tata letak. Anda bahkan dapat menentukan dengan resolusi dalam piksel.
private void createCameraPreviewSession() { SurfaceTexture texture = mImageView.getSurfaceTexture();
Dan ketika sesi yang sama ini siap, callback yang disebutkan di atas dipanggil dan kita mulai dengan ekspresi para googloders: “displaying the camera preview”. Di sini, mereka yang ingin dapat menyesuaikan pengaturan fokus otomatis dan lampu kilat, tetapi untuk sekarang kita akan bertahan dengan pengaturan default.
Buat tata letakSekarang kita perlu, untuk berbicara, untuk membuat sketsa warna pada kanvas dan membuat gambar yang brilian dalam gaya
"Tiga tombol layar dan satu tampilan." <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextureView android:id="@+id/textureView" android:layout_width="356dp" android:layout_height="410dp" android:layout_marginTop="32dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.49" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <LinearLayout android:layout_width="292dp" android:layout_height="145dp" android:layout_marginStart="16dp" android:orientation="vertical" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textureView" app:layout_constraintVertical_bias="0.537"> <Button android:id="@+id/button4" android:layout_width="match_parent" android:layout_height="wrap_content" android:text=" " /> <Button android:id="@+id/button5" android:layout_width="match_parent" android:layout_height="wrap_content" android:text=" " /> <Button android:id="@+id/button6" android:layout_width="match_parent" android:layout_height="wrap_content" android:text=" " /> </LinearLayout> </androidx.constr

Prosesnya cukup sepele dan siapa pun bisa berbalik ke sini sesuai keinginannya. Tetapi untuk menulis nama-nama tombol secara langsung dalam tata letak juga perilaku buruk dan dalam versi yang bekerja tidak perlu untuk melakukannya.
Karenanya, dalam Aktivitas itu sendiri, kami membuat pendengar, yaitu pendengar untuk tombol dan tampilan.
private Button mButtonOpenCamera1 = null; private Button mButtonOpenCamera2 = null; private Button mButtonToMakeShot = null; private TextureView mImageView = null; @RequiresApi(api = Build.VERSION_CODES.M) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ……... mButtonOpenCamera1 = findViewById(R.id.button1); mButtonOpenCamera2 = findViewById(R.id.button2); mButtonToMakeShot =findViewById(R.id.button3); mImageView = findViewById(R.id.textureView); mButtonOpenCamera1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (myCameras[CAMERA2].isOpen()) myCameras[CAMERA2].closeCamera(); if (myCameras[CAMERA1] != null) { if (!myCameras[CAMERA1].isOpen()) myCameras[CAMERA1].openCamera(); } } }); mButtonOpenCamera2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (myCameras[CAMERA1].isOpen()) myCameras[CAMERA1].closeCamera(); if (myCameras[CAMERA2] != null) { if (!myCameras[CAMERA2].isOpen()) myCameras[CAMERA2].openCamera(); } } }); mButtonToMakeShot.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) {
Penugasan tombol jelas dari namanya, kami akan meninggalkan tombol ketiga untuk gambar mendatang.
Dan jika Anda sekarang menyatukan semua potongan kode maka
dapatkan yang berikut ini: package com.example.camera; import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.ContextCompat; import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; import android.graphics.SurfaceTexture; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraManager; import android.hardware.camera2.CaptureRequest; import android.os.Build; import android.os.Bundle; import android.util.Log; import android.view.Surface; import android.view.TextureView; import android.view.View; import android.widget.Button; import java.util.Arrays; public class MainActivity extends AppCompatActivity { public static final String LOG_TAG = "myLogs"; CameraService[] myCameras = null; private CameraManager mCameraManager = null; private final int CAMERA1 = 0; private final int CAMERA2 = 1; private Button mButtonOpenCamera1 = null; private Button mButtonOpenCamera2 = null; private Button mButtonToMakeShot = null; private TextureView mImageView = null; @RequiresApi(api = Build.VERSION_CODES.M) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.d(LOG_TAG, " "); if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED || (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) ) { requestPermissions(new String[]{Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE},1); } mButtonOpenCamera1 = findViewById(R.id.button1); mButtonOpenCamera2 = findViewById(R.id.button2); mButtonToMakeShot =findViewById(R.id.button3); mImageView = findViewById(R.id.textureView); mButtonOpenCamera1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (myCameras[CAMERA2].isOpen()) {myCameras[CAMERA2].closeCamera();} if (myCameras[CAMERA1] != null) { if (!myCameras[CAMERA1].isOpen()) myCameras[CAMERA1].openCamera(); } } }); mButtonOpenCamera2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (myCameras[CAMERA1].isOpen()) {myCameras[CAMERA1].closeCamera();} if (myCameras[CAMERA2] != null) { if (!myCameras[CAMERA2].isOpen()) myCameras[CAMERA2].openCamera(); } } }); mButtonToMakeShot.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) {
Kami memuat, mulai, bekerja!
Secara umum, jika ini tidak cukup untuk Anda, proses pemotretan itu sendiri dapat sangat beragam. Tomoaki Jepang kami menunjukkan dan menjelaskan caranya, membawa diagram yang indah.

Pertama, kamera perlu fokus. Ini biasanya tidak menyebabkan masalah, tetapi kadang-kadang membutuhkan beberapa upaya, yang juga dilaksanakan melalui panggilan balik.
CameraCaptureSession.StateCallback().
Kemudian kamera memasuki mode pratinjau PRECAPTURE. Pada tahap ini, kamera menghitung exposure, white balance, dan aperture (saya dulu tahu apa itu di masa kanak-kanak, tapi sekarang pengetahuan ini hilang). Terkadang panggilan balik dapat mengembalikan permintaan CONTROL_AE_STATE_FLASH_REQUIRED, yang berarti "alangkah baiknya menyalakan lampu kilat." Ini dapat dihidupkan secara otomatis dengan cara - setAutoFlash (mPreviewRequestBuilder).
Ketika semua parameter yang diperlukan untuk pemotretan ditentukan, maka panggilan balik mengembalikan status CONTROL_AE_STATE_CONVERGED memberi sinyal kepada kami bahwa kamera siap untuk mengambil gambar.
Pada halaman googloid, semua ini sudah ada dalam contoh, dan jika Anda memiliki kesabaran untuk menerobos ladang ranjau dan pagar kawat, maka kehormatan bagi Anda.
Ambil gambar dan simpan gambar ke fileDi sinilah saya mulai mengalami masalah.
Tidak, kalau dilihat dari diagram blok di atas (bukan Jepang, tetapi yang sebelumnya), semuanya tampaknya tidak terlalu rumit. Kami sedang menunggu kamera untuk mengambil gambar. Setelah diproses dengan kelas CamerCaptureSession, itu akan tersedia sebagai objek Permukaan, yang pada gilirannya dapat diproses menggunakan kelas ImageReader.Yang benar adalah, untuk membuat objek ImageReader lagi, butuh waktu. Kami menunggu saat ini di pendengar berikutnya bernama OnImageAvailableListener. Dan akhirnya, dengan bantuan instance dari kelas ImageSaver terakhir, kami menyimpan gambar ke file dan tentu saja kami melakukannya secara asinkron juga, karena ImageSaver Runnable di sini.Masalahnya adalah saya tidak bisa melampirkan ImageReader ini di mana pun, karena panggilan balik dari CameraCaptureSession.StateCallback () sudah sibuk menyiarkan video ke tampilan smartphone. Dan jika saya melakukan sesi baru, maka Android diprediksi akan mengutuk dan menutup aplikasi. Akibatnya (jangan tanya saya bagaimana) saya berhasil melintasi kuda dan rusa betina dalam satu metode createCameraPreviewSession (), yang digunakan untuk menampilkan gambar kamera hanya pada tampilan.Ini potongan kode ini sebelumnya: private void createCameraPreviewSession() { SurfaceTexture texture = mImageView.getSurfaceTexture(); Surface surface = new Surface(texture); try { final CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); builder.addTarget(surface); mCameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() …….
Dan di sini dia mengejar: private ImageReader mImageReader; private void createCameraPreviewSession() { mImageReader = ImageReader.newInstance(1920,1080,ImageFormat.JPEG,1); mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, null); SurfaceTexture texture = mImageView.getSurfaceTexture(); Surface surface = new Surface(texture); try { final CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); builder.addTarget(surface); mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()), new CameraCaptureSession.StateCallback() ……
Perbedaannya, terlepas dari definisi instance ImageReader di bagian atas, hampir sulit dipahami. Baru saja ditambahkan ke permukaan, koma dipisahkan mImageReader.getSurface () dan hanya itu. Tetapi sampai Anda mencapainya ...Dari saat itu segalanya menjadi lebih menyenangkan dan Anda dapat menggunakan tombol layar ketiga "Ambil Gambar". Ketika ditekan, metode makePhoto () disebut (yah, siapa sangka): mButtonToMakeShot.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (myCameras[CAMERA1].isOpen()) myCameras[CAMERA1].makePhoto(); if (myCameras[CAMERA2].isOpen()) myCameras[CAMERA2].makePhoto(); } }); …… public class CameraService { public void makePhoto (){ try {
Dan segera setelah itu kita menulis pendengar OnImageAvailableListener: private final ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { { Toast.makeText(MainActivity.this," ", Toast.LENGTH_SHORT).show();} } };
Meskipun dia tidak melakukan apa-apa, dia hanya memberi isyarat dengan bersulang bahwa mereka mengatakan semuanya beres, Anda dapat menyimpan gambar ke file.Dan untuk ini kita perlu file itu sendiri: public class CameraService { private File mFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "test1.jpg");;
Dan juga objek khusus dari kelas ImageSaver, yang dengan cepat mentransfer data dari gambar ke buffer byte, dan dari sana ke file biner.Kelas ini statis dan Runnable. Oleh karena itu, kami menempatkannya di MainActivity sendiri: private static class ImageSaver implements Runnable { private final File mFile; ImageSaver(Image image, File file) { mImage = image; mFile = file; } @Override public void run() { ByteBuffer buffer = mImage.getPlanes()[0].getBuffer(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes); FileOutputStream output = null; try { output = new FileOutputStream(mFile); output.write(bytes); } catch (IOException e) { e.printStackTrace(); } finally { mImage.close(); if (null != output) { try { output.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
Dan agar berfungsi, kami juga menulis di pendengar OnImageAvailableListener: mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile));
TUNGGU! OH SHIT !!Apa lagi mBackgroundHandler ??? Tetap saja, itu bekerja dengan sempurna tanpa dia.Namun pada kenyataannya, pertanyaan yang tepat adalah - bagaimana cara kerjanya tanpa itu? Karena, sebagaimana dijabarkan dalam contoh Google, BackgroundHandler menyediakan BackgroundThread, yang pada gilirannya adalah utas yang bekerja di latar belakang dan sebenarnya bertanggung jawab atas kamera. Dan faktanya, kita harus mendaftar di awal Kegiatan kita: private HandlerThread mBackgroundThread; private Handler mBackgroundHandler = null; private void startBackgroundThread() { mBackgroundThread = new HandlerThread("CameraBackground"); mBackgroundThread.start(); mBackgroundHandler = new Handler(mBackgroundThread.getLooper()); } private void stopBackgroundThread() { mBackgroundThread.quitSafely(); try { mBackgroundThread.join(); mBackgroundThread = null; mBackgroundHandler = null; } catch (InterruptedException e) { e.printStackTrace(); } }
Tidak hanya itu, Anda masih perlu menambahkan awal dan berhenti dari BackgroundThread di sini juga: public void onPause() { super.onPause(); stopBackgroundThread(); } @Override public void onResume() { super.onResume(); startBackgroundThread(); }
Sedangkan untuk mBackgroundHandler, harus ditambahkan ke semua panggilan balik kami yang membutuhkan handler dan di mana kami, tanpa khawatir, menulis null sebagai gantinya.Hal yang paling menarik adalah bahwa kita JANGAN memulai utas latar belakang ini ketika kita membuka aplikasi, karena mudah dilihat dari teks program. Yaitu, itu dimulai secara implisit dan tanpa bantuan kami. Tetapi kita harus menghentikannya dan menjalankannya dalam mode onPause () dan onResume (). Beberapa jenis kontradiksi muncul di sini.Tetapi sekarang gambar berhasil disimpan ke file. Ini mudah diverifikasi dengan menjalankan aplikasi. Seperti kata pepatah, mahkota kerja di atas semua penghargaan.
Benar, gambarnya ada di sisinya, tetapi untuk menyelesaikan masalah ini adalah tugas generasi mendatang.Daftar lengkap program package com.example.camera; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.ContextCompat; import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; import android.graphics.ImageFormat; import android.graphics.SurfaceTexture; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraManager; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.TotalCaptureResult; import android.media.Image; import android.media.ImageReader; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.util.Log; import android.view.Surface; import android.view.TextureView; import android.view.View; import android.widget.Button; import android.widget.Toast; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.util.Arrays; public class MainActivity extends AppCompatActivity { public static final String LOG_TAG = "myLogs"; CameraService[] myCameras = null; private CameraManager mCameraManager = null; private final int CAMERA1 = 0; private final int CAMERA2 = 1; private Button mButtonOpenCamera1 = null; private Button mButtonOpenCamera2 = null; private Button mButtonToMakeShot = null; private TextureView mImageView = null; private HandlerThread mBackgroundThread; private Handler mBackgroundHandler = null; private void startBackgroundThread() { mBackgroundThread = new HandlerThread("CameraBackground"); mBackgroundThread.start(); mBackgroundHandler = new Handler(mBackgroundThread.getLooper()); } private void stopBackgroundThread() { mBackgroundThread.quitSafely(); try { mBackgroundThread.join(); mBackgroundThread = null; mBackgroundHandler = null; } catch (InterruptedException e) { e.printStackTrace(); } } @RequiresApi(api = Build.VERSION_CODES.M) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.d(LOG_TAG, " "); if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED || (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) ) { requestPermissions(new String[]{Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE},1); } mButtonOpenCamera1 = findViewById(R.id.button1); mButtonOpenCamera2 = findViewById(R.id.button2); mButtonToMakeShot =findViewById(R.id.button3); mImageView = findViewById(R.id.textureView); mButtonOpenCamera1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (myCameras[CAMERA2].isOpen()) {myCameras[CAMERA2].closeCamera();} if (myCameras[CAMERA1] != null) { if (!myCameras[CAMERA1].isOpen()) myCameras[CAMERA1].openCamera(); } } }); mButtonOpenCamera2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (myCameras[CAMERA1].isOpen()) {myCameras[CAMERA1].closeCamera();} if (myCameras[CAMERA2] != null) { if (!myCameras[CAMERA2].isOpen()) myCameras[CAMERA2].openCamera(); } } }); mButtonToMakeShot.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (myCameras[CAMERA1].isOpen()) myCameras[CAMERA1].makePhoto(); if (myCameras[CAMERA2].isOpen()) myCameras[CAMERA2].makePhoto(); } }); mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try{