Pembaruan yang dilakukan pada area khusus tampilan ini diberikan di bawah:
- Mengubah ukuran aktivitas dan tampilan
- Ukuran dan rasio aspek layar
- Kebijakan Display
- Setelan jendela tampilan
- ID iklan display statis
- Menggunakan lebih dari dua layar
- Fokus per layar
Mengubah ukuran aktivitas dan tampilan
Untuk menunjukkan bahwa aplikasi mungkin tidak mendukung mode multi-aplikasi atau pengubahan ukuran, aktivitas menggunakan atribut resizeableActivity=false
. Masalah umum yang dihadapi aplikasi saat aktivitas diubah ukurannya meliputi:
- Aktivitas dapat memiliki konfigurasi yang berbeda dari aplikasi atau komponen non-visual lainnya. Kesalahan umum adalah membaca metrik tampilan dari konteks aplikasi. Nilai yang ditampilkan tidak akan disesuaikan dengan metrik area yang terlihat tempat aktivitas ditampilkan.
- Aktivitas mungkin tidak menangani pengubahan ukuran dan mengalami error, menampilkan UI yang terdistorsi, atau kehilangan status karena peluncuran ulang tanpa menyimpan status instance.
- Aplikasi dapat mencoba menggunakan koordinat input absolut (bukan yang relatif terhadap posisi jendela), yang dapat merusak input dalam multi-aplikasi.
Di Android 7 (dan yang lebih tinggi), aplikasi dapat disetel
resizeableActivity=false
agar selalu berjalan dalam mode layar penuh. Dalam
kasus ini, platform mencegah aktivitas yang tidak dapat diubah ukurannya masuk ke layar
split. Jika pengguna mencoba memanggil 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-aplikasi, kecuali jika mode
kompatibilitas diterapkan:
- Konfigurasi yang sama diterapkan ke proses, yang berisi semua aktivitas dan komponen non-aktivitas.
- Konfigurasi yang diterapkan memenuhi persyaratan CDD untuk layar yang kompatibel dengan aplikasi.
Di Android 10, platform masih mencegah aktivitas yang tidak dapat diubah ukurannya masuk ke mode layar terpisah, tetapi aktivitas tersebut dapat diskalakan untuk sementara jika aktivitas telah mendeklarasikan orientasi atau rasio aspek tetap. Jika tidak, aktivitas akan diubah ukurannya untuk mengisi seluruh layar seperti di Android 9 dan yang lebih rendah.
Penerapan default menerapkan kebijakan berikut:
Jika aktivitas dinyatakan tidak kompatibel dengan multi-aplikasi melalui
penggunaan atribut android:resizeableActivity
dan jika
aktivitas tersebut memenuhi salah satu kondisi yang dijelaskan di bawah, maka saat konfigurasi
layar yang diterapkan harus berubah, aktivitas dan proses akan disimpan dengan
konfigurasi asli dan pengguna akan diberi kemampuan untuk meluncurkan ulang
proses aplikasi guna menggunakan konfigurasi layar yang telah diupdate.
- Memiliki orientasi tetap melalui penerapan
android:screenOrientation
- Aplikasi memiliki rasio aspek maksimum atau minimum default dengan menargetkan level API atau mendeklarasikan rasio aspek secara eksplisit
Gambar ini menampilkan aktivitas yang tidak dapat diubah ukurannya dengan rasio aspek yang dideklarasikan. Saat melipat perangkat, jendela akan diperkecil agar sesuai dengan area sambil mempertahankan rasio aspek menggunakan letterboxing yang sesuai. Selain itu, opsi mulai ulang aktivitas diberikan kepada pengguna setiap kali area tampilan untuk aktivitas diubah.
Saat perangkat dibentangkan, konfigurasi, ukuran, dan rasio aspek aktivitas tidak berubah, tetapi opsi untuk memulai ulang aktivitas ditampilkan.
Jika resizeableActivity
tidak disetel (atau disetel ke
true
), aplikasi sepenuhnya mendukung pengubahan ukuran.
Implementasi
Aktivitas yang tidak dapat diubah ukurannya dengan orientasi atau rasio aspek tetap disebut
mode kompatibilitas ukuran (SCM) dalam kode. Kondisi 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 mengisi seluruh layar, aktivitas tersebut akan disejajarkan di bagian atas dan
ditengahkan secara horizontal. Batas aktivitas dihitung oleh
AppWindowToken#calculateCompatBoundsTransformation()
.
Jika aktivitas SCM menggunakan konfigurasi layar yang berbeda dengan
penampungnya (misalnya, ukuran tampilan diubah, atau aktivitas dipindahkan ke
tampilan lain), ActivityRecord#inSizeCompatMode()
bernilai benar dan
SizeCompatModeActivityController
(di UI Sistem) menerima
callback untuk menampilkan tombol mulai ulang proses.
Ukuran dan rasio aspek layar
Android 10 memberikan dukungan untuk rasio aspek baru
dari rasio tinggi 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 tampilan sekunder dengan ukuran dan
resolusi yang lebih kecil daripada yang diperlukan oleh Android 9 dan yang lebih rendah (lebar atau tinggi minimum 2, 5 inci, DP minimum 320 untuk smallestScreenWidth
),
tetapi hanya aktivitas yang memilih untuk mendukung tampilan kecil ini yang dapat ditempatkan
di sana.
Aplikasi dapat memilih untuk ikut serta dengan mendeklarasikan ukuran minimum yang didukung yang lebih kecil dari atau sama dengan ukuran layar target. Gunakan atribut tata letak aktivitas android:minHeight
dan
android:minWidth
di
AndroidManifest untuk melakukannya.
Kebijakan tampilan
Android 10 memisahkan dan memindahkan kebijakan tampilan tertentu dari penerapan WindowManagerPolicy
default di PhoneWindowManager
ke class per tampilan, seperti:
- Status dan rotasi layar
- Pelacakan beberapa peristiwa tombol dan gerakan
- UI sistem dan jendela dekorasi
Di Android 9 (dan yang lebih rendah), class PhoneWindowManager
menangani
kebijakan tampilan, status dan setelan, rotasi, pelacakan frame jendela dekorasi, dan lainnya. Android 10 memindahkan sebagian besar hal ini ke
class DisplayPolicy
, kecuali pelacakan rotasi, yang telah
dipindahkan ke DisplayRotation
.
Setelan jendela tampilan
Di Android 10, setelan windowing per-tampilan yang dapat dikonfigurasi telah diperluas untuk mencakup:
- Mode tampilan jendela default
- Nilai overscan
- Rotasi pengguna dan mode rotasi
- Ukuran, kepadatan, dan mode penskalaan yang dipaksakan
- Mode penghapusan konten (saat tampilan dihapus)
- Dukungan untuk dekorasi sistem dan IME
Class DisplayWindowSettings
berisi setelan untuk opsi ini. Data ini disimpan ke disk di partisi /data
di
display_settings.xml
setiap kali setelan diubah. Untuk
mengetahui 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 dihapus oleh penghapusan data.
Secara default, Android 10 menggunakan
DisplayInfo#uniqueId
sebagai ID untuk layar saat mempertahankan
setelan. uniqueId
harus diisi untuk semua tampilan. Selain itu, tampilan ini stabil untuk tampilan fisik dan jaringan. Anda juga dapat
menggunakan port layar fisik sebagai ID, yang dapat ditetapkan di
DisplayWindowSettings#mIdentifier
. Pada setiap penulisan, semua setelan ditulis sehingga aman untuk memperbarui kunci yang digunakan untuk entri tampilan dalam penyimpanan. Untuk mengetahui detailnya, lihat
ID tampilan statis.
Setelan dipertahankan di direktori /data
karena alasan historis. Awalnya, setelan ini digunakan untuk mempertahankan setelan yang ditetapkan pengguna, seperti
rotasi layar.
ID tampilan statis
Android 9 (dan yang lebih rendah) tidak menyediakan ID yang stabil untuk tampilan di framework. Saat layar ditambahkan ke sistem, Display#mDisplayId
atau DisplayInfo#displayId
akan dibuat untuk layar tersebut dengan menambahkan penghitung statis. Jika sistem menambahkan dan menghapus tampilan yang sama, ID yang dihasilkan akan berbeda.
Jika perangkat memiliki beberapa tampilan yang tersedia sejak booting, tampilan dapat diberi ID yang berbeda, bergantung pada waktunya. Meskipun Android 9 (dan versi sebelumnya) menyertakan DisplayInfo#uniqueId
, Android 9 tidak berisi informasi yang cukup untuk membedakan antara tampilan karena tampilan fisik diidentifikasi sebagai local:0
atau local:1
, untuk merepresentasikan tampilan bawaan dan eksternal.
Android 10 mengubah DisplayInfo#uniqueId
untuk menambahkan ID yang stabil dan membedakan antara tampilan lokal, jaringan, dan
virtual.
Jenis tampilan | Format |
---|---|
Lokal | local:<stable-id> |
Jaringan | network:<mac-address> |
Virtual | virtual:<package-name-and-name> |
Selain pembaruan pada uniqueId
,
DisplayInfo.address
berisi DisplayAddress
, yaitu
ID tampilan yang stabil di seluruh proses mulai ulang. 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 yang mudah untuk mendapatkan informasi port (Physical#getPort()
). Metode ini dapat digunakan dalam framework untuk mengidentifikasi tampilan secara statis. Misalnya, digunakan dalam
DisplayWindowSettings
). DisplayAddress.Network
berisi alamat MAC dan dapat dibuat dengan
DisplayAddress#fromMacAddress()
.
Penambahan ini memungkinkan produsen perangkat mengidentifikasi layar dalam penyiapan multi-layar statis dan mengonfigurasi berbagai setelan dan fitur sistem menggunakan ID layar statis, seperti port untuk layar fisik. Metode ini disembunyikan dan hanya ditujukan untuk digunakan dalam
system_server
.
Dengan ID tampilan HWC (yang dapat bersifat buram dan tidak selalu stabil), metode ini menampilkan nomor port 8-bit (spesifik per platform) yang mengidentifikasi konektor fisik untuk output tampilan, serta blob EDID tampilan.
SurfaceFlinger mengekstrak informasi produsen atau model dari EDID untuk menghasilkan ID tampilan 64-bit yang stabil yang diekspos ke framework. Jika metode ini tidak didukung atau terjadi error, SurfaceFlinger akan kembali ke mode MD lama, dengan DisplayInfo#address
bernilai null dan DisplayInfo#uniqueId
dikodekan secara permanen, seperti yang 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"
Menggunakan lebih dari dua layar
Di Android 9 (dan yang lebih rendah), SurfaceFlinger dan DisplayManagerService
mengasumsikan keberadaan paling banyak dua layar fisik dengan ID yang dikodekan secara permanen 0
dan 1.
Mulai dari Android 10, SurfaceFlinger dapat memanfaatkan API Hardware Composer (HWC) untuk menghasilkan ID tampilan yang stabil, sehingga dapat mengelola sejumlah tampilan fisik yang arbitrer. Untuk mempelajari lebih lanjut, lihat ID tampilan statis.
Framework dapat mencari token IBinder
untuk tampilan fisik melalui SurfaceControl#getPhysicalDisplayToken
setelah mendapatkan ID tampilan 64-bit dari SurfaceControl#getPhysicalDisplayIds
atau dari peristiwa hotplug DisplayEventReceiver
.
Di Android 10 (dan yang lebih rendah), tampilan internal utama adalah
TYPE_INTERNAL
dan semua tampilan sekunder ditandai sebagai TYPE_EXTERNAL
terlepas dari jenis koneksi. Oleh karena itu, layar internal tambahan diperlakukan sebagai layar eksternal.
Sebagai solusi, 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 yang lebih tinggi).
- Di Android 11, layar pertama yang dilaporkan selama booting adalah layar utama. Jenis koneksi (internal versus eksternal) tidak relevan. Namun, layar utama tetap tidak dapat dihentikan koneksinya dan harus berupa layar internal dalam praktiknya. Perhatikan bahwa beberapa ponsel foldable memiliki beberapa layar internal.
- Layar sekunder dikategorikan dengan benar sebagai
Display.TYPE_INTERNAL
atauDisplay.TYPE_EXTERNAL
(sebelumnya dikenal sebagaiDisplay.TYPE_BUILT_IN
danDisplay.TYPE_HDMI
) bergantung pada jenis koneksinya.
Implementasi
Di Android 9 dan yang lebih rendah, layar diidentifikasi oleh ID 32-bit,
dengan 0 adalah layar internal, 1 adalah layar eksternal, [2, INT32_MAX]
adalah layar virtual HWC, dan -1 mewakili layar yang tidak valid atau layar virtual non-HWC.
Mulai Android 10, layar diberi ID yang stabil
dan persisten, yang memungkinkan SurfaceFlinger dan DisplayManagerService
melacak lebih dari dua layar dan mengenali layar yang pernah dilihat sebelumnya. Jika HWC mendukung IComposerClient.getDisplayIdentificationData
dan menyediakan data identifikasi layar, SurfaceFlinger akan mem-parsing struktur EDID dan mengalokasikan ID layar 64-bit yang stabil untuk layar fisik dan virtual HWC. ID dinyatakan menggunakan
jenis opsi, dengan nilai null mewakili tampilan yang tidak valid atau tampilan virtual non-HWC. Tanpa dukungan HWC, SurfaceFlinger akan kembali ke perilaku lama dengan maksimal dua layar fisik.
Fokus per layar
Untuk mendukung beberapa sumber input yang menargetkan setiap tampilan secara bersamaan, Android 10 dapat dikonfigurasi untuk mendukung beberapa jendela yang difokuskan, paling banyak satu per tampilan. Tindakan ini hanya ditujukan untuk jenis perangkat khusus saat beberapa pengguna berinteraksi dengan perangkat yang sama pada waktu yang sama dan menggunakan metode atau perangkat input yang berbeda, seperti Android Automotive.
Sebaiknya fitur ini tidak diaktifkan untuk perangkat biasa, termasuk perangkat multi-layar atau perangkat yang digunakan untuk pengalaman seperti desktop. Hal ini terutama disebabkan oleh masalah keamanan yang dapat menyebabkan pengguna bertanya-tanya jendela mana yang memiliki fokus input.
Bayangkan pengguna yang memasukkan informasi aman ke dalam kolom input teks, mungkin login ke aplikasi perbankan atau memasukkan teks yang berisi informasi sensitif. Aplikasi berbahaya dapat membuat tampilan virtual di luar layar untuk menjalankan aktivitas, juga dengan kolom input teks. Aktivitas yang sah dan berbahaya memiliki fokus dan keduanya menampilkan indikator input aktif (kursor berkedip).
Namun, karena input dari keyboard (hardware atau software) hanya dimasukkan ke aktivitas teratas (aplikasi yang baru saja diluncurkan), dengan membuat tampilan virtual tersembunyi, aplikasi berbahaya dapat mengambil input pengguna, bahkan saat menggunakan keyboard software di layar perangkat utama.
Gunakan com.android.internal.R.bool.config_perDisplayFocusEnabled
untuk menyetel fokus per tampilan.
Kompatibilitas
Masalah: Di Android 9 dan yang lebih rendah, paling banyak satu jendela dalam sistem yang memiliki fokus pada satu waktu.
Solusi: Dalam kasus yang jarang terjadi ketika dua jendela dari proses yang sama akan difokuskan, sistem hanya memberikan fokus ke jendela yang lebih tinggi dalam urutan Z. Batasan ini dihapus untuk aplikasi yang menargetkan Android 10, yang diharapkan dapat mendukung beberapa jendela yang difokuskan secara bersamaan.
Implementasi
WindowManagerService#mPerDisplayFocusEnabled
mengontrol ketersediaan fitur ini. Di ActivityManager
,
ActivityDisplay#getFocusedStack()
kini digunakan, bukan pelacakan
global dalam variabel. ActivityDisplay#getFocusedStack()
menentukan fokus berdasarkan urutan Z, bukan menyimpan nilai dalam cache. Hal ini dilakukan agar hanya satu sumber, WindowManager, yang perlu melacak urutan Z aktivitas.
ActivityStackSupervisor#getTopDisplayFocusedStack()
mengambil pendekatan serupa untuk kasus ketika stack yang paling fokus di sistem harus diidentifikasi. Tumpukan dilalui dari atas ke bawah, mencari
tumpukan pertama yang memenuhi syarat.
InputDispatcher
kini dapat memiliki beberapa jendela yang difokuskan
(satu per layar). Jika peristiwa input khusus tampilan, peristiwa tersebut akan dikirim
ke jendela yang difokuskan di tampilan yang sesuai. Jika tidak, peristiwa akan dikirim
ke jendela yang difokuskan di tampilan yang difokuskan, yaitu tampilan yang paling sering
digunakan oleh pengguna.
Lihat InputDispatcher::mFocusedWindowHandlesByDisplay
dan
InputDispatcher::setFocusedDisplay()
. Aplikasi yang difokuskan juga diupdate secara terpisah di InputManagerService melalui NativeInputManager::setFocusedApplication()
.
Di WindowManager
, jendela yang difokuskan juga dilacak secara terpisah.
Lihat DisplayContent#mCurrentFocus
dan
DisplayContent#mFocusedApp
serta penggunaannya masing-masing. Metode pelacakan dan pembaruan fokus terkait telah dipindahkan dari WindowManagerService
ke DisplayContent
.