1. Sebelum memulai
Apa yang istimewa dari perangkat foldable?
Perangkat foldable adalah inovasi yang hanya terjadi sekali dalam satu generasi. Perangkat foldable 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 akan 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 baik. 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 praktis 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 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, 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. Hal ini akan menjadi titik entri 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 membangun 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 tidak.orientation()
menampilkanFoldingFeature.Orientation.HORIZONTAL
jika lebarFoldingFeature
lebih besar dari tinggi; jika tidak, 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.2.0-beta01, library ini menggunakan WindowAreaController
, sebuah API yang memungkinkan Mode Tampilan Belakang memindahkan jendela saat ini ke layar 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.2.0'
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 membangun pengalaman kamera terbaik pada perangkat foldable.
5. Mengimplementasikan mode Selfie Belakang
Mulai dengan mode Tampilan Belakang.
API yang memungkinkan mode ini adalah WindowAreaController
, yang memberikan informasi dan perilaku terkait perpindahan jendela di antara layar atau area layar pada perangkat.
API ini memungkinkan Anda membuat kueri daftar WindowAreaInfo
yang saat ini tersedia untuk interaksi.
Dengan menggunakan WindowAreaInfo
, Anda dapat mengakses WindowAreaSession
, sebuah antarmuka untuk menampilkan fitur area jendela aktif dan status ketersediaan untuk WindowAreaCapability.
tertentu
- Deklarasikan variabel ini di
MainActivity
Anda:
step1/MainActivity.kt
private lateinit var windowAreaController: WindowAreaController
private lateinit var displayExecutor: Executor
private var rearDisplaySession: WindowAreaSession? = null
private var rearDisplayWindowAreaInfo: WindowAreaInfo? = null
private var rearDisplayStatus: WindowAreaCapability.Status =
WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNSUPPORTED
private val rearDisplayOperation = WindowAreaCapability.Operation.OPERATION_TRANSFER_ACTIVITY_TO_AREA
- Dan inisialisasi variabel tersebut dalam metode
onCreate()
:
step1/MainActivity.kt
displayExecutor = ContextCompat.getMainExecutor(this)
windowAreaController = WindowAreaController.getOrCreate()
lifecycleScope.launch(Dispatchers.Main) {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
windowAreaController.windowAreaInfos
.map{info->info.firstOrNull{it.type==WindowAreaInfo.Type.TYPE_REAR_FACING}}
.onEach { info -> rearDisplayWindowAreaInfo = info }
.map{it?.getCapability(rearDisplayOperation)?.status?: WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNSUPPORTED }
.distinctUntilChanged()
.collect {
rearDisplayStatus = it
updateUI()
}
}
}
- Sekarang, implementasikan fungsi
updateUI()
untuk mengaktifkan atau menonaktifkan tombol selfie belakang, bergantung pada status saat ini:
step1/MainActivity.kt
private fun updateUI() {
if(rearDisplaySession != null) {
binding.rearDisplay.isEnabled = true
// A session is already active, clicking on the button will disable it
} else {
when(rearDisplayStatus) {
WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNSUPPORTED -> {
binding.rearDisplay.isEnabled = false
// RearDisplay Mode is not supported on this device"
}
WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNAVAILABLE -> {
binding.rearDisplay.isEnabled = false
// RearDisplay Mode is not currently available
}
WindowAreaCapability.Status.WINDOW_AREA_STATUS_AVAILABLE -> {
binding.rearDisplay.isEnabled = true
// You can enable RearDisplay Mode
}
WindowAreaCapability.Status.WINDOW_AREA_STATUS_ACTIVE -> {
binding.rearDisplay.isEnabled = true
// You can disable RearDisplay Mode
}
else -> {
binding.rearDisplay.isEnabled = false
// RearDisplay status is unknown
}
}
}
}
Langkah terakhir ini bersifat opsional, tetapi sangat berguna untuk mempelajari semua kemungkinan status WindowAreaCapability.
- Sekarang, terapkan fungsi
toggleRearDisplayMode
, yang akan menutup sesi, jika kemampuan sudah aktif, atau panggil fungsitransferActivityToWindowArea
:
step1/CameraViewModel.kt
private fun toggleRearDisplayMode() {
if(rearDisplayStatus == WindowAreaCapability.Status.WINDOW_AREA_STATUS_ACTIVE) {
if(rearDisplaySession == null) {
rearDisplaySession = rearDisplayWindowAreaInfo?.getActiveSession(rearDisplayOperation)
}
rearDisplaySession?.close()
} else {
rearDisplayWindowAreaInfo?.token?.let { token ->
windowAreaController.transferActivityToWindowArea(
token = token,
activity = this,
executor = displayExecutor,
windowAreaSessionCallback = this
)
}
}
}
Perhatikan penggunaan MainActivity
sebagai WindowAreaSessionCallback
.
Rear Display API berfungsi dengan pendekatan pemroses: saat Anda meminta untuk memindahkan konten ke layar lain, Anda akan memulai sesi yang ditampilkan melalui metode onSessionStarted()
pemroses. Jika ingin kembali ke layar dalam (dan yang lebih besar), tutup sesi, dan Anda mendapatkan konfirmasi dalam metode onSessionEnded()
. 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
. Metode callback tersebut sangat berguna untuk mendapatkan notifikasi tentang status sesi dan mengupdate aplikasi.
Untuk kali ini, agar lebih mudah, cukup periksa body fungsi jika ada error dan catat statusnya.
step1/MainActivity.kt
override fun onSessionEnded(t: Throwable?) {
if(t != null) {
Log.d("Something was broken: ${t.message}")
}else{
Log.d("rear session ended")
}
}
override fun onSessionStarted(session: WindowAreaSession) {
Log.d("rear session started [session=$session]")
}
- Bangun dan jalankan aplikasi. Jika Anda kemudian membentangkan perangkat dan mengetuk tombol layar belakang, Anda akan melihat pesan seperti ini:
- Pilih "Switch screens now" untuk melihat 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 hal 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 beberapa kemampuan unik untuk perangkat foldable, seperti Mode Tampilan Belakang atau Mode di atas meja, serta cara menggunakannya menggunakan Jetpack WindowManager.
Anda siap menerapkan pengalaman pengguna yang luar biasa untuk aplikasi kamera Anda.