Dukungan layar

Pembaruan yang dilakukan pada area khusus tampilan tersebut tercantum di bawah ini:

Mengubah ukuran aktivitas dan layar

Untuk menunjukkan bahwa aplikasi mungkin tidak mendukung mode multi-aplikasi atau pengubahan ukuran, aktivitas menggunakan atribut resizeableActivity=false. Umum masalah yang ditemukan oleh aplikasi saat aktivitas diubah ukurannya meliputi:

  • Suatu aktivitas dapat memiliki konfigurasi yang berbeda dari aplikasi atau yang lainnya non-visual. Kesalahan umum adalah membaca metrik tampilan dari aplikasi konteks tambahan. Nilai yang ditampilkan tidak akan disesuaikan dengan metrik area yang terlihat tempat aktivitas ditampilkan.
  • Suatu aktivitas mungkin tidak menangani pengubahan ukuran dan error, menampilkan UI yang terdistorsi, atau kehilangan status karena diluncurkan kembali tanpa menyimpan status instance.
  • Aplikasi mungkin mencoba menggunakan koordinat input absolut (bukan koordinat input relatif terhadap posisi jendela), yang dapat merusak input di multi-aplikasi.

Di Android 7 (dan yang lebih tinggi), aplikasi dapat disetel resizeableActivity=false untuk selalu berjalan dalam mode layar penuh. Di beberapa Dalam hal ini, platform mencegah aktivitas yang tidak dapat diubah ukurannya dibagi ke dalam pemisahan layar. Jika pengguna mencoba memanggil aktivitas yang tidak dapat diubah ukurannya dari peluncur saat berada dalam mode layar terpisah, platform keluar dari mode layar terpisah dan meluncurkan aktivitas yang tidak dapat diubah ukurannya dalam mode layar penuh.

Aplikasi yang secara eksplisit menetapkan atribut ini ke false dalam manifes tidak boleh diluncurkan dalam mode multi-aplikasi, kecuali jika mode tersebut diterapkan:

  • Konfigurasi yang sama diterapkan pada proses, yang berisi semua aktivitas dan non-aktivitas.
  • Konfigurasi yang diterapkan memenuhi persyaratan CDD untuk aplikasi yang kompatibel layar.

Di Android 10, platform masih mencegah aktivitas yang tidak dapat diubah ukurannya agar tidak masuk ke mode layar terpisah, tetapi bisa juga diskalakan sementara jika aktivitas telah mendeklarasikan orientasi atau aspek tetap rasio. Jika tidak, aktivitas akan berubah ukuran untuk mengisi seluruh layar seperti di Android 9 dan lebih rendah.

Implementasi default menerapkan kebijakan berikut:

Ketika suatu aktivitas dideklarasikan tidak kompatibel dengan multi-aplikasi melalui penggunaan atribut android:resizeableActivity dan kapan memenuhi salah satu kondisi yang dijelaskan di bawah ini, maka ketika diterapkan konfigurasi layar harus diubah, aktivitas dan proses disimpan dengan konfigurasi asli dan pengguna diberikan kemampuan untuk meluncurkan kembali proses aplikasi untuk menggunakan konfigurasi layar yang diupdate.

  • 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 perangkat dilipat, ukuran jendela akan diperkecil agar sesuai dengan area saat mempertahankan rasio aspek menggunakan tampilan lebar yang sesuai. Selain itu, opsi {i>restart activity<i} disediakan kepada pengguna setiap kali aktivitas diubah.

Saat membuka perangkat, konfigurasi, ukuran, dan rasio aspek aktivitas tidak berubah, namun opsi untuk memulai ulang aktivitas akan ditampilkan.

Jika resizeableActivity tidak ditetapkan (atau ditetapkan ke true), aplikasi sepenuhnya mendukung pengubahan ukuran.

Implementasi

Aktivitas yang tidak dapat diubah ukurannya dengan orientasi atau rasio aspek tetap dipanggil mode kompatibilitas ukuran (SCM) dalam kode. Kondisi ini didefinisikan dalam ActivityRecord#shouldUseSizeCompatMode(). Ketika aktivitas SCM diluncurkan, konfigurasi terkait layar (seperti ukuran atau kepadatan) dalam konfigurasi penggantian yang diminta, sehingga aktivitas tidak lagi bergantung pada pada konfigurasi tampilan saat ini.

Jika aktivitas SCM tidak dapat mengisi seluruh layar, aktivitas itu akan ditempatkan di atas dan ke tengah secara horizontal. Batas aktivitas dihitung dengan AppWindowToken#calculateCompatBoundsTransformation().

Ketika aktivitas SCM menggunakan konfigurasi layar yang berbeda dari (misalnya, tampilan diubah ukurannya, atau aktivitas dipindahkan ke display), ActivityRecord#inSizeCompatMode() bernilai benar (true) dan SizeCompatModeActivityController (di UI Sistem) menerima untuk menampilkan tombol mulai ulang proses.

Ukuran layar dan rasio aspek

Android 10 memberikan dukungan untuk rasio aspek baru dari layar panjang dan tipis dengan rasio tinggi hingga 1:1. Aplikasi dapat menentukan ApplicationInfo#maxAspectRatio dan ApplicationInfo#minAspectRatio layar tempat keduanya tidak bisa ditangani.

rasio aplikasi di Android 10

Gambar 1. Contoh rasio aplikasi yang didukung di Android 10

Implementasi perangkat dapat memiliki tampilan sekunder dengan ukuran dan resolusi yang lebih kecil dari yang dibutuhkan oleh Android 9, dan yang lebih rendah (minimal 2.5 lebar atau tinggi inci, minimum 320 DP untuk smallestScreenWidth), tetapi hanya aktivitas yang memilih untuk mendukung layar kecil ini yang dapat ditempatkan di sana.

Aplikasi dapat memilih untuk ikut serta dengan menyatakan ukuran minimum yang didukung yang lebih kecil dari atau sama dengan ukuran tampilan target. Gunakan android:minHeight dan atribut tata letak aktivitas android:minWidth di AndroidManifest untuk melakukannya.

Kebijakan display

Android 10 memisahkan dan memindahkan tampilan tertentu kebijakan dari implementasi WindowManagerPolicy default di PhoneWindowManager ke class per-tampilan, seperti:

  • Status dan rotasi tampilan
  • Beberapa pelacakan peristiwa tombol dan gerakan
  • UI sistem dan jendela dekorasi

Di Android 9 (dan yang lebih lama), class PhoneWindowManager menangani kebijakan tampilan, status dan setelan, rotasi, bingkai jendela dekorasi pelacakan, dan banyak lagi. Android 10 memindahkan sebagian besar class DisplayPolicy, kecuali untuk pelacakan rotasi, yang memiliki telah dipindahkan ke DisplayRotation.

Setelan jendela tampilan

Di Android 10, konfigurasi per tampilan yang dapat dikonfigurasi pengaturan windowing telah diperluas untuk mencakup:

  • Mode jendela tampilan default
  • Pemindaian berlebih pada nilai
  • Mode rotasi dan rotasi pengguna
  • Mode ukuran, kepadatan, dan penskalaan paksa
  • Mode penghapusan konten (saat layar dihapus)
  • Dukungan untuk dekorasi sistem dan IME

Class DisplayWindowSettings berisi setelan untuk objek ini lainnya. Tabel disimpan ke disk dalam partisi /data dalam display_settings.xml setiap kali setelan diubah. Sebagai detail, lihat DisplayWindowSettings.AtomicFileStorage dan DisplayWindowSettings#writeSettings(). Produsen perangkat dapat memberikan nilai default dalam display_settings.xml untuk perangkatnya konfigurasi Anda. Namun, karena file disimpan di /data, logika tambahan mungkin diperlukan untuk memulihkan file jika dihapus dengan penghapusan total.

Secara default, Android 10 menggunakan DisplayInfo#uniqueId sebagai ID untuk tampilan saat mempertahankan pengaturan. uniqueId harus diisi untuk semua layar. Di beberapa selain itu, lebih stabil untuk tampilan fisik dan jaringan. Dimungkinkan juga untuk menggunakan porta tampilan fisik sebagai pengenal, yang dapat diatur dalam DisplayWindowSettings#mIdentifier. Pada setiap penulisan, semua setelan ditulis sehingga aman untuk memperbarui kunci yang digunakan untuk entri tampilan di Storage. Untuk mengetahui detailnya, lihat ID tampilan statis.

Setelan disimpan di direktori /data untuk histori alasan. 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 Google Workspace for Education. Ketika {i>display<i} ditambahkan ke sistem, Display#mDisplayId atau DisplayInfo#displayId sebelumnya adalah untuk tampilan itu dengan menambahkan penghitung statis. Jika sistem menambahkan dan menghapus tampilan yang sama, menghasilkan ID yang berbeda.

Jika perangkat memiliki beberapa layar yang tersedia dari {i>booting<i}, layar itu bisa diberi ID yang berbeda, tergantung pada waktunya. Meskipun Android 9 (dan sebelumnya) menyertakan DisplayInfo#uniqueId, baris tersebut tidak cukup berisi informasi untuk membedakan antarlayar karena tampilan fisik diidentifikasi sebagai local:0 atau local:1, untuk mewakili layar bawaan dan eksternal.

DisplayInfo#uniqueId perubahan Android 10 untuk menambahkan ID yang stabil dan untuk membedakan antara alamat lokal, jaringan, dan tampilan virtual.

Jenis tampilan Format
Lokal
local:<stable-id>
Jaringan
network:<mac-address>
Virtual
virtual:<package-name-and-name>

Selain update pada uniqueId, DisplayInfo.address berisi DisplayAddress, ID tampilan yang stabil meskipun telah dimulai ulang. Di Android 10, DisplayAddress mendukung fisik dan layar jaringan. DisplayAddress.Physical berisi stabil ID tampilan (sama seperti di uniqueId) dan dapat dibuat dengan DisplayAddress#fromPhysicalDisplayId().

Android 10 juga menyediakan metode yang mudah untuk informasi porta (Physical#getPort()). Metode ini dapat digunakan di kerangka kerja untuk mengidentifikasi layar secara statis. Misalnya, DHCP digunakan di DisplayWindowSettings). DisplayAddress.Network berisi alamat MAC dan dapat dibuat dengan DisplayAddress#fromMacAddress().

Penambahan ini memungkinkan produsen perangkat mengidentifikasi layar secara statis penyiapan multi-tampilan dan untuk mengonfigurasi berbagai setelan dan fitur sistem menggunakan ID tampilan statis, seperti porta untuk tampilan fisik. Ini metode tersembunyi dan hanya dimaksudkan untuk digunakan di dalam system_server.

Dengan ID tampilan HWC (yang bisa buram dan tidak selalu stabil), ini mengembalikan nomor port 8-bit (khusus platform) yang mengidentifikasi konektor fisik untuk output tampilan, serta blob EDID layar. SurfaceFlinger mengekstrak informasi produsen atau model dari EDID ke menghasilkan ID tampilan 64-bit stabil yang diekspos ke framework. Jika metode ini tidak didukung atau mengalami {i>error<i}, SurfaceFlinger kembali ke mode MD lama, di mana DisplayInfo#address adalah null dan DisplayInfo#uniqueId adalah hard code, 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 adanya maksimal dua layar fisik dengan ID hard code 0 dan 1.

Mulai Android 10, SurfaceFlinger dapat memanfaatkan Hardware Composer (HWC) API untuk menghasilkan ID tampilan yang stabil, yang memungkinkannya mengelola jumlah tampilan fisik yang berubah-ubah. Untuk mempelajari lebih lanjut, lihat ID tampilan statis.

Framework ini dapat mencari token IBinder untuk ditampilkan melalui SurfaceControl#getPhysicalDisplayToken setelah mendapatkan ID tampilan 64-bit dari SurfaceControl#getPhysicalDisplayIds atau dari peristiwa hotplug DisplayEventReceiver.

Di Android 10 (dan yang lebih lama), tampilan internal utama adalah TYPE_INTERNAL dan semua tampilan sekunder ditandai sebagai TYPE_EXTERNAL terlepas dari jenis koneksi. Oleh karena itu, tampilan internal tambahan dianggap sebagai eksternal. Sebagai solusinya, kode khusus perangkat dapat membuat asumsi tentang DisplayAddress.Physical#getPort jika HWC diketahui dan alokasi port logika bisa diprediksi.

Batasan ini dihapus di Android 11 (dan yang lebih baru).

  • Di Android 11, tampilan pertama yang dilaporkan selama booting adalah layar utama. Jenis koneksi (internal versus eksternal) tidak relevan. Namun, tetap benar bahwa layar utama tidak dapat diputus dan mengikuti dalam praktiknya harus berupa tampilan internal. Perlu diperhatikan bahwa beberapa ponsel foldable memiliki tampilan internal.
  • Layar sekunder dikategorikan dengan benar sebagai Display.TYPE_INTERNAL atau Display.TYPE_EXTERNAL (sebelumnya dikenal sebagai Display.TYPE_BUILT_IN dan Display.TYPE_HDMI) bergantung pada jenis koneksinya.

Implementasi

Di Android 9 dan yang lebih rendah, layar diidentifikasi oleh ID 32-bit, dengan 0 adalah tampilan internal, 1 adalah layar eksternal, [2, INT32_MAX] adalah layar virtual HWC, dan -1 mewakili tampilan yang tidak valid atau tampilan virtual non-HWC.

Mulai Android 10, layar akan diberi status stabil dan ID persisten, yang memungkinkan SurfaceFlinger dan DisplayManagerService untuk melacak lebih dari dua layar dan mengenali tampilan yang sebelumnya terlihat. Jika HWC mendukung IComposerClient.getDisplayIdentificationData dan menyediakan tampilan data identifikasi, SurfaceFlinger mengurai struktur EDID dan mengalokasikan ID tampilan 64-bit untuk tampilan fisik dan virtual HWC. ID tersebut dinyatakan menggunakan jenis opsi, dengan nilai null mewakili tampilan yang tidak valid atau virtual non-HWC tampilan. Tanpa dukungan HWC, SurfaceFlinger kembali ke perilaku lama dengan hampir dua layar fisik.

Fokus per-tampilan

Untuk mendukung beberapa sumber input yang menargetkan setiap layar secara bersamaan Android 10 dapat dikonfigurasi untuk mendukung banyak jendela yang terfokus, maksimal satu per-tampilan. Ini hanya ditujukan bagi pengguna jenis perangkat ketika beberapa pengguna berinteraksi dengan perangkat yang sama secara waktu dan menggunakan metode input atau perangkat yang berbeda, seperti Android Otomotif.

Sebaiknya fitur ini tidak diaktifkan untuk perangkat biasa, termasuk perangkat multilayar atau yang digunakan seperti desktop pengalaman yang lancar bagi developer. Hal ini utamanya disebabkan oleh masalah keamanan yang mungkin menyebabkan pengguna untuk bertanya-tanya jendela mana yang memiliki fokus input.

Bayangkan pengguna yang memasukkan informasi aman ke isian {i>input <i}teks, mungkin masuk ke aplikasi perbankan atau memasukkan teks yang berisi tidak akurat atau tidak sesuai. Aplikasi berbahaya dapat membuat tampilan luar layar virtual dengan yang digunakan untuk menjalankan aktivitas, juga dengan isian {i>input <i}teks. Sah dan aktivitas berbahaya memiliki fokus dan keduanya menampilkan indikator input aktif (kursor berkedip).

Namun, karena {i>input<i} dari {i>keyboard<i} (perangkat keras atau perangkat lunak) dimasukkan ke dalam hanya aktivitas teratas (aplikasi yang terakhir diluncurkan), dengan membuat tampilan virtual tersembunyi, aplikasi berbahaya dapat mengambil input pengguna, bahkan saat menggunakan {i>keyboard<i} virtual pada layar perangkat utama.

Gunakan com.android.internal.R.bool.config_perDisplayFocusEnabled untuk menyetel fokus per-tampilan.

Kompatibilitas

Masalah: Di Android 9 dan yang lebih lama, maksimal satu jendela di fokus pada satu waktu.

Solusi: Dalam kasus yang jarang terjadi, saat dua jendela dari proses yang sama akan difokuskan, sistem memberikan fokus hanya ke jendela yang lebih tinggi dalam urutan Z. Pembatasan ini dihapus untuk aplikasi yang menargetkan Android 10, saat ini diharapkan bisa mendukung beberapa jendela yang difokuskan secara bersamaan.

Implementasi

WindowManagerService#mPerDisplayFocusEnabled mengontrol ketersediaan fitur ini. Setelah ActivityManager, ActivityDisplay#getFocusedStack() kini digunakan sebagai pengganti pelacakan data dalam variabel. ActivityDisplay#getFocusedStack() menentukan fokus berdasarkan urutan Z daripada meng-{i>cache<i} nilai. Ini agar hanya satu sumber, yaitu WindowManager, perlu melacak aktivitas urutan Z.

ActivityStackSupervisor#getTopDisplayFocusedStack() mengambil pendekatan serupa untuk kasus tersebut ketika {i>stack <i}paling fokus dalam sistem harus diidentifikasi. Tumpukan dilalui dari atas ke bawah, untuk mencari tumpukan pertama yang memenuhi syarat.

InputDispatcher kini dapat memiliki beberapa jendela yang difokuskan (satu per tampilan). Jika peristiwa input khusus untuk tampilan, peristiwa itu dikirim ke jendela yang difokuskan dalam tampilan yang sesuai. Jika tidak, dikirimkan ke jendela yang difokuskan pada tampilan yang difokuskan, yang merupakan tampilan yang yang terakhir berinteraksi.

Lihat InputDispatcher::mFocusedWindowHandlesByDisplay dan InputDispatcher::setFocusedDisplay(). Aplikasi yang difokuskan juga akan diupdate secara terpisah di InputManagerService melalui NativeInputManager::setFocusedApplication().

Di WindowManager, jendela yang difokuskan juga dilacak secara terpisah. Lihat DisplayContent#mCurrentFocus dan DisplayContent#mFocusedApp dan penggunaannya masing-masing. Fokus terkait metode pelacakan dan pembaruan telah dipindahkan dari WindowManagerService hingga DisplayContent.