1. Sebelum memulai
Apa yang istimewa dari perangkat foldable?
Perangkat foldable adalah inovasi yang hanya terjadi sekali dalam satu generasi. Perangkat ini memberikan pengalaman unik, dan disertai peluang unik untuk menyenangkan pengguna Anda dengan fitur yang berbeda seperti UI dalam mode di atas meja untuk penggunaan handsfree.
Prasyarat
- Pengetahuan dasar tentang pengembangan aplikasi Android
- Pengetahuan dasar framework Injeksi Dependensi dengan Hilt
Yang akan Anda bangun
Dalam codelab ini, Anda membangun aplikasi kamera dengan tata letak yang dioptimalkan untuk perangkat foldable.
Anda mulai dengan aplikasi kamera dasar yang tidak bereaksi terhadap postur perangkat apa pun atau memanfaatkan kamera belakang yang lebih baik untuk mendapatkan hasil selfie yang lebih sempurna. Anda memperbarui kode sumber untuk memindahkan pratinjau ke layar yang lebih kecil saat perangkat dibentangkan dan bereaksi terhadap ponsel yang diatur dalam mode di atas meja.
Meskipun aplikasi kamera adalah kasus penggunaan yang paling nyaman untuk API ini, kedua fitur yang Anda pelajari dalam codelab ini dapat diterapkan ke aplikasi apa pun.
Yang akan Anda pelajari
- Cara menggunakan Jetpack Window Manager untuk bereaksi terhadap perubahan postur
- Cara memindahkan aplikasi Anda ke layar perangkat foldable yang lebih kecil
Yang akan Anda butuhkan
- Versi terbaru Android Studio
- Perangkat foldable atau emulator perangkat foldable
2. Memulai persiapan
Mendapatkan kode awal
- Jika sudah menginstal Git, Anda cukup menjalankan perintah di bawah ini. Untuk memeriksa apakah Git sudah diinstal atau belum, ketik
git --version
di terminal atau command line dan pastikan Git dijalankan dengan benar.
git clone https://github.com/android/large-screen-codelabs.git
- Opsional: Jika tidak memiliki Git, Anda dapat mengklik tombol berikut untuk mendownload semua kode untuk codelab ini:
Membuka modul pertama
- Di Android Studio, buka modul pertama di
/step1
.
Jika Anda diminta untuk menggunakan versi Gradle terbaru, lanjutkan lalu update.
3. Menjalankan dan mengamati
- Jalankan kode pada modul
step1
.
Seperti yang Anda lihat, ini adalah aplikasi kamera sederhana. Anda dapat beralih antara kamera depan dan belakang serta menyesuaikan rasio aspek. Namun, tombol pertama dari kiri saat ini tidak memiliki fungsi apa pun—tetapi ini akan menjadi titik masuk untuk mode Selfie Belakang.
- Sekarang, coba letakkan perangkat dalam posisi setengah terbuka, di mana engselnya tidak sepenuhnya lurus atau tertutup, tetapi membentuk sudut 90 derajat.
Seperti yang Anda lihat, aplikasi tidak merespons postur perangkat yang berbeda dan tata letaknya juga tidak berubah, sehingga engsel berada di tengah jendela bidik.
4. Mempelajari Jetpack WindowManager
Library Jetpack WindowManager membantu developer aplikasi membuat pengalaman yang dioptimalkan untuk perangkat foldable. Library ini berisi class FoldingFeature
yang menjelaskan lipatan di layar yang fleksibel atau engsel di antara dua panel layar fisik. API-nya memberikan akses ke informasi penting yang berkaitan dengan perangkat:
state()
menampilkanFLAT
jika engsel dibuka 180 derajat atauHALF_OPENED
jika engsel dibuka 90 derajat.orientation()
menampilkanFoldingFeature.Orientation.HORIZONTAL
jika lebarFoldingFeature
lebih besar dari tingginya; jika tidak, class ini akan menampilkanFoldingFeature.Orientation.VERTICAL
.bounds()
menyediakan batasanFoldingFeature
dalam formatRect
.
Class FoldingFeature
berisi informasi tambahan, seperti occlusionType()
atau isSeparating()
, tetapi codelabe ini tidak membahasnya secara mendalam.
Mulai versi 1.1.0-beta01, library ini menggunakan WindowAreaController
, sebuah API yang memungkinkan Mode Tampilan Belakang memindahkan jendela saat ini ke tampilan yang sejajar dengan kamera belakang, yang sangat cocok untuk berfoto selfie menggunakan kamera belakang serta banyak kasus penggunaan lainnya.
Menambahkan dependensi
- Untuk menggunakan Jetpack WindowManager di aplikasi Anda, tambahkan dependensi berikut ke file
build.gradle
level modul Anda:
step1/build.gradle
def work_version = '1.1.0-beta01'
implementation "androidx.window:window:$work_version"
implementation "androidx.window:window-java:$work_version"
implementation "androidx.window:window-core:$work_version"
Sekarang Anda dapat mengakses class FoldingFeature
dan WindowAreaController
di aplikasi Anda. Gunakan kedua class tersebut untuk membuat pengalaman kamera terbaik pada perangkat foldable.
5. Mengimplementasikan mode Selfie Belakang
Mulai dengan mode Tampilan Belakang. API yang memungkinkan mode ini adalah WindowAreaControllerJavaAdapter
, yang memerlukan Executor
dan menampilkan WindowAreaSession
yang menyimpan keadaan saat ini. Class WindowAreaSession
ini harus dipertahankan saat Activity
Anda dihancurkan dan dibuat ulang. Oleh karena itu, Anda perlu menyimpannya di dalam ViewModel
agar class ini tersimpan dengan aman saat terjadi perubahan konfigurasi.
- Deklarasikan variabel ini di
MainActivity
Anda:
step1/MainActivity.kt
private lateinit var windowAreaController: WindowAreaControllerJavaAdapter
private lateinit var displayExecutor: Executor
- Dan inisialisasi variabel tersebut dalam metode
onCreate()
:
step1/MainActivity.kt
windowInfoTracker = WindowInfoTracker.getOrCreate(this)
displayExecutor = ContextCompat.getMainExecutor(this)
windowAreaController = WindowAreaControllerJavaAdapter(WindowAreaController.getOrCreate())
Sekarang Activity
Anda siap untuk memindahkan konten ke layar yang lebih kecil, tetapi Anda perlu menyimpan sesi tersebut.
- Untuk menyimpan sesi, buka
CameraViewModel
dan deklarasikan variabel ini di dalamnya:
step1/CameraViewModel.kt
var rearDisplaySession: WindowAreaSession? = null
private set
rearDisplaySession
harus bersifat variabel, karena kode ini berubah setiap kali Anda membuatnya. Namun, pastikan kode tidak dapat diperbarui dari luar karena Anda sekarang membuat metode yang memperbaruinya kapan pun diperlukan.
- Tempelkan kode ini di dalam
CameraViewModel
:
step1/CameraViewModel.kt
fun updateSession(newSession: WindowAreaSession? = null) {
rearDisplaySession = newSession
}
Metode ini dipanggil setiap kali kode Anda perlu memperbarui sesi, dan sebaiknya ini dienkapsulasi dalam satu titik akses.
Rear Display API bekerja dengan pendekatan pemroses: saat Anda meminta untuk memindahkan konten ke layar yang lebih kecil, Anda memulai sesi yang dihasilkan melalui metode onSessionStarted()
pemroses. Jika ingin kembali ke layar dalam (dan lebih besar), tutup sesi, dan Anda mendapatkan konfirmasi dalam metode onSessionEnded()
. Anda memanfaatkan metode ini untuk memperbarui rearDisplaySession
di dalam CameraViewModel
. Untuk membuat pemroses seperti itu, Anda perlu mengimplementasikan antarmuka WindowAreaSessionCallback
.
- Ubah deklarasi
MainActivity
agar mengimplementasikan antarmukaWindowAreaSessionCallback
:
step1/MainActivity.kt
class MainActivity : AppCompatActivity(), WindowAreaSessionCallback
Sekarang, terapkan metode onSessionStarted
dan onSessionEnded
di dalam MainActivity
. Untuk metode pertama, sebaiknya simpan WindowAreaSession
, dan dalam metode kedua, reset ke null
. Hal ini sangat berguna karena keberadaan WindowAreaSession
memungkinkan Anda memutuskan apakah akan memulai sesi atau menutup sesi yang sudah ada.
step1/MainActivity.kt
override fun onSessionEnded() {
viewModel.updateSession(null)
}
override fun onSessionStarted(session: WindowAreaSession) {
viewModel.updateSession(session)
}
- Di dalam file
MainActivity.kt
, tulis kode terakhir yang diperlukan agar API ini berfungsi:
step1/MainActivity.kt
private fun startRearDisplayMode() {
if (viewModel.rearDisplaySession != null) {
viewModel.rearDisplaySession?.close()
} else {
windowAreaController.startRearDisplayModeSession(
this,
displayExecutor,
this
)
}
}
Seperti disebutkan sebelumnya, untuk memahami tindakan apa yang harus diambil, Anda perlu memeriksa keberadaan rearDisplaySession
di dalam CameraViewModel
: jika yang ditampilkan bukan null
, berarti sesi sudah berlangsung, sehingga sesi tersebut ditutup. Di sisi lain, jika yang ditampilkan adalah null
, Anda menggunakan windowAreaController
untuk memulai sesi baru, dengan meneruskan Activity
dua kali. Yang pertama digunakan sebagai Context
dan yang kedua sebagai pemroses WindowAreaSessionCallback
.
- Sekarang, bangun dan jalankan aplikasi. Jika Anda kemudian membentangkan perangkat dan mengetuk tombol tampilan belakang, Anda akan dihadapkan pada pesan seperti ini:
- Klik Beralih layar sekarang dan lihat konten Anda dipindahkan ke layar luar.
6. Mengimplementasikan Mode di atas meja
Sekarang saatnya membuat aplikasi Anda fold-aware: pindahkan konten ke samping atau ke atas engsel perangkat berdasarkan orientasi lipatan. Untuk melakukannya, Anda akan bertindak di dalam FoldingStateActor
sehingga kode Anda dipisahkan dari Activity
agar lebih mudah dibaca.
Bagian inti dari API ini terdiri dari antarmuka WindowInfoTracker
, yang dibuat dengan metode statis yang memerlukan Activity
:
step1/CameraCodelabDependencies.kt
@Provides
fun provideWindowInfoTracker(activity: Activity) =
WindowInfoTracker.getOrCreate(activity)
Anda tidak perlu menulis kode ini karena sudah ada, tetapi akan berguna untuk memahami bagaimana WindowInfoTracker
dibangun.
- Untuk memproses perubahan jendela apa pun, proses perubahan ini dalam metode
onResume()
dariActivity
Anda:
step1/MainActivity.kt
lifecycleScope.launch {
foldingStateActor.checkFoldingState(
this@MainActivity,
binding.viewFinder
)
}
- Sekarang, buka file
FoldingStateActor
, karena sudah saatnya memasukkan metodecheckFoldingState()
.
Seperti yang sudah Anda lihat, metode ini berjalan dalam fase RESUMED
dari Activity
Anda, dan memanfaatkan WindowInfoTracker
untuk memproses perubahan tata letak apa pun.
step1/FoldingStateActor.kt
windowInfoTracker.windowLayoutInfo(activity)
.collect { newLayoutInfo ->
activeWindowLayoutInfo = newLayoutInfo
updateLayoutByFoldingState(cameraViewfinder)
}
Dengan menggunakan antarmuka WindowInfoTracker
, Anda dapat memanggil windowLayoutInfo()
untuk mengumpulkan Flow
dari WindowLayoutInfo
yang berisi semua informasi yang tersedia di DisplayFeature
.
Langkah terakhir adalah bereaksi terhadap perubahan ini dan memindahkan konten yang sesuai. Anda melakukan ini di dalam metode updateLayoutByFoldingState()
, selangkah demi selangkah.
- Pastikan
activityLayoutInfo
berisi beberapa propertiDisplayFeature
, dan setidaknya salah satunya adalahFoldingFeature
. Jika tidak, Anda tidak perlu melakukan apa pun:
step1/FoldingStateActor.kt
val foldingFeature = activeWindowLayoutInfo?.displayFeatures
?.firstOrNull { it is FoldingFeature } as FoldingFeature?
?: return
- Hitung posisi lipatan untuk memastikan posisi perangkat memengaruhi tata letak Anda dan tidak berada di luar batas hierarki Anda:
step1/FoldingStateActor.kt
val foldPosition = FoldableUtils.getFeaturePositionInViewRect(
foldingFeature,
cameraViewfinder.parent as View
) ?: return
Sekarang, Anda yakin telah memiliki FoldingFeature
yang memengaruhi tata letak, jadi Anda perlu memindahkan konten Anda.
- Periksa apakah
FoldingFeature
menampilkanHALF_OPEN
atau cukup pulihkan posisi konten Anda. Jika yang ditampilkan adalahHALF_OPEN
, Anda perlu menjalankan pemeriksaan lain dan bertindak berbeda berdasarkan orientasi lipatan:
step1/FoldingStateActor.kt
if (foldingFeature.state == FoldingFeature.State.HALF_OPENED) {
when (foldingFeature.orientation) {
FoldingFeature.Orientation.VERTICAL -> {
cameraViewfinder.moveToRightOf(foldPosition)
}
FoldingFeature.Orientation.HORIZONTAL -> {
cameraViewfinder.moveToTopOf(foldPosition)
}
}
} else {
cameraViewfinder.restore()
}
Jika lipatannya VERTICAL
, Anda memindahkan konten ke kanan. Jika tidak, Anda memindahkannya ke atas posisi lipatan.
- Bangun dan jalankan aplikasi Anda, lalu bentangkan perangkat Anda dan tempatkan dalam mode di atas meja untuk melihat konten bergerak sebagaimana yang dimaksudkan.
7. Selamat
Dalam codelab ini, Anda telah mempelajari keistimewaan perangkat foldable, perubahan postur, dan Rear Display API.