อัตราเฟรม

API อัตราเฟรมช่วยให้แอปแจ้งแพลตฟอร์ม Android เกี่ยวกับอัตราเฟรมที่ต้องการได้ และพร้อมใช้งานในแอปที่กำหนดเป้าหมายเป็น Android 11 (ระดับ API 30) ขึ้นไป โดยปกติแล้ว อุปกรณ์ส่วนใหญ่จะรองรับอัตราการรีเฟรชจอแสดงผลเพียงอัตราเดียว ซึ่งมักจะเป็น 60Hz แต่ปัจจุบันมีการเปลี่ยนแปลงแล้ว อุปกรณ์หลายเครื่องรองรับอัตราการรีเฟรชเพิ่มเติม เช่น 90Hz หรือ 120Hz อุปกรณ์บางเครื่องรองรับการเปลี่ยนอัตราการรีเฟรชที่ราบรื่น ขณะที่อุปกรณ์อื่นๆ จะแสดงหน้าจอสีดำสั้นๆ ซึ่งมักจะนาน 1 วินาที

วัตถุประสงค์หลักของ API คือการช่วยให้แอปใช้ประโยชน์จากอัตราการรีเฟรชจอแสดงผลที่รองรับทั้งหมดได้ดียิ่งขึ้น ตัวอย่างเช่น แอปที่เล่นวิดีโอ 24Hz ซึ่งเรียก setFrameRate() อาจทำให้อุปกรณ์เปลี่ยนอัตราการรีเฟรชจอแสดงผลจาก 60Hz เป็น 120Hz อัตราการรีเฟรชใหม่นี้ช่วยให้เล่นวิดีโอ 24Hz ได้อย่างราบรื่นโดยไม่มีอาการภาพกระตุก และไม่จำเป็นต้องใช้การดึงลงแบบ 3:2 เหมือนกับการเล่นวิดีโอเดียวกันในจอแสดงผล 60Hz ซึ่งจะช่วยให้ประสบการณ์ของผู้ใช้ดียิ่งขึ้น

การใช้งานพื้นฐาน

Android มีวิธีต่างๆ ในการเข้าถึงและควบคุมพื้นผิว ดังนั้นจึงมี API setFrameRate() หลายเวอร์ชัน API แต่ละเวอร์ชันใช้พารามิเตอร์เดียวกันและทำงานเหมือนกัน ดังนี้

แอปไม่จำเป็นต้องพิจารณาอัตราการรีเฟรชจอแสดงผลที่รองรับจริง ซึ่งรับได้โดยการเรียก Display.getSupportedModes() เพื่อเรียก setFrameRate() อย่างปลอดภัย เช่น แม้ว่าอุปกรณ์จะรองรับเพียง 60Hz ให้เรียก setFrameRate() ด้วยอัตราเฟรมที่แอปต้องการ อุปกรณ์ที่ไม่มีอัตราเฟรมที่ตรงกับอัตราเฟรมของแอปมากกว่าจะยังคงใช้อัตราการรีเฟรชจอแสดงผลปัจจุบัน

หากต้องการดูว่าการเรียก setFrameRate() ส่งผลให้เกิดการเปลี่ยนแปลงอัตราการรีเฟรชจอแสดงผลหรือไม่ ให้ลงทะเบียนรับการแจ้งเตือนการเปลี่ยนแปลงจอแสดงผลโดยเรียกDisplayManager.registerDisplayListener()หรือ AChoreographer_registerRefreshRateCallback()

เมื่อเรียก setFrameRate() ควรส่งอัตราเฟรมที่แน่นอนแทนการปัดเศษเป็นจำนวนเต็ม เช่น เมื่อแสดงวิดีโอที่บันทึกที่ 29.97Hz ให้ส่ง 29.97 แทนการปัดเศษเป็น 30

สำหรับแอปวิดีโอ พารามิเตอร์ความเข้ากันได้ที่ส่งไปยัง setFrameRate() ควรตั้งค่าเป็น Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE เพื่อให้คำแนะนำเพิ่มเติมแก่แพลตฟอร์ม Android ว่าแอปจะใช้การดึงลงเพื่อปรับให้เข้ากับอัตราการรีเฟรชจอแสดงผลที่ไม่ตรงกัน (ซึ่งจะส่งผลให้เกิดอาการภาพกระตุก)

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

การเปลี่ยนอัตราเฟรมที่ไม่ราบรื่น

ในอุปกรณ์บางเครื่อง การเปลี่ยนอัตราการรีเฟรชอาจมีการหยุดชะงักทางภาพ เช่น หน้าจอสีดำเป็นเวลา 1-2 วินาที ซึ่งมักเกิดขึ้นในกล่องรับสัญญาณ ทีวี และอุปกรณ์ที่คล้ายกัน โดยค่าเริ่มต้น เฟรมเวิร์ก Android จะไม่เปลี่ยนโหมด เมื่อมีการเรียก API Surface.setFrameRate() เพื่อหลีกเลี่ยงการหยุดชะงักทางภาพดังกล่าว

ผู้ใช้บางรายชอบการหยุดชะงักทางภาพที่จุดเริ่มต้นและจุดสิ้นสุดของวิดีโอที่ยาวขึ้น ซึ่งจะช่วยให้อัตราการรีเฟรชจอแสดงผลตรงกับอัตราเฟรมของวิดีโอ และหลีกเลี่ยงสิ่งประดิษฐ์จากการแปลงอัตราเฟรม เช่น อาการภาพกระตุกจากการดึงลงแบบ 3:2 สำหรับการเล่นภาพยนตร์

ด้วยเหตุนี้ การเปลี่ยนอัตราการรีเฟรชที่ไม่ราบรื่นจึงเปิดใช้ได้หากทั้งผู้ใช้และแอปเลือกใช้

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

คำแนะนำเพิ่มเติม

ทำตามคำแนะนำเหล่านี้สำหรับสถานการณ์ทั่วไป

พื้นผิวหลายรายการ

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

แพลตฟอร์มไม่เปลี่ยนเป็นอัตราเฟรมของแอป

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

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

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

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

ในบางกรณี แพลตฟอร์มอาจเปลี่ยนเป็นอัตราเฟรมที่เป็นจำนวนเท่าของอัตราเฟรมที่แอประบุใน setFrameRate() เช่น แอปอาจเรียก setFrameRate() ด้วย 60Hz และอุปกรณ์อาจเปลี่ยนจอแสดงผลเป็น 120Hz เหตุผลหนึ่งที่อาจเกิดกรณีนี้คือหากแอปอื่นมีพื้นผิวที่มีการตั้งค่าอัตราเฟรมเป็น 24Hz ในกรณีนั้น การแสดงผลที่ 120Hz จะช่วยให้ทั้งพื้นผิว 60Hz และพื้นผิว 24Hz ทำงานได้โดยไม่จำเป็นต้องใช้การดึงลง

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

setFrameRate() เทียบกับ preferredDisplayModeId

WindowManager.LayoutParams.preferredDisplayModeId เป็นอีกวิธีหนึ่งที่แอปสามารถระบุอัตราเฟรมของตนเองไปยังแพลตฟอร์มได้ แอปบางแอปต้องการเปลี่ยนอัตราการรีเฟรชจอแสดงผลเท่านั้น แทนที่จะเปลี่ยนการตั้งค่าโหมดการแสดงผลอื่นๆ เช่น ความละเอียดในการแสดงผล โดยทั่วไป ให้ใช้ setFrameRate() แทน preferredDisplayModeId ฟังก์ชัน setFrameRate() ใช้งานง่ายกว่าเนื่องจากแอปไม่จำเป็นต้องค้นหารายการโหมดการแสดงผลเพื่อหาโหมดที่มีอัตราเฟรมที่เฉพาะเจาะจง

setFrameRate() ช่วยให้แพลตฟอร์มมีโอกาสมากขึ้นในการเลือกอัตราเฟรมที่เข้ากันได้ในสถานการณ์ที่มีพื้นผิวหลายรายการที่ทำงานที่อัตราเฟรมแตกต่างกัน ตัวอย่างเช่น พิจารณาสถานการณ์ที่แอป 2 แอปทำงานในโหมดแยกหน้าจอบน Pixel 4 โดยแอปหนึ่งกำลังเล่นวิดีโอ 24Hz และอีกแอปหนึ่งกำลังแสดงรายการที่เลื่อนได้ให้ผู้ใช้ Pixel 4 รองรับอัตราการรีเฟรชจอแสดงผล 2 อัตรา ได้แก่ 60Hz และ 90Hz การใช้ API preferredDisplayModeId จะบังคับให้พื้นผิววิดีโอเลือก 60Hz หรือ 90Hz การเรียก setFrameRate() ด้วย 24Hz จะทำให้พื้นผิววิดีโอให้ข้อมูลเพิ่มเติมแก่แพลตฟอร์มเกี่ยวกับอัตราเฟรมของวิดีโอต้นฉบับ ซึ่งช่วยให้แพลตฟอร์มเลือก 90Hz สำหรับอัตราการรีเฟรชจอแสดงผลได้ ซึ่งดีกว่า 60Hz ในสถานการณ์นี้

อย่างไรก็ตาม มีบางสถานการณ์ที่ควรใช้ preferredDisplayModeId แทน setFrameRate() เช่น สถานการณ์ต่อไปนี้

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

setFrameRate() เทียบกับ preferredRefreshRate

WindowManager.LayoutParams#preferredRefreshRate จะตั้งค่าอัตราเฟรมที่ต้องการในหน้าต่างของแอป และอัตรานี้ใช้ได้กับพื้นผิวทั้งหมดภายในหน้าต่าง แอปควรกำหนดอัตราเฟรมที่ต้องการโดยไม่คำนึงถึงอัตราการรีเฟรชที่อุปกรณ์รองรับ ซึ่งคล้ายกับ setFrameRate() เพื่อให้ตัวจัดตารางเวลาได้รับคำแนะนำที่ดีขึ้นเกี่ยวกับอัตราเฟรมที่แอปต้องการ

ระบบจะละเว้น preferredRefreshRate สำหรับพื้นผิวที่ใช้ setFrameRate() โดยทั่วไป ให้ใช้ setFrameRate() หากเป็นไปได้

preferredRefreshRate เทียบกับ preferredDisplayModeId

หากแอปต้องการเปลี่ยนเฉพาะอัตราการรีเฟรชที่ต้องการ เราขอแนะนำให้ใช้ preferredRefreshRate แทน preferredDisplayModeId

หลีกเลี่ยงการเรียก setFrameRate() บ่อยเกินไป

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

การใช้งานสำหรับเกมหรือแอปที่ไม่ใช่วิดีโออื่นๆ

แม้ว่าวิดีโอจะเป็นกรณีการใช้งานหลักสำหรับ API setFrameRate() แต่ก็สามารถใช้กับแอปอื่นๆ ได้ ตัวอย่างเช่น เกมที่ไม่ต้องการทำงานสูงกว่า 60Hz (เพื่อลดการใช้พลังงานและเล่นได้นานขึ้น) สามารถเรียก Surface.setFrameRate(60, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT) ด้วยวิธีนี้ อุปกรณ์ที่ทำงานที่ 90Hz โดยค่าเริ่มต้นจะทำงานที่ 60Hz ขณะที่เกมทำงานอยู่ ซึ่งจะหลีกเลี่ยงอาการภาพกระตุกที่อาจเกิดขึ้นหากเกมทำงานที่ 60Hz ขณะที่จอแสดงผลทำงานที่ 90Hz

การใช้งาน FRAME_RATE_COMPATIBILITY_FIXED_SOURCE

FRAME_RATE_COMPATIBILITY_FIXED_SOURCE มีไว้สำหรับแอปวิดีโอเท่านั้น สำหรับการใช้งานที่ไม่ใช่วิดีโอ ให้ใช้ FRAME_RATE_COMPATIBILITY_DEFAULT

การเลือกกลยุทธ์สำหรับการเปลี่ยนอัตราเฟรม

  • เราขอแนะนำอย่างยิ่งให้แอปเรียก setFrameRate(fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS) เมื่อแสดงวิดีโอที่เล่นนาน เช่น ภาพยนตร์ โดยที่ fps คืออัตราเฟรมของวิดีโอ
  • เราขอแนะนำอย่างยิ่งไม่ให้แอปเรียก setFrameRate() ด้วย CHANGE_FRAME_RATE_ALWAYS เมื่อคุณคาดว่าการเล่นวิดีโอจะใช้เวลาหลายนาทีหรือน้อยกว่า

ตัวอย่างการผสานรวมสำหรับแอปเล่นวิดีโอ

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

  1. กำหนด changeFrameRateStrategy ดังนี้
    1. หากเล่นวิดีโอที่เล่นนาน เช่น ภาพยนตร์ ให้ใช้ MATCH_CONTENT_FRAMERATE_ALWAYS
    2. หากเล่นวิดีโอสั้น เช่น ตัวอย่างภาพยนตร์ ให้ใช้ CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
  2. หาก changeFrameRateStrategy เป็น CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS ให้ไปที่ขั้นตอนที่ 4
  3. ตรวจหาว่าการเปลี่ยนอัตราการรีเฟรชที่ไม่ราบรื่นกำลังจะเกิดขึ้นหรือไม่ โดยตรวจสอบว่าข้อเท็จจริงทั้ง 2 ข้อต่อไปนี้เป็นจริง
    1. ไม่สามารถเปลี่ยนโหมดราบรื่นจากอัตราการรีเฟรชปัจจุบัน (สมมติว่าเป็น C) เป็นอัตราเฟรมของวิดีโอ (สมมติว่าเป็น V) กรณีนี้จะเกิดขึ้นหาก C และ V แตกต่างกัน และ Display.getMode().getAlternativeRefreshRates ไม่มีจำนวนเท่าของ V
    2. ผู้ใช้เลือกใช้การเปลี่ยนแปลงอัตราการรีเฟรชที่ไม่ราบรื่น คุณตรวจหา ได้โดยตรวจสอบว่า DisplayManager.getMatchContentFrameRateUserPreference แสดงผล MATCH_CONTENT_FRAMERATE_ALWAYS หรือไม่
  4. หากการเปลี่ยนจะราบรื่น ให้ทำดังนี้
    1. เรียก setFrameRate และส่ง fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, และ changeFrameRateStrategy โดยที่ fps คืออัตราเฟรมของวิดีโอ
    2. เริ่มเล่นวิดีโอ
  5. หากการเปลี่ยนโหมดที่ไม่ราบรื่นกำลังจะเกิดขึ้น ให้ทำดังนี้
    1. แสดง UX เพื่อแจ้งให้ผู้ใช้ทราบ โปรดทราบว่าเราขอแนะนำให้คุณใช้วิธีให้ผู้ใช้ปิด UX นี้และข้ามการหน่วงเวลาเพิ่มเติมในขั้นตอนที่ 5.d เนื่องจากการหน่วงเวลาที่เราแนะนำนั้นนานกว่าที่จำเป็นในจอแสดงผลที่เปลี่ยนได้เร็วกว่า
    2. เรียก setFrameRate และส่ง fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, และ CHANGE_FRAME_RATE_ALWAYS, โดยที่ fps คืออัตราเฟรมของวิดีโอ
    3. รอการเรียกกลับ onDisplayChanged
    4. รอ 2 วินาทีเพื่อให้การเปลี่ยนโหมดเสร็จสมบูรณ์
    5. เริ่มเล่นวิดีโอ

รหัสเทียมเพื่อรองรับการเปลี่ยนที่ราบรื่นเท่านั้น มีดังนี้

SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
transaction.setFrameRate(surfaceControl,
    contentFrameRate,
    FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
    CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
transaction.apply();
beginPlayback();

รหัสเทียมเพื่อรองรับการเปลี่ยนที่ราบรื่นและไม่ราบรื่นตามที่อธิบายไว้ข้างต้นมีดังนี้

SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
if (isSeamlessSwitch(contentFrameRate)) {
  transaction.setFrameRate(surfaceControl,
      contentFrameRate,
      FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
      CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
  transaction.apply();
  beginPlayback();
} else if (displayManager.getMatchContentFrameRateUserPreference()
      == MATCH_CONTENT_FRAMERATE_ALWAYS) {
  showRefreshRateSwitchUI();
  sleep(shortDelaySoUserSeesUi);
  displayManager.registerDisplayListener();
  transaction.setFrameRate(surfaceControl,
      contentFrameRate,
      FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
      CHANGE_FRAME_RATE_ALWAYS);
  transaction.apply();
  waitForOnDisplayChanged();
  sleep(twoSeconds);
  hideRefreshRateSwitchUI();
  beginPlayback();
}