Android 17 มาพร้อมฟีเจอร์และ API ใหม่ๆ ที่ยอดเยี่ยมสำหรับนักพัฒนาแอป ส่วนต่อไปนี้ จะสรุปฟีเจอร์เหล่านี้เพื่อช่วยให้คุณเริ่มต้นใช้งาน API ที่เกี่ยวข้องได้
หากต้องการดูรายการ API ใหม่ที่มีการแก้ไขและถูกนำออกโดยละเอียด โปรดอ่านรายงานความแตกต่างของ API ดูรายละเอียดเกี่ยวกับ API ใหม่ได้ที่เอกสารอ้างอิง Android API โดยเราจะไฮไลต์ API ใหม่เพื่อให้มองเห็นได้ชัดเจน
นอกจากนี้ คุณควรตรวจสอบส่วนที่การเปลี่ยนแปลงของแพลตฟอร์มอาจส่งผลต่อแอปด้วย ดูข้อมูลเพิ่มเติมได้ที่หน้าต่อไปนี้
- การเปลี่ยนแปลงลักษณะการทำงานที่มีผลกับแอปเมื่อกำหนดเป้าหมายเป็น Android 17
- การเปลี่ยนแปลงลักษณะการทำงานที่มีผลกับแอปทั้งหมดโดยไม่คำนึงถึง
targetSdkVersion
ฟังก์ชันหลัก
Android 17 เพิ่มฟีเจอร์ใหม่ต่อไปนี้ที่เกี่ยวข้องกับฟังก์ชันหลักของ Android
ทริกเกอร์ ProfilingManager ใหม่
Android 17 เพิ่มทริกเกอร์ระบบใหม่หลายรายการลงใน ProfilingManager เพื่อ
ช่วยคุณรวบรวมข้อมูลเชิงลึกสำหรับแก้ไขข้อบกพร่องของปัญหาด้านประสิทธิภาพ
ทริกเกอร์ใหม่มีดังนี้
TRIGGER_TYPE_COLD_START: ทริกเกอร์จะเริ่มทำงานระหว่าง Cold Start ของแอป โดยจะแสดงตัวอย่างสแต็กการเรียกใช้และข้อมูลการติดตามระบบในการตอบกลับTRIGGER_TYPE_OOM: ทริกเกอร์จะเริ่มทำงานเมื่อแอปแสดงOutOfMemoryErrorและแสดง Java Heap Dump ในการตอบกลับTRIGGER_TYPE_KILL_EXCESSIVE_CPU_USAGE: ทริกเกอร์จะเริ่มทำงานเมื่อระบบปิดแอปเนื่องจากการใช้ CPU ผิดปกติและมากเกินไป และแสดงตัวอย่างสแต็กการเรียกใช้ในการตอบกลับTRIGGER_TYPE_ANOMALY: ตรวจหาความผิดปกติของประสิทธิภาพระบบ เช่น การเรียก Binder มากเกินไปและการใช้งานหน่วยความจำมากเกินไป
หากต้องการดูวิธีตั้งค่าทริกเกอร์ระบบ โปรดดูเอกสารประกอบเกี่ยวกับ การสร้างโปรไฟล์ตามทริกเกอร์และวิธีดึงและวิเคราะห์ข้อมูลการสร้างโปรไฟล์ เอกสารประกอบ
ทริกเกอร์การสร้างโปรไฟล์สำหรับความผิดปกติของแอป
Android 17 ขอแนะนำบริการตรวจหาความผิดปกติในอุปกรณ์ ซึ่งจะตรวจสอบลักษณะการทำงานที่ใช้ทรัพยากรมากและอาจเกิดการถดถอยด้านความเข้ากันได้ บริการนี้ผสานรวม
กับ ProfilingManagerจึงช่วยให้แอปของคุณรับอาร์ติแฟกต์การสร้างโปรไฟล์
ที่ทริกเกอร์โดยเหตุการณ์ที่ระบบตรวจพบได้
ใช้ทริกเกอร์ TRIGGER_TYPE_ANOMALY เพื่อตรวจหาปัญหาด้านประสิทธิภาพของระบบ
เช่น การเรียก Binder มากเกินไปและการใช้งานหน่วยความจำมากเกินไป เมื่อแอปละเมิดขีดจำกัดหน่วยความจำที่ระบบปฏิบัติการกำหนดไว้ ทริกเกอร์ความผิดปกติจะช่วยให้นักพัฒนาแอปได้รับ Heap Dump ที่เฉพาะเจาะจงกับแอปเพื่อช่วยระบุและแก้ไขปัญหาหน่วยความจำ นอกจากนี้ ทริกเกอร์ความผิดปกติยังแสดงโปรไฟล์แบบสุ่มตัวอย่างสแต็กในธุรกรรม Binder สำหรับการส่ง Binder Spam มากเกินไป
การเรียกกลับของ API นี้จะเกิดขึ้นก่อนการบังคับใช้ใดๆ ที่ระบบกำหนด เช่น ช่วยให้นักพัฒนาแอปเก็บรวบรวมข้อมูลการแก้ไขข้อบกพร่องได้ก่อนที่ระบบจะยุติแอปเนื่องจากใช้หน่วยความจำเกินขีดจำกัด
val profilingManager =
applicationContext.getSystemService(ProfilingManager::class.java)
val triggers = ArrayList<ProfilingTrigger>()
triggers.add(ProfilingTrigger.Builder(ProfilingTrigger.TRIGGER_TYPE_ANOMALY))
val mainExecutor: Executor = Executors.newSingleThreadExecutor()
val resultCallback = Consumer<ProfilingResult> { profilingResult ->
if (profilingResult.errorCode != ProfilingResult.ERROR_NONE) {
// upload profile result to server for further analysis
setupProfileUploadWorker(profilingResult.resultFilePath)
}
profilingManager.registerForAllProfilingResults(mainExecutor,
resultCallback)
profilingManager.addProfilingTriggers(triggers)
}
API ของ JobDebugInfo
Android 17 ขอแนะนำ API JobDebugInfo ใหม่ที่จะช่วยนักพัฒนาแอปในการแก้ไขข้อบกพร่องของงาน JobScheduler เช่น เหตุผลที่งานไม่ทำงาน ระยะเวลาที่งานทำงาน และข้อมูลรวมอื่นๆ
เมธอดแรกของ API JobDebugInfo ที่ขยายแล้วคือ
getPendingJobReasonStats() ซึ่งจะแสดงผลแผนผังของเหตุผลที่งานอยู่ใน
สถานะรอการดำเนินการและระยะเวลารอสะสมของแต่ละเหตุผล
เมธอดนี้จะเข้าร่วมกับเมธอด getPendingJobReasonsHistory() และ
getPendingJobReasons() เพื่อให้ข้อมูลเชิงลึกเกี่ยวกับเหตุผลที่งานที่กำหนดเวลาไว้ไม่ทำงานตามที่คาดไว้ แต่จะลดความซับซ้อนในการดึงข้อมูลโดยทำให้ทั้งระยะเวลาและเหตุผลของงานพร้อมใช้งานในเมธอดเดียว
ตัวอย่างเช่น สำหรับ jobId ที่ระบุ เมธอดอาจแสดงผล PENDING_JOB_REASON_CONSTRAINT_CHARGING และระยะเวลา 60000 มิลลิวินาที ซึ่งบ่งชี้ว่างานรอเป็นเวลา 60000 มิลลิวินาทีเนื่องจากข้อจำกัดในการชาร์จไม่เป็นไปตามเงื่อนไข
ลด Wake Lock ด้วยการรองรับ Listener สำหรับการปลุกที่อนุญาตขณะไม่ได้ใช้งาน
Android 17
เปิดตัวAlarmManager.setExactAndAllowWhileIdle รูปแบบใหม่ที่
ยอมรับ OnAlarmListener แทน PendingIntent กลไกใหม่ที่อิงตาม
การเรียกกลับนี้เหมาะสำหรับแอปที่ปัจจุบันใช้
WakeLock ต่อเนื่องเพื่อทำงานเป็นระยะๆ เช่น แอปส่งข้อความที่รักษาการเชื่อมต่อซ็อกเก็ต
ความเป็นส่วนตัว
Android 17 มีฟีเจอร์ใหม่ต่อไปนี้เพื่อปรับปรุงความเป็นส่วนตัวของผู้ใช้
การรองรับแพลตฟอร์มสำหรับ ClientHello ที่เข้ารหัส (ECH)
Android 17 เปิดตัวการรองรับแพลตฟอร์มสำหรับ Encrypted Client Hello (ECH) ซึ่งเป็นการปรับปรุงความเป็นส่วนตัวที่สำคัญสำหรับการสื่อสารผ่านเครือข่าย ECH เป็นส่วนขยายของ TLS 1.3 ที่เข้ารหัสการระบุชื่อเซิร์ฟเวอร์ (SNI) ระหว่างแฮนด์เชค TLS เริ่มต้น การเข้ารหัสนี้ช่วยปกป้องความเป็นส่วนตัวของผู้ใช้ด้วยการทำให้ตัวกลางในเครือข่ายระบุโดเมนที่เฉพาะเจาะจงซึ่งแอปเชื่อมต่อได้ยากขึ้น
ตอนนี้แพลตฟอร์มมี API ที่จำเป็นสำหรับไลบรารีระบบเครือข่ายเพื่อใช้ ECH แล้ว ซึ่งรวมถึงความสามารถใหม่ใน DnsResolver ในการค้นหาระเบียน DNS ของ HTTPS ที่มีการกำหนดค่า ECH และเมธอดใหม่ใน SSLEngines และ SSLSockets ของ Conscrypt เพื่อเปิดใช้ ECH โดยการส่งการกำหนดค่าเหล่านี้เมื่อเชื่อมต่อกับโดเมน นักพัฒนาแอปสามารถกำหนดค่ากำหนด ECH เช่น
การเปิดใช้แบบมีโอกาสหรือการกำหนดให้ใช้ ผ่านองค์ประกอบใหม่
<domainEncryption> ภายในไฟล์การกำหนดค่าความปลอดภัยของเครือข่าย
ซึ่งใช้ได้ทั่วโลกหรือในระดับโดเมน
คาดว่าไลบรารีเครือข่ายยอดนิยม เช่น HttpEngine, WebView และ OkHttp จะผสานรวม API ของแพลตฟอร์มเหล่านี้ในการอัปเดตในอนาคต ซึ่งจะช่วยให้แอปนำ ECH ไปใช้และปรับปรุงความเป็นส่วนตัวของผู้ใช้ได้ง่ายขึ้น
ดูข้อมูลเพิ่มเติมได้ที่เอกสารประกอบการทักทายไคลเอ็นต์ที่เข้ารหัส
เครื่องมือเลือกรายชื่อติดต่อ Android
เครื่องมือเลือกรายชื่อติดต่อ Android เป็นอินเทอร์เฟซที่ได้มาตรฐานและเรียกดูได้สำหรับผู้ใช้ในการแชร์รายชื่อติดต่อกับแอปของคุณ เครื่องมือเลือกนี้พร้อมใช้งานในอุปกรณ์ที่ใช้ Android 17 (ระดับ API 37) ขึ้นไป และเป็นทางเลือกที่ช่วยรักษาความเป็นส่วนตัวแทนREAD_CONTACTSแบบกว้าง แทนที่จะขอสิทธิ์เข้าถึงสมุดที่อยู่ทั้งหมดของผู้ใช้ แอปจะระบุฟิลด์ข้อมูลที่ต้องการ เช่น หมายเลขโทรศัพท์หรืออีเมล และผู้ใช้จะเลือกรายชื่อติดต่อที่ต้องการแชร์ได้ ซึ่งจะให้สิทธิ์แอปของคุณในการเข้าถึงแบบอ่านเฉพาะข้อมูลที่เลือก เพื่อให้ควบคุมได้อย่างละเอียดในขณะที่มอบประสบการณ์ของผู้ใช้ที่สอดคล้องกันด้วยความสามารถในการค้นหาในตัว การสลับโปรไฟล์ และการเลือกหลายรายการโดยไม่ต้องสร้างหรือบำรุงรักษา UI
ดูข้อมูลเพิ่มเติมได้ที่เอกสารประกอบของเครื่องมือเลือกรายชื่อติดต่อ
ความปลอดภัย
Android 17 เพิ่มฟีเจอร์ใหม่ต่อไปนี้เพื่อปรับปรุงความปลอดภัยของอุปกรณ์และแอป
โหมดการปกป้องขั้นสูงของ Android (AAPM)
โหมดการปกป้องขั้นสูงของ Android มอบฟีเจอร์ด้านความปลอดภัยชุดใหม่ที่ทรงพลังให้แก่ผู้ใช้ Android ซึ่งถือเป็นก้าวสำคัญในการปกป้องผู้ใช้ โดยเฉพาะผู้ที่มีความเสี่ยงสูงจากการโจมตีที่ซับซ้อน AAPM ออกแบบมาให้เป็นฟีเจอร์ที่เลือกใช้ได้ โดยจะเปิดใช้งานด้วยการตั้งค่าเดียวที่ผู้ใช้เปิดได้ทุกเมื่อ เพื่อใช้ชุดการป้องกันความปลอดภัยที่กำหนดไว้
การกำหนดค่าหลักเหล่านี้รวมถึงการบล็อกการติดตั้งแอปจากแหล่งที่มาที่ไม่รู้จัก
(การโหลดจากแหล่งที่ไม่รู้จัก) การจำกัดการส่งสัญญาณข้อมูลผ่าน USB และการกำหนดให้สแกนด้วย Google Play Protect
ซึ่งจะช่วยลดพื้นที่ผิวการโจมตีของอุปกรณ์ได้อย่างมาก
นักพัฒนาแอปสามารถผสานรวมกับฟีเจอร์นี้ได้โดยใช้ API AdvancedProtectionManager เพื่อตรวจหาสถานะของโหมด ซึ่งจะช่วยให้แอปพลิเคชันใช้ท่าทีด้านความปลอดภัยที่เข้มงวดขึ้นโดยอัตโนมัติ หรือจำกัดฟังก์ชันการทำงานที่มีความเสี่ยงสูงเมื่อผู้ใช้เลือกใช้
การทำ APK Signing ด้วย PQC
ตอนนี้ Android รองรับ APK Signature Scheme แบบไฮบริดแล้ว เพื่อให้ข้อมูลประจำตัวสำหรับการลงนามของแอปปลอดภัยจากภัยคุกคามที่อาจเกิดขึ้นจากการโจมตีที่ใช้การประมวลผลควอนตัม ฟีเจอร์นี้จะแนะนำ APK Signature Scheme ใหม่ ซึ่งช่วยให้คุณจับคู่คีย์การลงนามแบบคลาสสิก (เช่น RSA หรือ EC) กับอัลกอริทึมวิทยาการเข้ารหัสหลังควอนตัม (PQC) ใหม่ (ML-DSA)
แนวทางแบบไฮบริดนี้ช่วยให้แอปของคุณยังคงปลอดภัยจากการโจมตีด้วยควอนตัมในอนาคต ขณะเดียวกันก็ยังคงความเข้ากันได้แบบย้อนหลังกับ Android เวอร์ชันเก่าและอุปกรณ์ที่ใช้การยืนยันลายเซ็นแบบคลาสสิกได้อย่างเต็มที่
ผลกระทบต่อนักพัฒนาแอป
- แอปที่ใช้ Play App Signing: หากคุณใช้ Play App Signing คุณสามารถรอให้ Google Play มีตัวเลือกให้อัปเกรดลายเซ็นแบบไฮบริดโดยใช้คีย์ PQC ที่สร้างโดย Google Play ซึ่งจะช่วยให้แอปได้รับการปกป้องโดยไม่จำเป็นต้องจัดการคีย์ด้วยตนเอง
- แอปที่ใช้คีย์ที่จัดการเอง: นักพัฒนาแอปที่จัดการคีย์การลงนามของตนเองสามารถใช้เครื่องมือสร้าง Android ที่อัปเดตแล้ว (เช่น apksigner) เพื่อเปลี่ยนไปใช้ข้อมูลประจำตัวแบบไฮบริด โดยรวมคีย์ PQC กับคีย์แบบคลาสสิกใหม่ (คุณต้องสร้างคีย์แบบคลาสสิกใหม่ โดยจะนำคีย์เก่ามาใช้ซ้ำไม่ได้)
การเชื่อมต่อ
Android 17 เพิ่มฟีเจอร์ต่อไปนี้เพื่อปรับปรุงการเชื่อมต่ออุปกรณ์และแอป
เครือข่ายดาวเทียมที่มีข้อจำกัด
Implements optimizations to enable apps to function effectively over low-bandwidth satellite networks.
ประสบการณ์ของผู้ใช้และ UI ของระบบ
Android 17 มีการเปลี่ยนแปลงต่อไปนี้เพื่อปรับปรุงประสบการณ์ของผู้ใช้
สตรีมระดับเสียงของ Assistant โดยเฉพาะ
Android 17 เปิดตัวสตรีมระดับเสียงของผู้ช่วยโดยเฉพาะสำหรับแอป Assistant
สำหรับการเล่นด้วย USAGE_ASSISTANT การเปลี่ยนแปลงนี้จะแยกเสียงของ Assistant
ออกจากสตรีมสื่อมาตรฐาน เพื่อให้ผู้ใช้ควบคุมระดับเสียงทั้ง 2 อย่างแยกกันได้
ซึ่งจะช่วยให้ทำสิ่งต่างๆ ได้ เช่น ปิดเสียงการเล่นสื่อในขณะที่ยังคงได้ยินคำตอบของ Assistant และในทางกลับกัน
แอป Assistant ที่มีสิทธิ์เข้าถึงโหมดเสียง MODE_ASSISTANT_CONVERSATION ใหม่จะช่วยปรับปรุงความสอดคล้องในการควบคุมระดับเสียงได้ดียิ่งขึ้น แอป Assistant สามารถใช้
โหมดนี้เพื่อบอกใบ้ให้ระบบทราบเกี่ยวกับเซสชัน Assistant ที่ใช้งานอยู่
เพื่อให้มั่นใจว่าสามารถควบคุมสตรีมของ Assistant ได้นอกUSAGE_ASSISTANTการเล่นที่ใช้งานอยู่หรือด้วยอุปกรณ์ต่อพ่วงบลูทูธที่เชื่อมต่อ
Handoff
Handoff เป็นฟีเจอร์และ API ใหม่ที่จะพร้อมใช้งานใน Android 17 ซึ่งนักพัฒนาแอป สามารถผสานรวมเพื่อมอบความต่อเนื่องข้ามอุปกรณ์ให้แก่ผู้ใช้ ซึ่งช่วยให้ผู้ใช้เริ่มกิจกรรมในแอปบนอุปกรณ์ Android เครื่องหนึ่งและเปลี่ยนไปใช้อุปกรณ์ Android อีกเครื่องหนึ่งได้ Handoff จะทำงานในเบื้องหลังของอุปกรณ์ผู้ใช้และแสดงกิจกรรมที่พร้อมใช้งานจากอุปกรณ์อื่นๆ ที่อยู่ใกล้เคียงของผู้ใช้ผ่านจุดแรกเข้าต่างๆ เช่น ตัวเรียกใช้และแถบงานในอุปกรณ์ที่รับ
แอปสามารถกำหนดให้ Handoff เปิดแอป Android แบบเนทีฟเดียวกันได้ หากมีการ ติดตั้งและพร้อมใช้งานในอุปกรณ์ที่รับ ในขั้นตอนการทำงานจากแอปหนึ่งไปยังอีกแอปหนึ่งนี้ ระบบจะทำ Deep Link ผู้ใช้ไปยังกิจกรรมที่กำหนด หรือจะเสนอการส่งต่อจากแอปไปยังเว็บเป็นตัวเลือกสำรองหรือติดตั้งใช้งานโดยตรงด้วยการส่งต่อ URL ก็ได้
การรองรับการส่งต่อจะได้รับการติดตั้งใช้งานตามกิจกรรม หากต้องการเปิดใช้ Handoff ให้เรียกใช้เมธอด
setHandoffEnabled()
สำหรับกิจกรรม คุณอาจต้องส่งข้อมูลเพิ่มเติมพร้อมกับการ
ส่งต่อเพื่อให้กิจกรรมที่สร้างขึ้นใหม่ในอุปกรณ์รับสามารถคืนค่า
สถานะที่เหมาะสมได้ ใช้แฮนเดิล
onHandoffActivityDataRequested()
เพื่อส่งคืนออบเจ็กต์
HandoffActivityData ซึ่ง
มีรายละเอียดที่ระบุวิธีที่แฮนเดิลควรจัดการและสร้างกิจกรรม
ใหม่ในอุปกรณ์ที่รับ
การอัปเดตแบบเรียลไทม์ - Semantic Color API
ใน Android 17 Live Update จะเปิดตัว Semantic Coloring API เพื่อ รองรับสีที่มีความหมายสากล
คลาสต่อไปนี้รองรับการระบายสีเชิงความหมาย
NotificationNotification.MetricNotification.ProgressStyle.PointNotification.ProgressStyle.Segment
เกมระบายสี
- สีเขียว: เกี่ยวข้องกับความปลอดภัย สีนี้ควรใช้ในกรณีที่ต้องการให้ผู้อื่นทราบว่าคุณอยู่ในสถานการณ์ที่ปลอดภัย
- สีส้ม: สำหรับ ระบุข้อควรระวังและทำเครื่องหมายอันตรายทางกายภาพ ควรใช้สีนี้ในกรณีที่ผู้ใช้ต้องให้ความสนใจกับการตั้งค่าการปกป้องที่ดีขึ้น
- สีแดง: โดยทั่วไปหมายถึงอันตราย หยุด ควรแสดงในกรณีที่ต้องการดึงดูดความสนใจของผู้คนอย่างเร่งด่วน
- สีน้ำเงิน: สีที่เป็นกลางสำหรับเนื้อหาที่ให้ข้อมูลและควรโดดเด่นจากเนื้อหาอื่นๆ
ตัวอย่างต่อไปนี้แสดงวิธีใช้รูปแบบเชิงความหมายกับข้อความในการแจ้งเตือน
val ssb = SpannableStringBuilder()
.append("Colors: ")
.append("NONE", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_UNSPECIFIED), 0)
.append(", ")
.append("INFO", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_INFO), 0)
.append(", ")
.append("SAFE", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_SAFE), 0)
.append(", ")
.append("CAUTION", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_CAUTION), 0)
.append(", ")
.append("DANGER", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_DANGER), 0)
Notification.Builder(context, channelId)
.setSmallIcon(R.drawable.ic_icon)
.setContentTitle("Hello World!")
.setContentText(ssb)
.setOngoing(true)
.setRequestPromotedOngoing(true)
UWB Downlink-TDoA API สำหรับ Android 17
Downlink Time Difference of Arrival (DL-TDoA) ranging lets a device determine its position relative to multiple anchors by measuring the relative arrival times of signals.
The following snippet demonstrates how to initialize the Ranging Manager, verify device capabilities, and start a DL-TDoA session:
Kotlin
class RangingApp {
fun initDlTdoa(context: Context) {
// Initialize the Ranging Manager
val rangingManager = context.getSystemService(RangingManager::class.java)
// Register for device capabilities
val capabilitiesCallback = object : RangingManager.RangingCapabilitiesCallback {
override fun onRangingCapabilities(capabilities: RangingCapabilities) {
// Make sure Dl-TDoA is supported before starting the session
if (capabilities.uwbCapabilities != null && capabilities.uwbCapabilities!!.isDlTdoaSupported) {
startDlTDoASession(context)
}
}
}
rangingManager.registerCapabilitiesCallback(Executors.newSingleThreadExecutor(), capabilitiesCallback)
}
fun startDlTDoASession(context: Context) {
// Initialize the Ranging Manager
val rangingManager = context.getSystemService(RangingManager::class.java)
// Create session and configure parameters
val executor = Executors.newSingleThreadExecutor()
val rangingSession = rangingManager.createRangingSession(executor, RangingSessionCallback())
val rangingRoundIndexes = byteArrayOf(0)
val config: ByteArray = byteArrayOf() // OOB config data
val params = DlTdoaRangingParams.createFromFiraConfigPacket(config, rangingRoundIndexes)
val rangingDevice = RangingDevice.Builder().build()
val rawTagDevice = RawRangingDevice.Builder()
.setRangingDevice(rangingDevice)
.setDlTdoaRangingParams(params)
.build()
val dtTagConfig = RawDtTagRangingConfig.Builder(rawTagDevice).build()
val preference = RangingPreference.Builder(DEVICE_ROLE_DT_TAG, dtTagConfig)
.setSessionConfig(SessionConfig.Builder().build())
.build()
// Start the ranging session
rangingSession.start(preference)
}
}
private class RangingSessionCallback : RangingSession.Callback {
override fun onDlTdoaResults(peer: RangingDevice, measurement: DlTdoaMeasurement) {
// Process measurement results here
}
}
Java
public class RangingApp {
public void initDlTdoa(Context context) {
// Initialize the Ranging Manager
RangingManager rangingManager = context.getSystemService(RangingManager.class);
// Register for device capabilities
RangingManager.CapabilitiesCallback capabilitiesCallback = new RangingManager.RangingCapabilitiesCallback() {
@Override
public void onRangingCapabilities(RangingCapabilities capabilities) {
// Make sure Dl-TDoA is supported before starting the session
if (capabilities.getUwbCapabilities() != null && capabilities.getUwbCapabilities().isDlTdoaSupported()) {
startDlTDoASession(context);
}
}
};
rangingManager.registerCapabilitiesCallback(Executors.newSingleThreadExecutor(), capabilitiesCallback);
}
public void startDlTDoASession(Context context) {
RangingManager rangingManager = context.getSystemService(RangingManager.class);
// Create session and configure parameters
Executor executor = Executors.newSingleThreadExecutor();
RangingSession rangingSession = rangingManager.createRangingSession(executor, new RangingSessionCallback());
byte[] rangingRoundIndexes = new byte[] {0};
byte[] config = new byte[0]; // OOB config data
DlTdoaRangingParams params = DlTdoaRangingParams.createFromFiraConfigPacket(config, rangingRoundIndexes);
RangingDevice rangingDevice = new RangingDevice.Builder().build();
RawRangingDevice rawTagDevice = new RawRangingDevice.Builder()
.setRangingDevice(rangingDevice)
.setDlTdoaRangingParams(params)
.build();
RawDtTagRangingConfig dtTagConfig = new RawDtTagRangingConfig.Builder(rawTagDevice).build();
RangingPreference preference = new RangingPreference.Builder(DEVICE_ROLE_DT_TAG, dtTagConfig)
.setSessionConfig(new SessionConfig.Builder().build())
.build();
// Start the ranging session
rangingSession.start(preference);
}
private static class RangingSessionCallback implements RangingSession.Callback {
@Override
public void onDlTdoaResults(RangingDevice peer, DlTdoaMeasurement measurement) {
// Process measurement results here
}
}
}
Out-of-Band (OOB) Configurations
The following snippet provides an example of DL-TDoA OOB configuration data for Wi-Fi and BLE:
Java
// Wifi Configuration
byte[] wifiConfig = {
(byte) 0xDD, (byte) 0x2D, (byte) 0x5A, (byte) 0x18, (byte) 0xFF, // Header
(byte) 0x5F, (byte) 0x19, // FiRa Sub-Element
(byte) 0x02, (byte) 0x00, // Profile ID
(byte) 0x06, (byte) 0x02, (byte) 0x20, (byte) 0x08, // MAC Address
(byte) 0x14, (byte) 0x01, (byte) 0x0C, // Preamble Index
(byte) 0x27, (byte) 0x02, (byte) 0x08, (byte) 0x07, // Vendor ID
(byte) 0x28, (byte) 0x06, (byte) 0xCA, (byte) 0xC8, (byte) 0xA6, (byte) 0xF7, (byte) 0x6F, (byte) 0x08, // Static STS IV
(byte) 0x08, (byte) 0x02, (byte) 0x60, (byte) 0x09, // Slot Duration
(byte) 0x1B, (byte) 0x01, (byte) 0x0A, // Slots per RR
(byte) 0x09, (byte) 0x04, (byte) 0xE8, (byte) 0x03, (byte) 0x00, (byte) 0x00, // Duration
(byte) 0x9F, (byte) 0x04, (byte) 0x67, (byte) 0x45, (byte) 0x23, (byte) 0x01 // Session ID
};
// BLE Configuration
byte[] bleConfig = {
(byte) 0x2D, (byte) 0x16, (byte) 0xF4, (byte) 0xFF, // Header
(byte) 0x5F, (byte) 0x19, // FiRa Sub-Element
(byte) 0x02, (byte) 0x00, // Profile ID
(byte) 0x06, (byte) 0x02, (byte) 0x20, (byte) 0x08, // MAC Address
(byte) 0x14, (byte) 0x01, (byte) 0x0C, // Preamble Index
(byte) 0x27, (byte) 0x02, (byte) 0x08, (byte) 0x07, // Vendor ID
(byte) 0x28, (byte) 0x06, (byte) 0xCA, (byte) 0xC8, (byte) 0xA6, (byte) 0xF7, (byte) 0x6F, (byte) 0x08, // Static STS IV
(byte) 0x08, (byte) 0x02, (byte) 0x60, (byte) 0x09, // Slot Duration
(byte) 0x1B, (byte) 0x01, (byte) 0x0A, // Slots per RR
(byte) 0x09, (byte) 0x04, (byte) 0xE8, (byte) 0x03, (byte) 0x00, (byte) 0x00, // Duration
(byte) 0x9F, (byte) 0x04, (byte) 0x67, (byte) 0x45, (byte) 0x23, (byte) 0x01 // Session ID
};
If you can't use an OOB configuration because it is missing, or if you need to
change default values that aren't in the OOB config, you can build parameters
with DlTdoaRangingParams.Builder as shown in the following snippet. You can use
these parameters in place of DlTdoaRangingParams.createFromFiraConfigPacket():
Kotlin
val dlTdoaParams = DlTdoaRangingParams.Builder(1)
.setComplexChannel(UwbComplexChannel.Builder()
.setChannel(9).setPreambleIndex(10).build())
.setDeviceAddress(deviceAddress)
.setSessionKeyInfo(byteArrayOf(0x01, 0x02, 0x03, 0x04))
.setRangingIntervalMillis(240)
.setSlotDuration(UwbRangingParams.DURATION_2_MS)
.setSlotsPerRangingRound(20)
.setRangingRoundIndexes(byteArrayOf(0x01, 0x05))
.build()
Java
DlTdoaRangingParams dlTdoaParams = new DlTdoaRangingParams.Builder(1)
.setComplexChannel(new UwbComplexChannel.Builder()
.setChannel(9).setPreambleIndex(10).build())
.setDeviceAddress(deviceAddress)
.setSessionKeyInfo(new byte[]{0x01, 0x02, 0x03, 0x04})
.setRangingIntervalMillis(240)
.setSlotDuration(UwbRangingParams.DURATION_2_MS)
.setSlotsPerRangingRound(20)
.setRangingRoundIndexes(new byte[]{0x01, 0x05})
.build();