หัวข้อนี้แสดงวิธีตั้งค่ากรณีการใช้งาน CameraX ภายในแอปเพื่อรับ
ซึ่งมีข้อมูลการหมุนที่ถูกต้อง ไม่ว่าจะมาจาก
ImageAnalysis
หรือกรณีการใช้งาน ImageCapture
ดังนั้น:
Analyzer
ของกรณีการใช้งานImageAnalysis
ควรได้รับเฟรมที่มี การหมุนที่ถูกต้อง- กรณีการใช้งาน
ImageCapture
ควรถ่ายภาพด้วยการหมุนที่ถูกต้อง
คำศัพท์
หัวข้อนี้ใช้คำศัพท์ต่อไปนี้ ดังนั้นการทำความเข้าใจว่าแต่ละคำหมายความว่าอย่างไร เป็นสิ่งสำคัญ:
- การวางแนวจอแสดงผล
- ส่วนนี้หมายถึงด้านใดของอุปกรณ์อยู่ในตำแหน่งที่สูงขึ้น และ ค่าใดค่าหนึ่งใน 4 ค่า ได้แก่ แนวตั้ง แนวนอน ย้อนกลับแนวตั้ง หรือย้อนกลับ แนวนอน
- การหมุนจอแสดงผล
- นี่คือค่าที่แสดงผลโดย
Display.getRotation()
และ แสดงองศาที่หมุนอุปกรณ์ทวนเข็มนาฬิกาจาก การวางแนวตามธรรมชาติ - การหมุนเวียนเป้าหมาย
- ข้อมูลนี้แสดงค่าองศาที่จะหมุน วางอุปกรณ์ตามเข็มนาฬิกาเพื่อให้ถึงแนวที่เป็นธรรมชาติ
วิธีระบุการหมุนเวียนเป้าหมาย
ตัวอย่างต่อไปนี้แสดงวิธีกำหนดการหมุนเป้าหมายสำหรับอุปกรณ์ ตามการวางแนวธรรมชาติ
ตัวอย่างที่ 1: การวางแนวตามธรรมชาติของแนวตั้ง
ตัวอย่างอุปกรณ์: Pixel 3 XL | |
---|---|
การวางแนวธรรมชาติ = แนวตั้ง การหมุนจอแสดงผล = 0 |
|
การวางแนวธรรมชาติ = แนวตั้ง การหมุนจอแสดงผล = 90 |
ตัวอย่างที่ 2: การวางแนวนอนตามธรรมชาติ
ตัวอย่างอุปกรณ์: Pixel C | |
---|---|
การวางแนวธรรมชาติ = แนวนอน การหมุนจอแสดงผล = 0 |
|
การวางแนวธรรมชาติ = แนวนอน การหมุนจอแสดงผล = 270 |
การหมุนภาพ
ปลายสายข้างไหนเป็นปลายสาย การวางแนวเซ็นเซอร์กำหนดไว้ใน Android เป็นค่าคงที่ ซึ่งแสดงองศา (0, 90, 180, 270) ที่เซ็นเซอร์หมุนจาก ที่ด้านบนของอุปกรณ์เมื่ออุปกรณ์อยู่ในตำแหน่งตามปกติ สำหรับ ในแผนภาพ การหมุนภาพจะอธิบายว่าข้อมูลควรเป็นอย่างไร หมุนตามเข็มนาฬิกาเพื่อให้ตั้งตรง
ตัวอย่างต่อไปนี้แสดงลักษณะการหมุนของภาพโดยขึ้นอยู่กับ การวางแนวเซ็นเซอร์ของกล้อง และจะถือว่ามีการตั้งค่าการหมุนเวียนเป้าหมายเป็น การหมุนจอแสดงผล
ตัวอย่างที่ 1: เซ็นเซอร์หมุน 90 องศา
ตัวอย่างอุปกรณ์: Pixel 3 XL | |
---|---|
การหมุนจอแสดงผล = 0 |
|
การหมุนจอแสดงผล = 90 |
ตัวอย่างที่ 2: เซ็นเซอร์หมุน 270 องศา
ตัวอย่างอุปกรณ์: Nexus 5X | |
---|---|
การหมุนจอแสดงผล = 0 |
|
การหมุนจอแสดงผล = 90 |
ตัวอย่างที่ 3: เซ็นเซอร์หมุน 0 องศา
ตัวอย่างอุปกรณ์: Pixel C (แท็บเล็ต) | |
---|---|
การหมุนจอแสดงผล = 0 |
|
การหมุนจอแสดงผล = 270 |
การคำนวณการหมุนของรูปภาพ
การวิเคราะห์รูปภาพ
Analyzer
ของ ImageAnalysis
ได้รับรูปภาพจากกล้องในรูปแบบ
ImageProxy
วินาที รูปภาพแต่ละรูปจะมีข้อมูลการหมุน ซึ่งสามารถเข้าถึงได้
ผ่าน:
val rotation = imageProxy.imageInfo.rotationDegrees
ค่านี้แสดงองศาที่ต้องใช้การหมุนรูปภาพ
ตามเข็มนาฬิกาเพื่อให้ตรงกับการหมุนเป้าหมายของ ImageAnalysis
ในบริบทของ
แอป Android การหมุนเป้าหมายของ ImageAnalysis
มักจะตรงกับ
การวางแนวของหน้าจอ
จับภาพ
Callback จะแนบอยู่กับอินสแตนซ์ ImageCapture
เพื่อส่งสัญญาณเมื่อมีการจับภาพ
ผลลัพธ์พร้อมแล้ว ผลลัพธ์อาจเป็นรูปภาพที่จับภาพไว้หรือข้อผิดพลาดก็ได้
เมื่อถ่ายภาพ Callback ที่ให้ไว้อาจมีสถานะอย่างใดอย่างหนึ่งต่อไปนี้ ประเภท:
OnImageCapturedCallback
: รับรูปภาพที่มีสิทธิ์เข้าถึงด้วยหน่วยความจำใน ของImageProxy
OnImageSavedCallback
: เรียกใช้เมื่อจับภาพแล้ว จัดเก็บไว้ในตำแหน่งที่ระบุโดยImageCapture.OutputFileOptions
ตัวเลือกสามารถระบุFile
OutputStream
หรือสถานที่ตั้งในMediaStore
การหมุนของรูปภาพที่จับภาพไว้โดยไม่คำนึงถึงรูปแบบ (ImageProxy
File
, OutputStream
, MediaStore Uri
) แสดงถึงองศาการหมุนตาม
ซึ่งภาพที่จับไว้จะต้องหมุนตามเข็มนาฬิกาเพื่อให้ตรงกับ ImageCapture
การหมุนเวียนเป้าหมาย ซึ่งในบริบทของแอป Android โดยทั่วไป
ให้ตรงกับการวางแนวของหน้าจอ
การดึงข้อมูลการหมุนภาพที่จับภาพทำได้โดยทำอย่างใดอย่างหนึ่งต่อไปนี้ ด้วยวิธีต่อไปนี้
ImageProxy
val rotation = imageProxy.imageInfo.rotationDegrees
File
val exif = Exif.createFromFile(file) val rotation = exif.rotation
OutputStream
val byteArray = outputStream.toByteArray() val exif = Exif.createFromInputStream(ByteArrayInputStream(byteArray)) val rotation = exif.rotation
MediaStore uri
val inputStream = contentResolver.openInputStream(outputFileResults.savedUri) val exif = Exif.createFromInputStream(inputStream) val rotation = exif.rotation
ยืนยันการหมุนของรูปภาพ
กรณีการใช้งาน ImageAnalysis
และ ImageCapture
ได้รับ ImageProxy
จาก
กล้องหลังจากส่งคำขอจับภาพสำเร็จ ImageProxy
รวมรูปภาพและ
เกี่ยวกับข้อมูลที่เกี่ยวข้อง รวมถึงการหมุนเวียนของโมเดลนั้นๆ ข้อมูลการหมุนเวียนนี้
แสดงองศาของการหมุนภาพเพื่อให้ตรงกับการใช้งาน
การหมุนเวียนเป้าหมายของตัวพิมพ์เล็ก/ใหญ่
หลักเกณฑ์การหมุนเวียนเป้าหมายของ ImageCapture/ImageAnalysis
เนื่องจากอุปกรณ์จำนวนมากไม่หมุนกลับในแนวตั้งหรือกลับด้านแนวนอน โดยค่าเริ่มต้น แอป Android บางแอปจะไม่รองรับการวางแนวเหล่านี้ การระบุว่าแอป รองรับหรือไม่เปลี่ยนวิธีการหมุนเวียนเป้าหมายของกรณีการใช้งาน อัปเดตแล้ว
ด้านล่างคือตาราง 2 ตารางที่กำหนดวิธีทำให้การหมุนเวียนเป้าหมายของกรณีการใช้งานซิงค์กันอยู่เสมอ ด้วยการหมุนจอแสดงผล ภาพแรกแสดงวิธีการ พร้อมทั้งสนับสนุน 4 ทิศทาง ส่วนที่สองจะจัดการกับการวางแนวที่อุปกรณ์หมุนเท่านั้น เป็น โดยค่าเริ่มต้น
วิธีเลือกหลักเกณฑ์ที่ต้องปฏิบัติตามในแอป
ตรวจสอบว่ากล้อง
Activity
ของแอปมีการวางแนวที่ล็อกไว้หรือไม่ การวางแนวที่ปลดล็อกอยู่ หรือหากมีการลบล้างการเปลี่ยนแปลงการกำหนดค่าการวางแนวเลือกว่าจะให้กล้องของแอป
Activity
รองรับอุปกรณ์ทั้ง 4 เครื่องหรือไม่ การวางแนว (แนวตั้ง แนวตั้งแบบกลับด้าน แนวนอน และกลับด้าน) หรือควรรองรับการวางแนวที่อุปกรณ์ ใช้อยู่รองรับเท่านั้น โดยค่าเริ่มต้น
รองรับการวางแนวทั้ง 4 แบบ
ตารางนี้กล่าวถึงหลักเกณฑ์บางประการที่ต้องปฏิบัติตามสำหรับกรณีที่อุปกรณ์ ไม่หมุนเพื่อกลับแนวตั้ง เช่นเดียวกันกับอุปกรณ์ ไม่หมุนกลับแนวนอน
สถานการณ์ | หลักเกณฑ์ | โหมดหน้าต่างเดียว | โหมดแยกหน้าจอหลายหน้าต่าง |
---|---|---|---|
การวางแนวที่ไม่ได้ล็อก |
ตั้งค่า Use Case ทุก
เวลาที่มีการสร้าง Activity เช่น
การติดต่อกลับ onCreate() ของ Activity
|
||
ใช้ของ OrientationEventListener
onOrientationChanged()
ภายใน Callback ให้อัปเดตการหมุนเวียนเป้าหมายของ Use Case ซึ่งสามารถรองรับกรณีที่ระบบไม่
สร้าง Activity ใหม่แม้หลังจากการเปลี่ยนการวางแนว
เหมือนตอนที่อุปกรณ์หมุน 180 องศา
|
แฮนเดิลด้วยเมื่อจอแสดงผลอยู่ในแนวกลับด้าน แนวตั้งและอุปกรณ์ไม่หมุนเพื่อกลับภาพแนวตั้ง "ค่าเริ่มต้น" |
จัดการกรณีที่ Activity ไม่
เกิดขึ้นใหม่เมื่ออุปกรณ์หมุน (เช่น 90 องศา) สิ่งนี้จะเกิดขึ้นในวันที่
อุปกรณ์รูปแบบของอุปกรณ์ขนาดเล็กเมื่อแอปกินพื้นที่ครึ่งหนึ่งของหน้าจอ
อุปกรณ์เมื่อแอปใช้พื้นที่ 2 ใน 3 ของหน้าจอ
|
|
ไม่บังคับ: ตั้งค่าscreenOrientation ของ Activity
พร็อพเพอร์ตี้ให้กับ fullSensor ใน AndroidManifest
|
วิธีนี้จะช่วยให้ UI ตั้งตรงเมื่ออุปกรณ์อยู่กลับด้าน
แนวตั้ง และอนุญาตให้
สร้าง Activity อีกครั้ง
เมื่อใดก็ตามที่อุปกรณ์หมุน 90 องศา
|
จะไม่มีผลกับอุปกรณ์ที่ไม่มีการหมุนเพื่อกลับภาพบุคคลภายใน "ค่าเริ่มต้น" ระบบไม่รองรับโหมดหลายหน้าต่างขณะที่จอแสดงผลอยู่ใน กลับแนวตั้ง | |
การวางแนวที่ล็อก |
ตั้งค่า Use Case เพียงครั้งเดียวเมื่อ
Activity สร้างขึ้นครั้งแรก เช่น ใน Activity
onCreate() Callback
|
||
ใช้ของ OrientationEventListener
onOrientationChanged()
ภายใน Callback ให้อัปเดตการหมุนเวียนเป้าหมายของกรณีการใช้งาน ยกเว้นการแสดงตัวอย่าง
|
จัดการกรณีที่ Activity ไม่
เกิดขึ้นใหม่เมื่ออุปกรณ์หมุน (เช่น 90 องศา) สิ่งนี้จะเกิดขึ้นในวันที่
อุปกรณ์รูปแบบของอุปกรณ์ขนาดเล็กเมื่อแอปกินพื้นที่ครึ่งหนึ่งของหน้าจอ
อุปกรณ์เมื่อแอปใช้พื้นที่ 2 ใน 3 ของหน้าจอ
|
||
ลบล้าง configChanges การวางแนวแล้ว |
ตั้งค่า Use Case เพียงครั้งเดียวเมื่อ
Activity สร้างขึ้นครั้งแรก เช่น ใน Activity
onCreate() Callback
|
||
ใช้ของ OrientationEventListener
onOrientationChanged()
ภายใน Callback ให้อัปเดตการหมุนเวียนเป้าหมายของ Use Case
|
จัดการกรณีที่ Activity ไม่
เกิดขึ้นใหม่เมื่ออุปกรณ์หมุน (เช่น 90 องศา) สิ่งนี้จะเกิดขึ้นในวันที่
อุปกรณ์รูปแบบของอุปกรณ์ขนาดเล็กเมื่อแอปกินพื้นที่ครึ่งหนึ่งของหน้าจอ
อุปกรณ์เมื่อแอปใช้พื้นที่ 2 ใน 3 ของหน้าจอ
|
||
ไม่บังคับ: ตั้งค่าพร็อพเพอร์ตี้ screenOrientation ของกิจกรรมเป็น FullSensor ใน ไฟล์ AndroidManifest | อนุญาตให้ UI ตั้งตรงเมื่ออุปกรณ์อยู่ในแนวตั้งกลับกัน | จะไม่มีผลกับอุปกรณ์ที่ไม่มีการหมุนเพื่อกลับภาพบุคคลภายใน "ค่าเริ่มต้น" ระบบไม่รองรับโหมดหลายหน้าต่างขณะที่จอแสดงผลอยู่ใน กลับแนวตั้ง |
รองรับการวางแนวที่อุปกรณ์รองรับเท่านั้น
รองรับเฉพาะการวางแนวที่อุปกรณ์รองรับโดยค่าเริ่มต้น (ซึ่งอาจ ต้องไม่รวมแนวตั้ง/กลับด้าน)
สถานการณ์ | หลักเกณฑ์ | โหมดแยกหน้าจอหลายหน้าต่าง |
---|---|---|
การวางแนวที่ไม่ได้ล็อก |
ตั้งค่า Use Case ทุก
เวลาที่มีการสร้าง Activity เช่น
การติดต่อกลับ onCreate() ของ Activity
|
|
ใช้ของ DisplayListener
onDisplayChanged() ภายใน
Callback อัปเดตการหมุนเวียนเป้าหมายของกรณีการใช้งาน เช่น
อุปกรณ์หมุน 180 องศาแล้ว
|
จัดการกรณีที่ Activity ไม่
เกิดขึ้นใหม่เมื่ออุปกรณ์หมุน (เช่น 90 องศา) สิ่งนี้จะเกิดขึ้นในวันที่
อุปกรณ์รูปแบบของอุปกรณ์ขนาดเล็กเมื่อแอปกินพื้นที่ครึ่งหนึ่งของหน้าจอ
อุปกรณ์เมื่อแอปใช้พื้นที่ 2 ใน 3 ของหน้าจอ
|
|
การวางแนวที่ล็อก |
ตั้งค่า Use Case เพียงครั้งเดียวเมื่อ
Activity สร้างขึ้นครั้งแรก เช่น ใน Activity
onCreate() Callback
|
|
ใช้ของ OrientationEventListener
onOrientationChanged()
ภายใน Callback ให้อัปเดตการหมุนเวียนเป้าหมายของ Use Case
|
จัดการกรณีที่ Activity ไม่
เกิดขึ้นใหม่เมื่ออุปกรณ์หมุน (เช่น 90 องศา) สิ่งนี้จะเกิดขึ้นในวันที่
อุปกรณ์รูปแบบของอุปกรณ์ขนาดเล็กเมื่อแอปกินพื้นที่ครึ่งหนึ่งของหน้าจอ
อุปกรณ์เมื่อแอปใช้พื้นที่ 2 ใน 3 ของหน้าจอ
|
|
ลบล้าง configChanges การวางแนวแล้ว |
ตั้งค่า Use Case เพียงครั้งเดียวเมื่อ
Activity สร้างขึ้นครั้งแรก เช่น ใน Activity
onCreate() Callback
|
|
ใช้ของ DisplayListener
onDisplayChanged() ภายใน
Callback อัปเดตการหมุนเวียนเป้าหมายของกรณีการใช้งาน เช่น
อุปกรณ์หมุน 180 องศาแล้ว
|
จัดการกรณีที่ Activity ไม่
เกิดขึ้นใหม่เมื่ออุปกรณ์หมุน (เช่น 90 องศา) สิ่งนี้จะเกิดขึ้นในวันที่
อุปกรณ์รูปแบบของอุปกรณ์ขนาดเล็กเมื่อแอปกินพื้นที่ครึ่งหนึ่งของหน้าจอ
อุปกรณ์เมื่อแอปใช้พื้นที่ 2 ใน 3 ของหน้าจอ
|
ปลดล็อกการวางแนวแล้ว
Activity
มีการวางแนวที่ปลดล็อกเมื่อการวางแนวจอแสดงผล
(เช่น แนวตั้งหรือแนวนอน) ตรงกับการวางแนวของอุปกรณ์ด้วย
ยกเว้นแนวตั้ง/แนวนอนแบบย้อนกลับ ซึ่งอุปกรณ์บางรุ่นไม่รองรับ
โดยค่าเริ่มต้น หากต้องการบังคับให้อุปกรณ์หมุนไปทั้ง 4 ทิศทาง ให้ตั้งค่า
พร็อพเพอร์ตี้ screenOrientation
ของ Activity
ไปยัง fullSensor
ในโหมดหลายหน้าต่าง อุปกรณ์ที่ไม่รองรับกลับแนวตั้ง/แนวนอน
โดยค่าเริ่มต้น จะไม่หมุนกลับในแนวตั้ง/แนวนอน แม้ว่า
ตั้งค่าพร็อพเพอร์ตี้ screenOrientation
เป็น fullSensor
<!-- The Activity has an unlocked orientation, but might not rotate to reverse portrait/landscape in single-window mode if the device doesn't support it by default. --> <activity android:name=".UnlockedOrientationActivity" /> <!-- The Activity has an unlocked orientation, and will rotate to all four orientations in single-window mode. --> <activity android:name=".UnlockedOrientationActivity" android:screenOrientation="fullSensor" />
ล็อกการวางแนวอยู่
จอแสดงผลจะมีการวางแนวที่ล็อกไว้เมื่อวางอยู่ในการวางแนวจอแสดงผลเดิม
(เช่น แนวตั้งหรือแนวนอน) ไม่ว่าอุปกรณ์จะวางในแนวใด
อุปกรณ์ ซึ่งทำได้โดยการระบุ screenOrientation
ของ Activity
ภายในการประกาศในไฟล์ AndroidManifest.xml
เมื่อวางการวางแนวจอแสดงผลไว้ ระบบจะไม่ทำลายและ
สร้าง Activity
ใหม่ขณะที่หมุนอุปกรณ์
<!-- The Activity keeps a portrait orientation even as the device rotates. --> <activity android:name=".LockedOrientationActivity" android:screenOrientation="portrait" />
ลบล้างการเปลี่ยนแปลงการกำหนดค่าการวางแนวแล้ว
เมื่อ Activity
ลบล้างการกำหนดค่าการวางแนว ระบบอาจ
ไม่ทำลายและสร้างขึ้นใหม่เมื่อการวางแนวอุปกรณ์เปลี่ยนไป
ระบบจะอัปเดต UI เพื่อให้ตรงกับการวางแนวของอุปกรณ์
<!-- The Activity's UI might not rotate in reverse portrait/landscape if the device doesn't support it by default. --> <activity android:name=".OrientationConfigChangesOverriddenActivity" android:configChanges="orientation|screenSize" /> <!-- The Activity's UI will rotate to all 4 orientations in single-window mode. --> <activity android:name=".OrientationConfigChangesOverriddenActivity" android:configChanges="orientation|screenSize" android:screenOrientation="fullSensor" />
การตั้งค่ากรณีการใช้งานกล้อง
ในสถานการณ์ที่อธิบายไว้ข้างต้น กรณีการใช้งานกล้องสามารถตั้งค่าได้เมื่อ
Activity
สร้างขึ้นครั้งแรก
ในกรณีของ Activity
ที่มีการวางแนวที่ปลดล็อกแล้ว การตั้งค่านี้จะดำเนินการเสร็จสิ้น
ทุกครั้งที่หมุนอุปกรณ์ เพราะระบบจะทำลายและสร้าง
Activity
เมื่อเปลี่ยนการวางแนว ซึ่งทำให้ตั้งค่ากรณีการใช้งาน
การหมุนเป้าหมายให้ตรงกับการวางแนวของจอแสดงผลโดยค่าเริ่มต้นทุกครั้ง
ในกรณีของ Activity
ซึ่งการวางแนวที่ล็อกไว้หรือการวางแนวที่ลบล้าง
มีการเปลี่ยนแปลงการกำหนดค่าการวางแนว การตั้งค่านี้จะเกิดขึ้นเพียงครั้งเดียวเมื่อActivity
สร้างขึ้นครั้งแรก
class CameraActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val cameraProcessFuture = ProcessCameraProvider.getInstance(this) cameraProcessFuture.addListener(Runnable { val cameraProvider = cameraProcessFuture.get() // By default, the use cases set their target rotation to match the // display’s rotation. val preview = buildPreview() val imageAnalysis = buildImageAnalysis() val imageCapture = buildImageCapture() cameraProvider.bindToLifecycle( this, cameraSelector, preview, imageAnalysis, imageCapture) }, mainExecutor) } }
การตั้งค่า OrientationEventListener
การใช้ OrientationEventListener
ช่วยให้คุณอัปเดตเป้าหมายอย่างต่อเนื่อง
การหมุนของกรณีการใช้งานกล้องเมื่อการวางแนวของอุปกรณ์เปลี่ยนแปลง
class CameraActivity : AppCompatActivity() { private val orientationEventListener by lazy { object : OrientationEventListener(this) { override fun onOrientationChanged(orientation: Int) { if (orientation == ORIENTATION_UNKNOWN) { return } val rotation = when (orientation) { in 45 until 135 -> Surface.ROTATION_270 in 135 until 225 -> Surface.ROTATION_180 in 225 until 315 -> Surface.ROTATION_90 else -> Surface.ROTATION_0 } imageAnalysis.targetRotation = rotation imageCapture.targetRotation = rotation } } } override fun onStart() { super.onStart() orientationEventListener.enable() } override fun onStop() { super.onStop() orientationEventListener.disable() } }
การตั้งค่า DisplayListener
การใช้ DisplayListener
ช่วยให้คุณอัปเดตการหมุนเป้าหมายของกล้องได้
ใช้งานในบางกรณี เช่น เมื่อระบบไม่ทำลาย
และสร้าง Activity
ใหม่หลังจากที่อุปกรณ์หมุน 180 องศา
class CameraActivity : AppCompatActivity() { private val displayListener = object : DisplayManager.DisplayListener { override fun onDisplayChanged(displayId: Int) { if (rootView.display.displayId == displayId) { val rotation = rootView.display.rotation imageAnalysis.targetRotation = rotation imageCapture.targetRotation = rotation } } override fun onDisplayAdded(displayId: Int) { } override fun onDisplayRemoved(displayId: Int) { } } override fun onStart() { super.onStart() val displayManager = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager displayManager.registerDisplayListener(displayListener, null) } override fun onStop() { super.onStop() val displayManager = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager displayManager.unregisterDisplayListener(displayListener) } }