Pembaruan yang dilakukan pada area khusus tampilan ini disediakan di bawah:
- Mengubah ukuran aktivitas dan tampilan
- Ukuran tampilan dan rasio aspek
- Tampilkan kebijakan
- Pengaturan jendela tampilan
- Pengidentifikasi tampilan statis
- Menggunakan lebih dari dua tampilan
- Fokus per tampilan
Ubah ukuran aktivitas dan tampilan
Untuk menunjukkan bahwa aplikasi mungkin tidak mendukung mode multi-jendela atau pengubahan ukuran, aktivitas menggunakan atribut resizeableActivity=false
. Masalah umum yang dihadapi oleh aplikasi saat aktivitas diubah ukurannya meliputi:
- Suatu aktivitas dapat memiliki konfigurasi yang berbeda dari aplikasi atau komponen non-visual lainnya. Kesalahan umum adalah membaca metrik tampilan dari konteks aplikasi. Nilai yang dikembalikan tidak akan disesuaikan dengan metrik area yang terlihat di mana aktivitas ditampilkan.
- Suatu aktivitas mungkin tidak dapat menangani pengubahan ukuran dan error, menampilkan UI yang terdistorsi, atau kehilangan status karena peluncuran ulang tanpa menyimpan status instance.
- Suatu aplikasi mungkin mencoba menggunakan koordinat masukan absolut (bukan koordinat relatif terhadap posisi jendela), yang dapat merusak masukan dalam multi-jendela.
Di Android 7 (dan lebih tinggi), aplikasi dapat disetel resizeableActivity=false
agar selalu berjalan dalam mode layar penuh. Dalam hal ini, platform mencegah aktivitas yang tidak dapat diubah ukurannya masuk ke layar terpisah. Jika pengguna mencoba menjalankan aktivitas yang tidak dapat diubah ukurannya dari peluncur saat sudah berada dalam mode layar terpisah, platform akan keluar dari mode layar terpisah dan meluncurkan aktivitas yang tidak dapat diubah ukurannya dalam mode layar penuh.
Aplikasi yang secara eksplisit menyetel atribut ini ke false
dalam manifes tidak boleh diluncurkan dalam mode multi-jendela, kecuali mode kompatibilitas diterapkan:
- Konfigurasi yang sama diterapkan pada proses, yang berisi semua komponen aktivitas dan non-aktivitas.
- Konfigurasi yang diterapkan memenuhi persyaratan CDD untuk tampilan yang kompatibel dengan aplikasi.
Di Android 10, platform masih mencegah aktivitas yang tidak dapat diubah ukurannya masuk ke mode layar terpisah, namun aktivitas tersebut dapat diskalakan untuk sementara jika aktivitas tersebut telah menyatakan orientasi atau rasio aspek tetap. Jika tidak, aktivitas akan diubah ukurannya hingga memenuhi seluruh layar seperti di Android 9 dan lebih rendah.
Implementasi default menerapkan kebijakan berikut:
Ketika suatu aktivitas dinyatakan tidak kompatibel dengan multi-jendela melalui penggunaan atribut android:resizeableActivity
dan ketika aktivitas tersebut memenuhi salah satu kondisi yang dijelaskan di bawah, maka ketika konfigurasi layar yang diterapkan harus berubah, aktivitas dan proses disimpan dengan konfigurasi asli dan pengguna diberikan kemampuan untuk meluncurkan kembali proses aplikasi untuk menggunakan konfigurasi layar yang diperbarui.
- Apakah orientasi tetap melalui aplikasi
android:screenOrientation
- Aplikasi memiliki rasio aspek maksimum atau minimum default dengan menargetkan tingkat API atau menyatakan rasio aspek secara eksplisit
Gambar ini menampilkan aktivitas yang tidak dapat diubah ukurannya dengan rasio aspek yang dinyatakan. Saat melipat perangkat, jendela diperkecil agar sesuai dengan area sambil mempertahankan rasio aspek menggunakan kotak surat yang sesuai. Selain itu, opsi memulai ulang aktivitas diberikan kepada pengguna setiap kali area tampilan aktivitas diubah.
Saat membuka perangkat, konfigurasi, ukuran, dan rasio aspek aktivitas tidak berubah, namun opsi untuk memulai ulang aktivitas ditampilkan.
Jika resizeableActivity
tidak disetel (atau disetel ke true
), aplikasi sepenuhnya mendukung pengubahan ukuran.
Penerapan
Aktivitas yang tidak dapat diubah ukurannya dengan orientasi atau rasio aspek tetap disebut mode kompatibilitas ukuran (SCM) dalam kode. Kondisi ini ditentukan dalam ActivityRecord#shouldUseSizeCompatMode()
. Saat aktivitas SCM diluncurkan, konfigurasi terkait layar (seperti ukuran atau kepadatan) ditetapkan dalam konfigurasi penggantian yang diminta, sehingga aktivitas tidak lagi bergantung pada konfigurasi tampilan saat ini.
Jika aktivitas SCM tidak dapat memenuhi seluruh layar, maka aktivitas tersebut akan disejajarkan bagian atas dan berada di tengah secara horizontal. Batas aktivitas dihitung dengan AppWindowToken#calculateCompatBoundsTransformation()
.
Ketika aktivitas SCM menggunakan konfigurasi layar yang berbeda dari kontainernya (misalnya, ukuran tampilan diubah, atau aktivitas dipindahkan ke tampilan lain), ActivityRecord#inSizeCompatMode()
bernilai true dan SizeCompatModeActivityController
(di UI Sistem) menerima callback untuk menampilkan prosesnya tombol mulai ulang.
Ukuran tampilan dan rasio aspek
Android 10 memberikan dukungan untuk rasio aspek baru dari rasio tinggi pada layar panjang dan tipis hingga rasio 1:1. Aplikasi dapat menentukan ApplicationInfo#maxAspectRatio
dan ApplicationInfo#minAspectRatio
layar yang dapat ditangani.
Gambar 1. Contoh rasio aplikasi yang didukung di Android 10
Implementasi perangkat dapat memiliki layar sekunder dengan ukuran dan resolusi lebih kecil dari yang disyaratkan oleh Android 9, dan lebih rendah (lebar atau tinggi minimum 2,5 inci, minimum 320 DP untuk smallestScreenWidth
), namun hanya aktivitas yang ikut serta untuk mendukung layar kecil ini yang dapat ditempatkan di sana.
Aplikasi dapat ikut serta dengan menyatakan ukuran minimum yang didukung yang lebih kecil dari oe sama dengan ukuran tampilan target. Gunakan atribut tata letak aktivitas android:minHeight
dan android:minWidth
di AndroidManifest untuk melakukannya.
Tampilkan kebijakan
Android 10 memisahkan dan memindahkan kebijakan tampilan tertentu dari implementasi WindowManagerPolicy
default di PhoneWindowManager
ke kelas per tampilan, seperti:
- Status tampilan dan rotasi
- Beberapa tombol dan pelacakan peristiwa gerak
- UI sistem dan jendela dekorasi
Di Android 9 (dan lebih rendah), kelas PhoneWindowManager
menangani kebijakan tampilan, status dan pengaturan, rotasi, pelacakan bingkai jendela dekorasi, dan banyak lagi. Android 10 memindahkan sebagian besarnya ke kelas DisplayPolicy
, kecuali pelacakan rotasi, yang telah dipindahkan ke DisplayRotation
.
Pengaturan jendela tampilan
Di Android 10, pengaturan jendela per tampilan yang dapat dikonfigurasi telah diperluas untuk mencakup:
- Mode jendela tampilan default
- Nilai pemindaian berlebihan
- Rotasi pengguna dan mode rotasi
- Ukuran paksa, kepadatan, dan mode penskalaan
- Mode penghapusan konten (saat tampilan dihapus)
- Dukungan untuk dekorasi sistem dan IME
Kelas DisplayWindowSettings
berisi pengaturan untuk opsi ini. Mereka tetap berada di disk di partisi /data
di display_settings.xml
setiap kali pengaturan diubah. Untuk detailnya, lihat DisplayWindowSettings.AtomicFileStorage
dan DisplayWindowSettings#writeSettings()
. Produsen perangkat dapat memberikan nilai default di display_settings.xml
untuk konfigurasi perangkat mereka. Namun, karena file disimpan di /data
, logika tambahan mungkin diperlukan untuk memulihkan file jika terhapus dengan penghapusan.
Secara default, Android 10 menggunakan DisplayInfo#uniqueId
sebagai pengidentifikasi tampilan saat mempertahankan setelan. uniqueId
harus diisi untuk semua tampilan. Selain itu, stabil untuk tampilan fisik dan jaringan. Port tampilan fisik juga dapat digunakan sebagai pengidentifikasi, yang dapat diatur di DisplayWindowSettings#mIdentifier
. Pada setiap penulisan, semua pengaturan ditulis sehingga aman untuk memperbarui kunci yang digunakan untuk entri tampilan di penyimpanan. Untuk detailnya, lihat Pengidentifikasi tampilan statis .
Pengaturan dipertahankan di direktori /data
karena alasan historis. Awalnya, mereka digunakan untuk mempertahankan pengaturan yang ditetapkan pengguna, seperti rotasi tampilan.
Pengidentifikasi tampilan statis
Android 9 (dan yang lebih rendah) tidak menyediakan ID stabil untuk tampilan dalam framework. Saat tampilan ditambahkan ke sistem, Display#mDisplayId
atau DisplayInfo#displayId
dibuat untuk tampilan tersebut dengan menambah penghitung statis. Jika sistem menambahkan dan menghapus tampilan yang sama, ID yang berbeda akan dihasilkan.
Jika suatu perangkat memiliki beberapa tampilan yang tersedia sejak booting, tampilan tersebut dapat diberi pengenal berbeda, bergantung pada waktunya. Meskipun Android 9 (dan versi lebih lama) menyertakan DisplayInfo#uniqueId
, informasi tersebut tidak berisi cukup informasi untuk membedakan tampilan karena tampilan fisik diidentifikasi sebagai local:0
atau local:1
, untuk mewakili tampilan internal dan eksternal.
Android 10 mengubah DisplayInfo#uniqueId
untuk menambahkan pengenal stabil dan membedakan antara tampilan lokal, jaringan, dan virtual.
Tipe tampilan | Format |
---|---|
Lokal | local:<stable-id> |
Jaringan | network:<mac-address> |
Maya | virtual:<package-name-and-name> |
Selain pembaruan pada uniqueId
, DisplayInfo.address
berisi DisplayAddress
, pengidentifikasi tampilan yang stabil saat reboot. Di Android 10, DisplayAddress
mendukung tampilan fisik dan jaringan. DisplayAddress.Physical
berisi ID tampilan yang stabil (sama seperti di uniqueId
) dan dapat dibuat dengan DisplayAddress#fromPhysicalDisplayId()
.
Android 10 juga menyediakan metode mudah untuk mendapatkan informasi port ( Physical#getPort()
). Metode ini dapat digunakan dalam kerangka kerja untuk mengidentifikasi tampilan secara statis. Misalnya, ini digunakan di DisplayWindowSettings
). DisplayAddress.Network
berisi alamat MAC dan dapat dibuat dengan DisplayAddress#fromMacAddress()
.
Penambahan ini memungkinkan produsen perangkat untuk mengidentifikasi tampilan dalam pengaturan multi-display statis dan mengonfigurasi pengaturan dan fitur sistem yang berbeda menggunakan pengidentifikasi tampilan statis, seperti port untuk tampilan fisik. Metode ini tersembunyi dan hanya dimaksudkan untuk digunakan dalam system_server
.
Mengingat ID tampilan HWC (yang bisa jadi buram dan tidak selalu stabil), metode ini mengembalikan nomor port 8-bit (khusus platform) yang mengidentifikasi konektor fisik untuk output tampilan, serta gumpalan EDID tampilan. SurfaceFlinger mengekstrak informasi pabrikan atau model dari EDID untuk menghasilkan ID tampilan 64-bit stabil yang diekspos ke kerangka kerja. Jika metode ini tidak didukung atau terjadi kesalahan, SurfaceFlinger kembali ke mode MD lama, dengan DisplayInfo#address
adalah null dan DisplayInfo#uniqueId
dikodekan secara permanen, seperti dijelaskan di atas.
Untuk memverifikasi bahwa fitur ini didukung, jalankan:
$ dumpsys SurfaceFlinger --display-id # Example output. Display 21691504607621632 (HWC display 0): port=0 pnpId=SHP displayName="LQ123P1JX32" Display 9834494747159041 (HWC display 2): port=1 pnpId=HWP displayName="HP Z24i" Display 1886279400700944 (HWC display 1): port=2 pnpId=AUS displayName="ASUS MB16AP"
Gunakan lebih dari dua tampilan
Di Android 9 (dan yang lebih rendah), SurfaceFlinger dan DisplayManagerService
mengasumsikan keberadaan paling banyak dua layar fisik dengan ID hard-code 0 dan 1.
Dimulai dengan Android 10, SurfaceFlinger dapat memanfaatkan API Hardware Composer (HWC) untuk menghasilkan ID tampilan yang stabil, yang memungkinkannya mengelola sejumlah tampilan fisik secara acak. Untuk mempelajari lebih lanjut, lihat Pengidentifikasi tampilan statis .
Kerangka kerja dapat mencari token IBinder
untuk tampilan fisik melalui SurfaceControl#getPhysicalDisplayToken
setelah mendapatkan ID tampilan 64-bit dari SurfaceControl#getPhysicalDisplayIds
atau dari acara hotplug DisplayEventReceiver
.
Di Android 10 (dan yang lebih rendah), tampilan internal utama adalah TYPE_INTERNAL
dan semua tampilan sekunder ditandai sebagai TYPE_EXTERNAL
, apa pun jenis koneksinya. Oleh karena itu, tampilan internal tambahan dianggap sebagai tampilan eksternal. Sebagai solusinya, kode khusus perangkat dapat membuat asumsi tentang DisplayAddress.Physical#getPort
jika HWC diketahui dan logika alokasi port dapat diprediksi.
Batasan ini dihapus di Android 11 (dan lebih tinggi).
- Di Android 11, tampilan pertama yang dilaporkan saat booting adalah tampilan utama. Jenis koneksi (internal versus eksternal) tidak relevan. Namun, tetap benar bahwa tampilan utama tidak dapat diputuskan sambungannya dan dalam praktiknya harus merupakan tampilan internal. Perlu diperhatikan bahwa beberapa ponsel lipat memiliki beberapa layar internal.
- Tampilan sekunder dikategorikan dengan benar sebagai
Display.TYPE_INTERNAL
atauDisplay.TYPE_EXTERNAL
(sebelumnya masing-masing dikenal sebagaiDisplay.TYPE_BUILT_IN
danDisplay.TYPE_HDMI
) bergantung pada jenis koneksinya.
Penerapan
Di Android 9 dan yang lebih rendah, tampilan diidentifikasi berdasarkan ID 32-bit, dengan 0 adalah tampilan internal, 1 adalah tampilan eksternal, [2, INT32_MAX]
adalah tampilan virtual HWC, dan -1 menunjukkan tampilan tidak valid atau non-HWC tampilan maya.
Dimulai dengan Android 10, tampilan diberikan ID yang stabil dan persisten, yang memungkinkan SurfaceFlinger dan DisplayManagerService
melacak lebih dari dua tampilan dan mengenali tampilan yang dilihat sebelumnya. Jika HWC mendukung IComposerClient.getDisplayIdentificationData
dan menyediakan data identifikasi tampilan, SurfaceFlinger menguraikan struktur EDID dan mengalokasikan ID tampilan 64-bit yang stabil untuk tampilan fisik dan virtual HWC. ID dinyatakan menggunakan tipe opsi, dengan nilai null mewakili tampilan yang tidak valid atau tampilan virtual non-HWC. Tanpa dukungan HWC, SurfaceFlinger kembali ke perilaku lama dengan paling banyak dua layar fisik.
Fokus per tampilan
Untuk mendukung beberapa sumber input yang menargetkan masing-masing tampilan secara bersamaan, Android 10 dapat dikonfigurasi untuk mendukung beberapa jendela terfokus, paling banyak satu jendela per tampilan. Hal ini ditujukan hanya untuk jenis perangkat khusus ketika beberapa pengguna berinteraksi dengan perangkat yang sama secara bersamaan dan menggunakan metode masukan atau perangkat berbeda, seperti Android Automotive.
Sangat disarankan agar fitur ini tidak diaktifkan untuk perangkat biasa, termasuk perangkat multilayar atau yang digunakan untuk pengalaman seperti desktop. Hal ini terutama disebabkan oleh masalah keamanan yang mungkin menyebabkan pengguna bertanya-tanya jendela mana yang memiliki fokus masukan.
Bayangkan pengguna yang memasukkan informasi aman ke dalam kolom input teks, mungkin masuk ke aplikasi perbankan atau memasukkan teks yang berisi informasi sensitif. Aplikasi berbahaya dapat membuat tampilan di luar layar virtual untuk menjalankan aktivitas, juga dengan kolom input teks. Aktivitas sah dan jahat memiliki fokus dan keduanya menampilkan indikator input aktif (kursor berkedip).
Namun, karena masukan dari keyboard (perangkat keras atau perangkat lunak) dimasukkan ke dalam aktivitas paling atas saja (aplikasi yang baru saja diluncurkan), dengan membuat tampilan virtual tersembunyi, aplikasi jahat dapat mengambil masukan pengguna, bahkan saat menggunakan keyboard perangkat lunak pada tampilan perangkat utama.
Gunakan com.android.internal.R.bool.config_perDisplayFocusEnabled
untuk menyetel fokus per tampilan.
Kesesuaian
Masalah: Di Android 9 dan lebih rendah, paling banyak satu jendela di sistem memiliki fokus dalam satu waktu.
Solusi: Dalam kasus yang jarang terjadi ketika dua jendela dari proses yang sama akan difokuskan, sistem memberikan fokus hanya pada jendela yang lebih tinggi dalam urutan Z. Pembatasan ini dihapus untuk aplikasi yang menargetkan Android 10, sehingga diharapkan aplikasi tersebut dapat mendukung beberapa jendela yang difokuskan secara bersamaan.
Penerapan
WindowManagerService#mPerDisplayFocusEnabled
mengontrol ketersediaan fitur ini. Di ActivityManager
, ActivityDisplay#getFocusedStack()
sekarang digunakan sebagai pengganti pelacakan global dalam sebuah variabel. ActivityDisplay#getFocusedStack()
menentukan fokus berdasarkan urutan Z, bukan menyimpan nilai dalam cache. Hal ini dimaksudkan agar hanya satu sumber, WindowManager, yang perlu melacak aktivitas urutan Z.
ActivityStackSupervisor#getTopDisplayFocusedStack()
mengambil pendekatan serupa untuk kasus-kasus ketika tumpukan fokus paling atas dalam sistem harus diidentifikasi. Tumpukan tersebut ditelusuri dari atas ke bawah, mencari tumpukan pertama yang memenuhi syarat.
InputDispatcher
sekarang dapat memiliki beberapa jendela fokus (satu jendela per tampilan). Jika peristiwa masukan bersifat spesifik untuk tampilan, maka peristiwa tersebut dikirimkan ke jendela fokus pada tampilan terkait. Jika tidak, ini akan dikirim ke jendela fokus di tampilan terfokus, yang merupakan tampilan yang terakhir kali berinteraksi dengan pengguna.
Lihat InputDispatcher::mFocusedWindowHandlesByDisplay
dan InputDispatcher::setFocusedDisplay()
. Aplikasi yang ditargetkan juga diperbarui secara terpisah di InputManagerService melalui NativeInputManager::setFocusedApplication()
.
Di WindowManager
, jendela terfokus juga dilacak secara terpisah. Lihat DisplayContent#mCurrentFocus
dan DisplayContent#mFocusedApp
serta kegunaannya masing-masing. Metode pelacakan fokus dan pembaruan terkait telah dipindahkan dari WindowManagerService
ke DisplayContent
.