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

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

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

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 ก็จะทำให้เกิดการแข่งขัน ปัญหานี้สามารถหลีกเลี่ยงได้โดยใช้การเรียกกลับที่กําหนดเองจาก WindowManager ไปยัง 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

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

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

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

การใช้งาน

ใน Android 10 RootActivityContainer#startHomeOnDisplay() จะเลือกคอมโพเนนต์และความตั้งใจที่ต้องการโดยอัตโนมัติโดยขึ้นอยู่กับจอแสดงผลที่เปิดหน้าจอหลัก RootActivityContainer#resolveSecondaryHomeActivity() มีตรรกะในการค้นหาคอมโพเนนต์กิจกรรมของ Launcher โดยขึ้นอยู่กับ 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 ตรรกะสำรองของวอลเปเปอร์สำหรับจอแสดงผลรอง