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

การอัปเดตที่ทำในพื้นที่เฉพาะของโฆษณา Display เหล่านี้จะแสดงในหน้านี้

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

Android 10 เพิ่มการรองรับการกำหนดค่าจอแสดงผลรองเพื่อแสดงการตกแต่งระบบบางอย่าง เช่น วอลเปเปอร์ แถบนำทาง และตัวเรียกใช้ โดยค่าเริ่มต้น จอแสดงผลหลักจะแสดงการตกแต่งระบบทั้งหมด และ จอแสดงผลรองจะแสดงการตกแต่งที่เปิดใช้โดยไม่บังคับ คุณตั้งค่าการรองรับตัวแก้ไขวิธีการป้อนข้อมูล (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 ของระบบที่รองรับการแสดงผลแบบหลายจอ (MD) ควรจัดการกรณีต่อไปนี้

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

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

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

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

Launcher

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

รูปที่ 1 ตัวอย่างโปรแกรมเรียกใช้แบบหลายจอแสดงผลสำหรับ platform/development/samples/MultiDisplay

โดย Launcher ที่มีอยู่ส่วนใหญ่ไม่รองรับหลายอินสแตนซ์และไม่ได้ปรับให้เหมาะกับ หน้าจอขนาดใหญ่ นอกจากนี้ ผู้ใช้มักคาดหวังประสบการณ์การใช้งานที่แตกต่างกัน บนจอแสดงผลรอง/ภายนอก 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 จะเลือกคอมโพเนนต์และ Intent ที่ต้องการโดยอัตโนมัติตามจอแสดงผล ที่เปิดใช้หน้าจอหลัก RootActivityContainer#resolveSecondaryHomeActivity มีตรรกะในการค้นหาคอมโพเนนต์กิจกรรมของตัวเรียกใช้โดยขึ้นอยู่กับตัวเรียกใช้ที่เลือกในปัจจุบัน และสามารถใช้ค่าเริ่มต้นของระบบได้หากจำเป็น (ดู 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 คลาสเพื่อตั้งค่าวอลเปเปอร์

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

  2. ในฝั่งเฟรมเวิร์ก ให้ใช้ displayId ที่ได้จากออบเจ็กต์ Context แล้วแมปกับตัวระบุแบบคงที่ (เช่น พอร์ตของ จอแสดงผลจริง) ใช้ตัวระบุแบบคงที่เพื่อคงวอลเปเปอร์ที่เลือกไว้

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

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

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

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

การใช้งาน

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

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

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

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

เปิดใช้การรองรับวอลเปเปอร์เคลื่อนไหว

ใน Android 10 ขึ้นไป (API 29) นักพัฒนาแอปสามารถใช้แอตทริบิวต์ android:supportsMultipleDisplays เพื่อระบุว่าวอลเปเปอร์ของตนเองจะแสดงในจอแสดงผลต่างๆ ได้หรือไม่ ในสภาพแวดล้อมของหน้าต่างเดสก์ท็อป ซึ่งมีการทำงานแบบมัลติทาสก์อย่างหนาแน่น การแสดงวอลเปเปอร์เคลื่อนไหวบนจอแสดงผลภายนอกอาจส่งผลกระทบอย่างมากต่อ ค่าใช้จ่ายของ GPU และหน่วยความจำ

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

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

หากฮาร์ดแวร์แสดงผลวอลเปเปอร์เคลื่อนไหวหลายอินสแตนซ์ได้ ให้ลบล้างการกำหนดค่าต่อไปนี้

เส้นทางทรัพยากร frameworks/base/core/res/res/values/config.xml
ชื่อการกำหนดค่า config_isLiveWallpaperSupportedInDesktopExperience

ปรับแต่งวอลเปเปอร์สำรอง

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

เส้นทางทรัพยากร frameworks/base/core/res/res/values/config.xml
ชื่อการกำหนดค่า fallback_wallpaper_component

ใช้การรองรับวอลเปเปอร์

หากต้องการใช้การเปลี่ยนแปลงเหล่านี้ ให้ใช้การวางซ้อนทรัพยากรในเวลาบิลด์ในโฟลเดอร์เฉพาะอุปกรณ์ ซึ่งโดยปกติคือ device/<vendor>/<product>/overlay/frameworks/base/core/res/res/values/