การสนับสนุนการตกแต่งระบบ

การอัปเดตเกี่ยวกับพื้นที่ที่แสดงผลโดยเฉพาะมีดังต่อไปนี้

การตกแต่งระบบ

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

ใช้ DisplayWindowSettings#setShouldShowSystemDecorsLocked() เพื่อเพิ่มการรองรับการตกแต่งระบบในจอแสดงผลที่เฉพาะเจาะจง หรือ ค่าเริ่มต้นใน /data/system/display_settings.xml ตัวอย่างเช่น ดูการตั้งค่าหน้าต่างการแสดงผล

การใช้งาน

DisplayWindowSettings#setShouldShowSystemDecorsLocked() ก็แสดงใน WindowManager#setShouldShowSystemDecors()สำหรับการทดสอบ การทริกเกอร์เมธอดนี้ ที่มีจุดประสงค์เพื่อเปิดใช้การตกแต่งระบบจะไม่เพิ่มหน้าต่างการตกแต่งที่ หายไปก่อนหน้านี้ หรือนำออกหากเคยอยู่มาก่อนหน้า ส่วนใหญ่ การเปลี่ยนแปลงการสนับสนุนการตกแต่งระบบจะมีผลอย่างสมบูรณ์หลังจาก รีบูตอุปกรณ์

ตรวจสอบการรองรับการตกแต่งระบบในฐานโค้ด WindowManager โดยปกติจะผ่าน DisplayContent#supportsSystemDecorations() ขณะที่ ตรวจสอบบริการภายนอก (เช่น UI ของระบบเพื่อดูว่าแถบนำทางหรือไม่ ควรแสดงขึ้น) ใช้ WindowManager#shouldShowSystemDecors() หากต้องการทําความเข้าใจสิ่งที่ควบคุมโดยการตั้งค่านี้ ให้ดูจุดโทรของ วิธีการเหล่านี้

หน้าต่างตกแต่ง UI ระบบ

Android 10 เพิ่มการรองรับหน้าต่างการตกแต่งระบบ สำหรับแถบนำทางเท่านั้น เนื่องจากแถบนำทางเป็นสิ่งจำเป็น สำหรับการนำทางระหว่างกิจกรรมและแอป โดยค่าเริ่มต้น แถบนำทางจะแสดง ค่าใช้จ่ายสำหรับบ้านและหลังบ้าน โดยจะรวมเฉพาะในกรณีที่จอแสดงผลเป้าหมายรองรับ การตกแต่งระบบ (ดูDisplayWindowSettings)

แถบสถานะ เป็นหน้าต่างระบบที่ซับซ้อนกว่าเนื่องจาก ยังมีหน้าต่างแจ้งเตือน การตั้งค่าด่วน และหน้าจอล็อกด้วย ใน Android 10 จอแสดงผลรองไม่รองรับแถบสถานะ ดังนั้น การแจ้งเตือน การตั้งค่า และการล็อกคีย์เต็มรูปแบบจะใช้ได้เฉพาะใน จอแสดงผลหลัก

รองไม่รองรับหน้าต่างระบบภาพรวม/ล่าสุด หน้าจอ ใน Android 10 AOSP จะแสดงเฉพาะ "ล่าสุด" ใน จอแสดงผลเริ่มต้นและมีกิจกรรมจากจอแสดงผลทั้งหมด เมื่อเปิดจาก เมื่อเร็วๆ นี้ กิจกรรมที่อยู่บนจอแสดงผลสำรองจะถูกนำมาแสดงด้านหน้าใน ที่แสดงโดยค่าเริ่มต้น แนวทางนี้มีปัญหาที่ทราบแล้ว เช่น โดยจะอัปเดตทันทีที่แอปแสดงบนหน้าจออื่นๆ

การใช้งาน

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

คอมโพเนนต์ UI ของระบบที่รองรับ Multi-Display (MD) ควรจัดการ กรณีต่อไปนี้

  • การเริ่มต้นโฆษณาแบบดิสเพลย์หลายรายการเมื่อเริ่มต้นระบบ
  • เพิ่มจอแสดงผลขณะรันไทม์แล้ว
  • นำจอแสดงผลออกขณะรันไทม์

เมื่อ UI ของระบบตรวจพบการเพิ่มการแสดงผลก่อน WindowManager ระบบจะสร้าง ภาวะแข่งขัน คุณสามารถหลีกเลี่ยงปัญหานี้ได้โดยใช้ Callback ที่กําหนดเองจาก WindowManager ไปยัง System UI เมื่อมีการเพิ่มจอแสดงผลแทนที่จะสมัครรับข้อมูล เหตุการณ์ DisplayManager.DisplayListener สำหรับการใช้ข้อมูลอ้างอิง ดูการรองรับแถบนำทางที่ CommandQueue.Callbacks#onDisplayReady และ WallpaperManagerInternal#onDisplayReady สำหรับวอลเปเปอร์

นอกจากนี้ Android 10 ยังมีการอัปเดตต่อไปนี้ด้วย

  • ชั้นเรียน NavigationBarController จะควบคุมทุกฟังก์ชัน เฉพาะแถบนำทางเท่านั้น
  • ดูแถบนำทางแบบกำหนดเองได้ที่ CarStatusBar
  • TYPE_NAVIGATION_BAR ไม่ได้จํากัดอยู่ที่รายการเดียวอีกต่อไป และสามารถใช้ได้ต่อดิสเพลย์
  • IWindowManager#hasNavigationBar() มีการอัปเดตให้รวม พารามิเตอร์ displayId สำหรับ UI ของระบบเท่านั้น

ปืนยิงลูกระเบิด

ใน Android 10 หน้าจอแต่ละหน้าจอได้รับการกำหนดค่าให้รองรับ การตกแต่งระบบมีสแต็กหน้าแรกสำหรับกิจกรรมของ Launcher ที่มีประเภท WindowConfiguration#ACTIVITY_TYPE_HOME โดยค่าเริ่มต้น จอแสดงผลแต่ละจอ ใช้อินสแตนซ์แยกต่างหากของกิจกรรม Launcher

รูปที่ 1 ตัวอย่าง Launcher แบบหลายจอแสดงผลสำหรับ platform/development/samples/MultiDisplay

Launcher ที่มีอยู่ส่วนใหญ่ไม่รองรับอินสแตนซ์หลายรายการและไม่ได้รับการเพิ่มประสิทธิภาพ สำหรับหน้าจอขนาดใหญ่ และเรายังคาดหวังว่า บนจอแสดงผลรอง/ภายนอก เพื่อมอบกิจกรรมเฉพาะสำหรับกิจกรรมรอง Android 10 เปิดตัวหมวดหมู่ SECONDARY_HOME ใน Intent ตัวกรอง อินสแตนซ์ของกิจกรรมนี้จะใช้ในจอแสดงผลทั้งหมดที่ระบบสนับสนุน สำหรับการตกแต่ง หนึ่งชิ้นต่อหนึ่งจอแสดงผล

<activity>
    ...
    <intent-filter>
        <category android:name="android.intent.category.SECONDARY_HOME" />
        ...
    </intent-filter>
</activity>

กิจกรรมต้องมีโหมดเปิดใช้งานที่ไม่ป้องกันการใช้ และคาดว่าจะปรับให้เข้ากับหน้าจอขนาดต่างๆ โหมดเปิดใช้งาน ต้องไม่ใช่ singleInstance หรือ singleTask

การใช้งาน

ใน Android 10 RootActivityContainer#startHomeOnDisplay() จะเลือกคอมโพเนนต์และความตั้งใจที่ต้องการโดยอัตโนมัติโดยขึ้นอยู่กับการแสดงผล ที่มีการเปิดหน้าจอหลัก RootActivityContainer#resolveSecondaryHomeActivity() มีตรรกะในการค้นหาคอมโพเนนต์กิจกรรมตัวเรียกใช้งานโดยขึ้นอยู่กับ Launcher ที่เลือกไว้ และสามารถใช้ค่าเริ่มต้นของระบบได้ ถ้าจำเป็น (โปรดดู ActivityTaskManagerService#getSecondaryHomeIntent())

ข้อจำกัดด้านความปลอดภัย

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

วอลเปเปอร์

ใน Android 10 (และสูงกว่า) รองรับวอลเปเปอร์ ในจอแสดงผลรอง

รูปที่ 2 วอลเปเปอร์เคลื่อนไหวทั้งภายใน (ด้านบน) และภายนอก จอแสดงผล (ด้านล่าง)

นักพัฒนาแอปสามารถประกาศการรองรับฟีเจอร์วอลเปเปอร์โดย android:supportsMultipleDisplays="true" ในช่วง ข้อกำหนด XML WallpaperInfo นอกจากนี้ นักพัฒนาวอลเปเปอร์ คาดว่าจะโหลดเนื้อหาโดยใช้บริบทการแสดงผลใน WallpaperService.Engine#getDisplayContext()

เฟรมเวิร์กจะสร้างอินสแตนซ์ WallpaperService.Engine 1 รายการ ต่อจอแสดงผล ดังนั้นแต่ละเครื่องมือจึงแสดงพื้นผิวและบริบทในการแสดงผลของตัวเอง ต้องแน่ใจว่าแต่ละเครื่องมือ สามารถวาดแยกกันได้ อัตราเฟรมที่ต่างกัน โดยขึ้นอยู่กับ VSYNC

เลือกวอลเปเปอร์สำหรับแต่ละหน้าจอ

Android 10 ไม่รองรับแพลตฟอร์มโดยตรงสำหรับการเลือกวอลเปเปอร์ สำหรับแต่ละหน้าจอ ตัวระบุดิสเพลย์ที่เสถียรคือ ที่จำเป็นต่อการคงการตั้งค่าวอลเปเปอร์ต่อจอแสดงผล Display#getDisplayId() เป็นแบบไดนามิก ดังนั้นจึงไม่สามารถรับประกันได้ว่า จอแสดงผลจริงจะมีรหัสเดียวกันหลังจากรีบูต

อย่างไรก็ตาม Android 10 ได้เพิ่ม DisplayInfo.mAddress ซึ่งมีตัวระบุแบบคงที่สำหรับจอแสดงผลจริง และใช้สำหรับ การนำไปใช้ในอนาคต น่าเสียดายที่สายเกินไปแล้วที่จะใช้ตรรกะนี้ สำหรับ Android 10 วิธีแก้ปัญหาที่แนะนำ

  1. ใช้ WallpaperManager API เพื่อตั้งค่าวอลเปเปอร์
  2. ได้รับ WallpaperManager จาก Context และออบเจ็กต์ Context แต่ละรายการมีข้อมูลเกี่ยวกับ จอแสดงผล (Context#getDisplay()/getDisplayId()) ดังนั้นคุณจึงสามารถ รับ displayId จากอินสแตนซ์ WallpaperManager โดยไม่ต้องเพิ่มเมธอดใหม่
  3. ในฝั่งของเฟรมเวิร์ก ให้ใช้ displayId ที่ได้รับจาก Context และแมปกับตัวระบุแบบคงที่ (เช่น พอร์ตของ จอแสดงผลจริง) ใช้ตัวระบุแบบคงที่เพื่อคงวอลเปเปอร์ที่เลือกไว้

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

หากจำเป็นต้องตั้งค่าวอลเปเปอร์สำหรับจอแสดงผลอื่นนอกเหนือจากจอแสดงผลปัจจุบัน จากนั้นสร้างออบเจ็กต์ Context ใหม่สำหรับพื้นที่แสดงผลเป้าหมาย (Context#createDisplayContext) และรับ WallpaperManager อินสแตนซ์จากจอแสดงผลนั้น

ข้อจำกัดด้านความปลอดภัย

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

การใช้งาน

ใน Android 10 IWallpaperConnection#attachEngine() และอินเทอร์เฟซ IWallpaperService#attach() ยอมรับ displayId เพื่อสร้างการเชื่อมต่อต่อจอแสดงผล WallpaperManagerService.DisplayConnector สรุปต่อจอแสดงผล เครื่องมือและการเชื่อมต่อวอลเปเปอร์ ใน WindowManager เครื่องมือควบคุมวอลเปเปอร์จะเป็น ที่สร้างขึ้นสำหรับออบเจ็กต์ DisplayContent แต่ละรายการขณะสร้างแทนที่จะเป็น WallpaperController เดียวสำหรับจอแสดงผลทั้งหมด

การใช้เมธอด WallpaperManager แบบสาธารณะบางส่วน (เช่น WallpaperManager#getDesiredMinimumWidth()) ได้รับการอัปเดตเพื่อประมวลผล และให้ข้อมูลสำหรับจอแสดงผลที่เกี่ยวข้อง WallpaperInfo#supportsMultipleDisplays() และ มีการเพิ่มแอตทริบิวต์ทรัพยากร เพื่อให้นักพัฒนาแอปสามารถรายงานว่า พร้อมใช้งานบนหลายหน้าจอได้แล้ว

หากบริการวอลเปเปอร์ที่แสดงในจอแสดงผลเริ่มต้นไม่รองรับ จอแสดงผลหลายจอ จากนั้นระบบจะแสดงวอลเปเปอร์เริ่มต้นบนอุปกรณ์รอง จอแสดงผล

รูปที่ 3 ตรรกะสำรองของวอลเปเปอร์สำหรับจอแสดงผลสำรอง