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

การอัปเดตที่ทํากับพื้นที่เฉพาะของจอแสดงผลมีดังนี้

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

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

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

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

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

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

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

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

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

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

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

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

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

การใช้งาน

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

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

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

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

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

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

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

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

แอปเลือกใช้ได้โดยประกาศขนาดขั้นต่ำที่รองรับซึ่งเล็กกว่าหรือเท่ากับขนาดการแสดงผลเป้าหมาย โดยให้ใช้แอตทริบิวต์เลย์เอาต์กิจกรรม 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 ให้กับจอแสดงผลนั้นโดยการเพิ่มตัวนับแบบคงที่ หากระบบเพิ่มและนําจอแสดงผลเดียวกันออก รหัสที่ได้จะต่างออกไป

หากอุปกรณ์มีจอแสดงผลหลายจอที่พร้อมใช้งานตั้งแต่การบูต ระบบอาจกำหนดตัวระบุที่แตกต่างกันให้กับจอแสดงผล ทั้งนี้ขึ้นอยู่กับช่วงเวลา แม้ว่า 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 มีรหัส Display แบบคงที่ (เหมือนกับใน uniqueId) และสร้างขึ้นได้ด้วย DisplayAddress#fromPhysicalDisplayId()

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

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

เมื่อระบุรหัสจอแสดงผล HWC (ซึ่งอาจทึบแสงและไม่เสถียรเสมอไป) วิธีการนี้จะแสดงผลหมายเลขพอร์ต 8 บิต (สำหรับแพลตฟอร์มที่เฉพาะเจาะจง) ซึ่งระบุขั้วต่อทางกายภาพสำหรับเอาต์พุตของจอแสดงผล รวมถึง BLOB EDID ของจอแสดงผล SurfaceFlinger จะดึงข้อมูลผู้ผลิตหรือโมเดลจาก EDID เพื่อสร้างรหัสการแสดงผล 64 บิตแบบคงที่ที่เปิดเผยต่อเฟรมเวิร์ก หากระบบไม่รองรับวิธีนี้หรือเกิดข้อผิดพลาด SurfaceFlinger จะกลับไปใช้โหมด MD เดิม โดยที่ DisplayInfo#address เป็นค่าว่างและ 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"

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

ใน Android 9 (และต่ำกว่า) SurfaceFlinger และ DisplayManagerService assumed the existence of at most two physical displays with hard-coded IDs 0 and 1

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

เฟรมเวิร์กจะค้นหาโทเค็น IBinder สำหรับจอแสดงผลจริงผ่าน SurfaceControl#getPhysicalDisplayToken หลังจากได้รับรหัสจอแสดงผล 64 บิตจาก SurfaceControl#getPhysicalDisplayIds หรือจากเหตุการณ์การเสียบปลั๊ก 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 และต่ำกว่า ระบบจะระบุจอแสดงผลด้วยรหัส 32 บิต โดยที่ 0 คือจอแสดงผลภายใน, 1 คือจอแสดงผลภายนอก, [2, INT32_MAX] คือจอแสดงผลเสมือน HWC และ -1 แสดงถึงจอแสดงผลที่ไม่ถูกต้องหรือจอแสดงผลเสมือนที่ไม่ใช่ HWC

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

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

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

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

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

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

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

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

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

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

การใช้งาน

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

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

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

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

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