รองรับการแสดงผล

การอัปเดตที่ทำในพื้นที่เฉพาะการแสดงผลเหล่านี้มีดังต่อไปนี้:

ปรับขนาดกิจกรรมและการแสดงผล

เพื่อระบุว่าแอปอาจไม่รองรับโหมดหลายหน้าต่างหรือการปรับขนาด กิจกรรมจะใช้แอตทริบิวต์ resizeableActivity=false ปัญหาทั่วไปที่แอพพบเมื่อมีการปรับขนาดกิจกรรม ได้แก่:

  • กิจกรรมอาจมีการกำหนดค่าที่แตกต่างจากแอปหรือส่วนประกอบอื่นที่ไม่ใช่ภาพ ข้อผิดพลาดทั่วไปคือการอ่านเมตริกการแสดงผลจากบริบทของแอป ค่าที่ส่งคืนจะไม่ถูกปรับเป็นเมตริกพื้นที่ที่มองเห็นได้ซึ่งมีกิจกรรมแสดงอยู่
  • กิจกรรมอาจไม่รองรับการปรับขนาดและข้อขัดข้อง แสดง UI ที่บิดเบี้ยว หรือสูญเสียสถานะเนื่องจากการเปิดใหม่โดยไม่บันทึกสถานะอินสแตนซ์
  • แอปอาจพยายามใช้พิกัดอินพุตสัมบูรณ์ (แทนที่จะเป็นพิกัดที่สัมพันธ์กับตำแหน่งหน้าต่าง) ซึ่งอาจทำให้อินพุตในหลายหน้าต่างเสียหาย

ใน Android 7 (และสูงกว่า) สามารถตั้งค่าแอป resizeableActivity=false ให้ทำงานในโหมดเต็มหน้าจอได้ตลอดเวลา ในกรณีนี้ แพลตฟอร์มจะป้องกันไม่ให้กิจกรรมที่ไม่สามารถปรับขนาดได้เข้าสู่หน้าจอแยก หากผู้ใช้พยายามเรียกใช้กิจกรรมที่ไม่สามารถปรับขนาดได้จากตัวเรียกใช้งานในขณะที่อยู่ในโหมดแบ่งหน้าจออยู่แล้ว แพลตฟอร์มจะออกจากโหมดแบ่งหน้าจอและเปิดกิจกรรมที่ไม่สามารถปรับขนาดได้ในโหมดเต็มหน้าจอ

แอปที่ตั้งค่าแอตทริบิวต์นี้เป็น false อย่างชัดเจนในรายการจะต้องไม่เปิดในโหมดหลายหน้าต่าง เว้นแต่จะใช้โหมดความเข้ากันได้:

  • มีการใช้การตั้งค่าคอนฟิกเดียวกันกับกระบวนการ ซึ่งประกอบด้วยกิจกรรมและส่วนประกอบที่ไม่ใช่กิจกรรมทั้งหมด
  • การกำหนดค่าที่ใช้เป็นไปตามข้อกำหนด CDD สำหรับจอแสดงผลที่เข้ากันได้กับแอป

ใน Android 10 แพลตฟอร์มยังคงป้องกันไม่ให้กิจกรรมที่ไม่สามารถปรับขนาดได้เข้าสู่โหมดแบ่งหน้าจอ แต่สามารถปรับขนาดได้ชั่วคราวหากกิจกรรมได้ประกาศการวางแนวหรืออัตราส่วนภาพคงที่ ถ้าไม่เช่นนั้น กิจกรรมจะปรับขนาดให้เต็มหน้าจอเหมือนกับใน Android 9 และต่ำกว่า

การใช้งานเริ่มต้นจะใช้นโยบายต่อไปนี้:

เมื่อกิจกรรมที่ประกาศว่าเข้ากันไม่ได้กับหลายหน้าต่างผ่านการใช้แอตทริบิวต์ android:resizeableActivity และเมื่อกิจกรรมนั้นตรงตามเงื่อนไขข้อใดข้อหนึ่งที่อธิบายไว้ด้านล่าง เมื่อต้องเปลี่ยนการกำหนดค่าหน้าจอที่ใช้ กิจกรรมและกระบวนการจะถูกบันทึกด้วยการกำหนดค่าดั้งเดิม และผู้ใช้จะได้รับสิทธิ์ในการเปิดกระบวนการแอปอีกครั้งเพื่อใช้การกำหนดค่าหน้าจอที่อัปเดต

  • มีการวางแนวคงที่ผ่านแอปพลิเคชัน android:screenOrientation
  • แอปมีอัตราส่วนกว้างยาวสูงสุดหรือต่ำสุดเริ่มต้นโดยการกำหนดเป้าหมายระดับ API หรือประกาศอัตราส่วนอย่างชัดเจน

รูปนี้แสดงกิจกรรมที่ไม่สามารถปรับขนาดได้โดยมีอัตราส่วนกว้างยาวที่ประกาศไว้ เมื่อพับอุปกรณ์ หน้าต่างจะถูกย่อขนาดลงเพื่อให้พอดีกับพื้นที่โดยยังคงรักษาอัตราส่วนไว้โดยใช้แถบดำแถบดำที่เหมาะสม นอกจากนี้ ผู้ใช้จะมีตัวเลือกกิจกรรมการรีสตาร์ททุกครั้งที่พื้นที่แสดงผลสำหรับกิจกรรมมีการเปลี่ยนแปลง

เมื่อกางอุปกรณ์ออก การกำหนดค่า ขนาด และอัตราส่วนภาพของกิจกรรมจะไม่เปลี่ยนแปลง แต่ตัวเลือกในการรีสตาร์ทกิจกรรมจะปรากฏขึ้น

เมื่อไม่ได้ตั้ง resizeableActivity (หรือตั้งค่าเป็น true ) แอปจะรองรับการปรับขนาดอย่างสมบูรณ์

การนำไปปฏิบัติ

กิจกรรมที่ไม่สามารถปรับขนาดได้ซึ่งมีการวางแนวหรืออัตราส่วนภาพคงที่เรียกว่าโหมดความเข้ากันได้ของขนาด (SCM) ในโค้ด เงื่อนไขถูกกำหนดไว้ใน ActivityRecord#shouldUseSizeCompatMode() เมื่อเปิดใช้งานกิจกรรม SCM การกำหนดค่าที่เกี่ยวข้องกับหน้าจอ (เช่น ขนาดหรือความหนาแน่น) จะได้รับการแก้ไขในการกำหนดค่าแทนที่ที่ร้องขอ ดังนั้นกิจกรรมจึงไม่ขึ้นอยู่กับการกำหนดค่าการแสดงผลปัจจุบันอีกต่อไป

หากกิจกรรม SCM ไม่สามารถเติมเต็มทั้งหน้าจอได้ กิจกรรมนั้นจะจัดชิดด้านบนและจัดกึ่งกลางแนวนอน ขอบเขตของกิจกรรมคำนวณโดย AppWindowToken#calculateCompatBoundsTransformation()

เมื่อกิจกรรม SCM ใช้การกำหนดค่าหน้าจอที่แตกต่างจากคอนเทนเนอร์ (เช่น จอแสดงผลถูกปรับขนาด หรือกิจกรรมถูกย้ายไปยังจอแสดงผลอื่น) ActivityRecord#inSizeCompatMode() เป็นจริง และ SizeCompatModeActivityController (ใน System UI) ได้รับการติดต่อกลับเพื่อแสดงกระบวนการ ปุ่มรีสตาร์ท

ขนาดการแสดงผลและอัตราส่วนภาพ

Android 10 ให้การสนับสนุนอัตราส่วนภาพใหม่ตั้งแต่อัตราส่วนหน้าจอที่ยาวและบางในระดับสูงไปจนถึงอัตราส่วน 1:1 แอปสามารถกำหนด ApplicationInfo#maxAspectRatio และ ApplicationInfo#minAspectRatio ของหน้าจอที่แอปสามารถจัดการได้

อัตราส่วนแอปใน Android 10

รูปที่ 1 ตัวอย่างอัตราส่วนแอปที่รองรับใน Android 10

การใช้งานอุปกรณ์สามารถมีจอแสดงผลรองที่มีขนาดและความละเอียดเล็กกว่าที่กำหนดโดย Android 9 และต่ำกว่า (ความกว้างหรือความสูงขั้นต่ำ 2.5 นิ้ว ขั้นต่ำ 320 DP สำหรับ smallestScreenWidth ) แต่เฉพาะกิจกรรมที่เลือกใช้เพื่อรองรับจอแสดงผลขนาดเล็กเหล่านี้เท่านั้นที่สามารถทำได้ วางไว้ที่นั่น

แอปสามารถเลือกใช้งานได้โดยประกาศขนาดขั้นต่ำที่รองรับซึ่งเล็กกว่า oe เท่ากับขนาดการแสดงผลเป้าหมาย ใช้แอตทริบิวต์เค้าโครงกิจกรรม android:minHeight และ android:minWidth ใน AndroidManifest เพื่อดำเนินการดังกล่าว

นโยบายการแสดงผล

Android 10 แยกและย้ายนโยบายการแสดงผลบางอย่างจากการใช้งาน WindowManagerPolicy เริ่มต้นใน PhoneWindowManager ไปยังคลาสต่อการแสดงผล เช่น:

  • แสดงสถานะและการหมุน
  • ปุ่มบางปุ่มและการติดตามเหตุการณ์การเคลื่อนไหว
  • UI ระบบและหน้าต่างตกแต่ง

ใน Android 9 (และต่ำกว่า) คลาส PhoneWindowManager จัดการนโยบายการแสดงผล สถานะและการตั้งค่า การหมุน การติดตามกรอบหน้าต่างการตกแต่ง และอื่นๆ Android 10 ย้ายส่วนใหญ่ไปยังคลาส DisplayPolicy ยกเว้นการติดตามการหมุนซึ่งถูกย้ายไปที่ DisplayRotation

การตั้งค่าหน้าต่างการแสดงผล

ใน Android 10 การตั้งค่าหน้าต่างต่อการแสดงผลที่กำหนดค่าได้ได้รับการขยายให้ครอบคลุมถึง:

  • โหมดหน้าต่างแสดงผลเริ่มต้น
  • ค่าโอเวอร์สแกน
  • การหมุนและโหมดการหมุนของผู้ใช้
  • ขนาดที่บังคับ ความหนาแน่น และโหมดการปรับขนาด
  • โหมดการลบเนื้อหา (เมื่อนำจอแสดงผลออก)
  • รองรับการตกแต่งระบบและ IME

คลาส DisplayWindowSettings ประกอบด้วยการตั้งค่าสำหรับตัวเลือกเหล่านี้ สิ่งเหล่านี้จะยังคงอยู่ในดิสก์ใน /data พาร์ติชันใน display_settings.xml ทุกครั้งที่มีการเปลี่ยนแปลงการตั้งค่า สำหรับรายละเอียด โปรดดูที่ DisplayWindowSettings.AtomicFileStorage และ DisplayWindowSettings#writeSettings() ผู้ผลิตอุปกรณ์สามารถระบุค่าเริ่มต้นใน display_settings.xml สำหรับการกำหนดค่าอุปกรณ์ของตนได้ อย่างไรก็ตาม เนื่องจากไฟล์ถูกจัดเก็บไว้ใน /data จึงอาจจำเป็นต้องใช้ตรรกะเพิ่มเติมในการกู้คืนไฟล์หากถูกลบด้วยการล้างข้อมูล

ตามค่าเริ่มต้น Android 10 จะใช้ DisplayInfo#uniqueId เป็นตัวระบุสำหรับจอแสดงผลเมื่อคงการตั้งค่าไว้ ควรมีการระบุ uniqueId สำหรับจอแสดงผลทั้งหมด นอกจากนี้ยังมีความเสถียรสำหรับการแสดงผลแบบฟิสิคัลและแบบเครือข่าย นอกจากนี้ยังสามารถใช้พอร์ตของจอแสดงผลจริงเป็นตัวระบุได้ ซึ่งสามารถตั้งค่าได้ใน DisplayWindowSettings#mIdentifier ในการเขียนแต่ละครั้ง การตั้งค่าทั้งหมดจะถูกเขียน ดังนั้นจึงปลอดภัยที่จะอัปเดตคีย์ที่ใช้สำหรับรายการแสดงผลในพื้นที่จัดเก็บข้อมูล สำหรับรายละเอียด โปรดดู ตัวระบุการแสดงผลแบบคงที่

การตั้งค่าจะยังคงอยู่ในไดเร็กทอรี /data ด้วยเหตุผลทางประวัติศาสตร์ เดิมทีใช้เพื่อคงการตั้งค่าที่ผู้ใช้กำหนดไว้ เช่น การหมุนจอแสดงผล

ตัวระบุการแสดงผลแบบคงที่

Android 9 (และต่ำกว่า) ไม่มีตัวระบุที่เสถียรสำหรับการแสดงผลในเฟรมเวิร์ก เมื่อเพิ่มจอแสดงผลลงในระบบ Display#mDisplayId หรือ DisplayInfo#displayId จะถูกสร้างขึ้นสำหรับจอแสดงผลนั้นโดยการเพิ่มตัวนับแบบคงที่ หากระบบเพิ่มและลบจอแสดงผลเดียวกัน จะเกิด ID อื่น

หากอุปกรณ์มีจอแสดงผลหลายจอตั้งแต่บูต จอแสดงผลอาจได้รับการกำหนดตัวระบุที่แตกต่างกัน ขึ้นอยู่กับช่วงเวลา แม้ว่า Android 9 (และรุ่นก่อนหน้า) จะรวม DisplayInfo#uniqueId ไว้ แต่ก็มีข้อมูลไม่เพียงพอที่จะแยกความแตกต่างระหว่างจอแสดงผลต่างๆ เนื่องจากจอแสดงผลทางกายภาพถูกระบุเป็น local:0 หรือ local:1 เพื่อแสดงถึงจอแสดงผลในตัวและจอแสดงผลภายนอก

Android 10 เปลี่ยน DisplayInfo#uniqueId เพื่อเพิ่มตัวระบุที่เสถียร และเพื่อแยกความแตกต่างระหว่างจอแสดงผลภายใน เครือข่าย และเสมือน

ประเภทการแสดงผล รูปแบบ
ท้องถิ่น
local:<stable-id>
เครือข่าย
network:<mac-address>
เสมือน
virtual:<package-name-and-name>

นอกจากการอัปเดตของ uniqueId แล้ว DisplayInfo.address ยังมี DisplayAddress ซึ่งเป็นตัวระบุการแสดงผลที่เสถียรตลอดการรีบูต ใน Android 10 DisplayAddress รองรับการแสดงผลทางกายภาพและเครือข่าย DisplayAddress.Physical มี ID การแสดงผลที่เสถียร (เหมือนกับใน uniqueId ) และสามารถสร้างได้ด้วย DisplayAddress#fromPhysicalDisplayId()

Android 10 ยังมีวิธีที่สะดวกในการรับข้อมูลพอร์ต ( Physical#getPort() ) วิธีการนี้สามารถใช้ในกรอบงานเพื่อระบุจอแสดงผลแบบคงที่ได้ ตัวอย่างเช่น ใช้ใน DisplayWindowSettings ) DisplayAddress.Network มีที่อยู่ MAC และสามารถสร้างได้ด้วย DisplayAddress#fromMacAddress()

ส่วนเพิ่มเติมเหล่านี้ช่วยให้ผู้ผลิตอุปกรณ์สามารถระบุจอแสดงผลในการตั้งค่าจอแสดงผลหลายจอแบบคงที่ และกำหนดค่าการตั้งค่าระบบและคุณสมบัติต่างๆ ได้โดยใช้ตัวระบุจอแสดงผลแบบคงที่ เช่น พอร์ตสำหรับจอแสดงผลทางกายภาพ วิธีการเหล่านี้ถูกซ่อนไว้และมีวัตถุประสงค์เพื่อใช้ภายใน system_server เท่านั้น

เมื่อกำหนด ID การแสดงผล HWC (ซึ่งอาจทึบแสงและไม่เสถียรเสมอไป) วิธีการนี้จะส่งคืนหมายเลขพอร์ต 8 บิต (เฉพาะแพลตฟอร์ม) ที่ระบุตัวเชื่อมต่อทางกายภาพสำหรับเอาต์พุตการแสดงผล รวมถึง EDID blob ของจอแสดงผล SurfaceFlinger แยกข้อมูลผู้ผลิตหรือรุ่นจาก EDID เพื่อสร้าง ID การแสดงผล 64 บิตที่เสถียรซึ่งเปิดเผยต่อเฟรมเวิร์ก หากวิธีนี้ไม่รองรับหรือเกิดข้อผิดพลาด SurfaceFlinger จะถอยกลับไปยังโหมด MD ดั้งเดิม โดยที่ DisplayInfo#address เป็น null และ DisplayInfo#uniqueId เป็นแบบฮาร์ดโค้ด ตามที่อธิบายไว้ข้างต้น

เพื่อตรวจสอบว่าคุณสมบัตินี้ได้รับการสนับสนุน ให้รัน:

$ 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"

ใช้จอแสดงผลมากกว่าสองจอ

ใน Android 9 (และต่ำกว่า) SurfaceFlinger และ DisplayManagerService ถือว่ามีจอแสดงผลจริงสูงสุดสองจอที่มีรหัสฮาร์ดโค้ด 0 และ 1

ตั้งแต่ Android 10 เป็นต้นไป SurfaceFlinger สามารถใช้ประโยชน์จาก Hardware Composer (HWC) API เพื่อสร้าง ID การแสดงผลที่เสถียร ซึ่งช่วยให้สามารถจัดการการแสดงผลทางกายภาพตามจำนวนที่ต้องการได้ หากต้องการเรียนรู้เพิ่มเติม โปรดดูที่ ตัวระบุการแสดงผลแบบคงที่

เฟรมเวิร์กสามารถค้นหาโทเค็น IBinder สำหรับการแสดงผลจริงผ่าน SurfaceControl#getPhysicalDisplayToken หลังจากได้รับ ID การแสดงผล 64 บิตจาก SurfaceControl#getPhysicalDisplayIds หรือจากเหตุการณ์ HotPlug DisplayEventReceiver

ใน Android 10 (และต่ำกว่า) จอแสดงผลภายในหลักคือ TYPE_INTERNAL และจอแสดงผลรองทั้งหมดจะถูกตั้งค่าสถานะเป็น TYPE_EXTERNAL โดยไม่คำนึงถึงประเภทการเชื่อมต่อ ดังนั้น จอแสดงผลภายในเพิ่มเติมจะถือเป็นจอแสดงผลภายนอก เพื่อเป็นวิธีแก้ปัญหา รหัสเฉพาะอุปกรณ์สามารถตั้งสมมติฐานเกี่ยวกับ DisplayAddress.Physical#getPort ได้ หากทราบ HWC และตรรกะการจัดสรรพอร์ตสามารถคาดเดาได้

ข้อจำกัดนี้จะถูกลบออกใน Android 11 (และสูงกว่า)

  • ใน Android 11 จอแสดงผลแรกที่รายงานระหว่างการบู๊ตคือจอแสดงผลหลัก ประเภทการเชื่อมต่อ (ภายในและภายนอก) ไม่มีความเกี่ยวข้อง อย่างไรก็ตาม ยังคงเป็นความจริงที่ว่าจอแสดงผลหลักไม่สามารถถอดออกได้ และในทางปฏิบัติแล้วจะต้องเป็นจอแสดงผลภายใน โปรดทราบว่าโทรศัพท์แบบพับได้บางรุ่นมีจอแสดงผลภายในหลายจอ
  • จอแสดงผลรองได้รับการจัดหมวดหมู่อย่างถูกต้องเป็น Display.TYPE_INTERNAL หรือ Display.TYPE_EXTERNAL (เดิมชื่อ Display.TYPE_BUILT_IN และ Display.TYPE_HDMI ตามลำดับ) ขึ้นอยู่กับประเภทการเชื่อมต่อ

การนำไปปฏิบัติ

ใน Android 9 และต่ำกว่า จอแสดงผลจะถูกระบุด้วย ID 32 บิต โดยที่ 0 คือจอแสดงผลภายใน 1 คือจอแสดงผลภายนอก [2, INT32_MAX] คือจอแสดงผลเสมือน HWC และ -1 หมายถึงจอแสดงผลที่ไม่ถูกต้องหรือไม่ใช่ HWC จอแสดงผลเสมือนจริง

เริ่มตั้งแต่ Android 10 เป็นต้นไป จอแสดงผลจะได้รับ ID ที่เสถียรและคงอยู่ ซึ่งช่วยให้ SurfaceFlinger และ DisplayManagerService ติดตามจอแสดงผลมากกว่าสองจอและจดจำจอแสดงผลที่เห็นก่อนหน้านี้ หาก HWC รองรับ IComposerClient.getDisplayIdentificationData และให้ข้อมูลการระบุจอแสดงผล SurfaceFlinger จะแยกวิเคราะห์โครงสร้าง EDID และจัดสรร ID การแสดงผล 64 บิตที่เสถียรสำหรับจอแสดงผลจริงและจอแสดงผลเสมือน HWC ID จะแสดงโดยใช้ประเภทตัวเลือก โดยที่ค่า Null แสดงถึงการแสดงผลที่ไม่ถูกต้องหรือการแสดงผลเสมือนที่ไม่ใช่ HWC หากไม่มีการสนับสนุน HWC SurfaceFlinger จะกลับไปใช้ลักษณะการทำงานแบบเดิมโดยมีจอแสดงผลทางกายภาพไม่เกินสองจอ

โฟกัสต่อการแสดงผล

เพื่อรองรับแหล่งอินพุตหลายแหล่งที่กำหนดเป้าหมายจอแสดงผลแต่ละจอพร้อมกัน คุณสามารถกำหนดค่า Android 10 ให้รองรับหน้าต่างที่โฟกัสหลายหน้าต่างได้มากที่สุดหนึ่งหน้าต่างต่อจอแสดงผล สิ่งนี้มีไว้สำหรับอุปกรณ์ประเภทพิเศษเท่านั้นเมื่อผู้ใช้หลายคนโต้ตอบกับอุปกรณ์เดียวกันในเวลาเดียวกันและใช้วิธีการป้อนข้อมูลหรืออุปกรณ์ที่แตกต่างกัน เช่น Android Automotive

ขอแนะนำอย่างยิ่งว่า อย่า เปิดใช้งานคุณสมบัตินี้กับอุปกรณ์ทั่วไป รวมถึงอุปกรณ์ที่มีหลายหน้าจอหรืออุปกรณ์ที่ใช้สำหรับประสบการณ์แบบเดสก์ท็อป นี่เป็นสาเหตุหลักมาจากข้อกังวลด้านความปลอดภัยที่อาจทำให้ผู้ใช้สงสัยว่าหน้าต่างใดมีโฟกัสการป้อนข้อมูล

ลองนึกภาพผู้ใช้ที่ป้อนข้อมูลที่ปลอดภัยในช่องป้อนข้อความ อาจเข้าสู่ระบบแอปธนาคารหรือป้อนข้อความที่มีข้อมูลที่ละเอียดอ่อน แอพที่เป็นอันตรายสามารถสร้างการแสดงผลเสมือนนอกหน้าจอเพื่อดำเนินกิจกรรม รวมถึงช่องป้อนข้อความด้วย กิจกรรมที่ถูกกฎหมายและเป็นอันตรายมีการมุ่งเน้นและทั้งสองจะแสดงตัวบ่งชี้อินพุตที่ใช้งานอยู่ (เคอร์เซอร์กะพริบ)

อย่างไรก็ตาม เนื่องจากการป้อนข้อมูลจากแป้นพิมพ์ (ฮาร์ดแวร์หรือซอฟต์แวร์) จะถูกป้อนเข้าสู่กิจกรรมระดับบนสุดเท่านั้น (แอปที่เปิดตัวล่าสุด) ด้วยการสร้างจอแสดงผลเสมือนที่ซ่อนอยู่ แอปที่เป็นอันตรายจึงสามารถดึงข้อมูลจากผู้ใช้ได้ แม้ว่าจะใช้แป้นพิมพ์ซอฟต์แวร์ก็ตาม บนหน้าจออุปกรณ์หลัก

ใช้ com.android.internal.R.bool.config_perDisplayFocusEnabled เพื่อตั้งค่าโฟกัสต่อการแสดงผล

ความเข้ากันได้

ปัญหา: ใน Android 9 และต่ำกว่า หน้าต่างในระบบมีโฟกัสได้สูงสุดครั้งละหนึ่งหน้าต่าง

วิธีแก้ไข: ในกรณีที่พบไม่บ่อยเมื่อหน้าต่างสองบานจากกระบวนการเดียวกันถูกโฟกัส ระบบจะให้โฟกัสเฉพาะหน้าต่างที่อยู่สูงกว่าในลำดับ Z ข้อจำกัดนี้จะถูกลบออกสำหรับแอปที่กำหนดเป้าหมายเป็น Android 10 ซึ่ง ณ จุดนี้คาดว่าจะสามารถรองรับหลายหน้าต่างที่โฟกัสพร้อมกันได้

การนำไปปฏิบัติ

WindowManagerService#mPerDisplayFocusEnabled ควบคุมความพร้อมใช้งานของคุณลักษณะนี้ ใน ActivityManager ตอน ActivityDisplay#getFocusedStack() ถูกใช้แทนการติดตามทั่วโลกในตัวแปร ActivityDisplay#getFocusedStack() กำหนดโฟกัสตามลำดับ Z แทนที่จะแคชค่า นี่เป็นเพราะว่า WindowManager แหล่งเดียวเท่านั้นที่ต้องติดตามลำดับ Z ของกิจกรรม

ActivityStackSupervisor#getTopDisplayFocusedStack() ใช้แนวทางที่คล้ายกันสำหรับกรณีเหล่านั้นเมื่อต้องระบุสแต็กที่โฟกัสบนสุดในระบบ สแต็กจะถูกสำรวจจากบนลงล่าง เพื่อค้นหาสแต็กที่มีสิทธิ์แรกที่มีสิทธิ์

ขณะนี้ InputDispatcher สามารถมีหน้าต่างที่โฟกัสได้หลายหน้าต่าง (หนึ่งหน้าต่างต่อจอแสดงผล) หากเหตุการณ์อินพุตเป็นแบบเฉพาะการแสดงผล เหตุการณ์นั้นจะถูกส่งไปยังหน้าต่างที่โฟกัสในจอแสดงผลที่เกี่ยวข้อง มิฉะนั้น จะถูกส่งไปยังหน้าต่างที่โฟกัสในจอแสดงผลที่โฟกัส ซึ่งเป็นจอแสดงผลที่ผู้ใช้โต้ตอบด้วยล่าสุด

โปรดดูที่ InputDispatcher::mFocusedWindowHandlesByDisplay และ InputDispatcher::setFocusedDisplay() แอปที่มุ่งเน้นยังได้รับการอัปเดตแยกต่างหากใน InputManagerService ผ่าน NativeInputManager::setFocusedApplication()

ใน WindowManager หน้าต่างที่โฟกัสจะถูกติดตามแยกกันเช่นกัน ดู DisplayContent#mCurrentFocus และ DisplayContent#mFocusedApp และการใช้งานที่เกี่ยวข้อง วิธีการติดตามและอัปเดตโฟกัสที่เกี่ยวข้องได้ถูกย้ายจาก WindowManagerService ไปยัง DisplayContent