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
การเรียกกลับของ 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)
}
JobDebugInfo APIs
Android 17 introduces new JobDebugInfo APIs to help developers debug
their JobScheduler jobs--why they aren't running, how long they ran for, and
other aggregated information.
The first method of the expanded JobDebugInfo APIs is
getPendingJobReasonStats(), which returns a map of reasons why the job was in
a pending execution state and their respective cumulative pending
durations. This method joins the getPendingJobReasonsHistory() and
getPendingJobReasons() methods to give you insight into why a scheduled
job is not running as expected, but simplifies information retrieval by making
both duration and job reason available in a single method.
For example, for a specified jobId, the method might return
PENDING_JOB_REASON_CONSTRAINT_CHARGING and a duration of 60000 ms, indicating
the job was pending for 60000ms due to the charging constraint not being
satisfied.
ลด Wake Lock ด้วยการรองรับ Listener สำหรับการอนุญาตขณะที่ไม่ได้ใช้งาน
Android 17 引入了 AlarmManager.setExactAndAllowWhileIdle 的新变体,该变体接受 OnAlarmListener 而不是 PendingIntent。这种基于回调的新机制非常适合目前依赖于持续唤醒锁来执行周期性任务的应用,例如维护套接字连接的即时通讯应用。
ความเป็นส่วนตัว
Android 17 มาพร้อมฟีเจอร์ใหม่ต่อไปนี้เพื่อปรับปรุงความเป็นส่วนตัวของผู้ใช้
การรองรับแพลตฟอร์มสำหรับ Encrypted Client Hello (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
The Android Contact Picker is a standardized, browsable interface for users to
share contacts with your app. Available on devices running
Android 17 (API level 37) or higher, the picker offers a privacy-preserving
alternative to the broad READ_CONTACTS permission. Instead of requesting
access to the user's entire address book, your app specifies the data fields it
needs, such as phone numbers or email addresses, and the user selects specific
contacts to share. This grants your app read access to only the selected data,
ensuring granular control while providing a consistent user experience with
built-in search, profile switching, and multi-selection capabilities without
having to build or maintain the UI.
For more information, see the contact picker documentation.
ความปลอดภัย
Android 17 มาพร้อมฟีเจอร์ใหม่ต่อไปนี้เพื่อปรับปรุงความปลอดภัยของอุปกรณ์และแอป
โหมดการปกป้องขั้นสูงของ Android (AAPM)
Android 高级保护模式为 Android 用户提供了一套强大的新安全功能,标志着在保护用户(尤其是面临较高风险的用户)免遭复杂攻击方面迈出了重要一步。AAPM 是一项选择启用功能,只需进行一项配置设置即可激活。用户可以随时启用该功能,以应用一套主观的安全保护措施。
这些核心配置包括:禁止安装未知来源的应用(旁加载)、限制 USB 数据信号传输,以及强制执行 Google Play 保护机制扫描,从而显著减小设备的攻击面。
开发者可以使用 AdvancedProtectionManager API 与此功能集成,以检测模式的状态,从而使应用能够在用户选择启用此模式时自动采用强化型安全姿态或限制高风险功能。
การทำ 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 มาพร้อมฟีเจอร์ต่อไปนี้เพื่อปรับปรุงการเชื่อมต่ออุปกรณ์และแอป
เครือข่ายดาวเทียมที่มีข้อจำกัด
ใช้การเพิ่มประสิทธิภาพเพื่อให้แอปทำงานได้อย่างมีประสิทธิภาพผ่านเครือข่ายดาวเทียมที่มีแบนด์วิดท์ต่ำ
ประสบการณ์ของผู้ใช้และ UI ของระบบ
Android 17 มีการเปลี่ยนแปลงต่อไปนี้เพื่อปรับปรุงประสบการณ์ของผู้ใช้
สตรีมเสียงผู้ช่วยโดยเฉพาะ
Android 17 เปิดตัวสตรีมเสียงผู้ช่วยโดยเฉพาะสำหรับแอป Assistant
สำหรับการเล่นด้วย USAGE_ASSISTANT การเปลี่ยนแปลงนี้จะแยกเสียงของผู้ช่วย
ออกจากสตรีมสื่อมาตรฐาน ทำให้ผู้ใช้ควบคุมระดับเสียงทั้ง 2 อย่างแยกกันได้
ซึ่งจะช่วยให้ทำสิ่งต่างๆ ได้ เช่น ปิดเสียงการเล่นสื่อในขณะที่ยังคงได้ยินคำตอบของ Assistant และในทางกลับกัน
แอป Assistant ที่มีสิทธิ์เข้าถึงโหมดเสียง MODE_ASSISTANT_CONVERSATION ใหม่
จะช่วยปรับปรุงความสอดคล้องในการควบคุมระดับเสียงได้ แอป Assistant สามารถใช้โหมดนี้เพื่อบอกใบ้ให้ระบบทราบเกี่ยวกับเซสชัน Assistant ที่ใช้งานอยู่
เพื่อให้มั่นใจว่าสามารถควบคุมสตรีม Assistant ได้นอกUSAGE_ASSISTANTการเล่นที่ใช้งานอยู่หรือด้วยอุปกรณ์ต่อพ่วงบลูทูธที่เชื่อมต่อ
Handoff
Handoff is a new feature and API coming to Android 17 that app developers can integrate with to provide cross-device continuity for their users. It allows the user to start an app activity on one Android device and transition it to another Android device. Handoff runs in the background of a user's device and surfaces available activities from the user's other nearby devices through various entry points, like the launcher and taskbar, on the receiving device.
Apps can designate Handoff to launch the same native Android app, if it is installed and available on the receiving device. In this app-to-app flow, the user is deep-linked to the designated activity. Alternatively, app-to-web Handoff can be offered as a fallback option or directly implemented with URL Handoff.
Handoff support is implemented on a per-activity basis. To enable Handoff, call
the
setHandoffEnabled()
method for the activity. Additional data may need to be passed along with the
handoff so the recreated activity on the receiving device can restore
appropriate state. Implement the
onHandoffActivityDataRequested()
callback to return a
HandoffActivityData object which
contains details that specify how Handoff should handle and recreate the
activity on the receiving device.
การอัปเดตแบบเรียลไทม์ - 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
การวัดระยะด้วยความแตกต่างของเวลาที่มาถึงของลิงก์ดาวน์ (DL-TDoA) ช่วยให้อุปกรณ์ระบุ ตำแหน่งของตนเองที่สัมพันธ์กับจุดยึดหลายจุดได้โดยการวัดเวลาที่สัญญาณมาถึง ที่สัมพันธ์กันข้อมูลโค้ดต่อไปนี้แสดงวิธีเริ่มต้นRanging Manager, ยืนยันความสามารถของอุปกรณ์ และเริ่มเซสชัน DL-TDoA
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)
ข้อมูลต่อไปนี้แสดงตัวอย่างข้อมูลการกำหนดค่า OOB ของ DL-TDoA สำหรับ Wi-Fi และ 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
};
หากใช้การกำหนดค่า OOB ไม่ได้เนื่องจากไม่มี หรือหากต้องการเปลี่ยนค่าเริ่มต้นที่ไม่ได้อยู่ในกำหนดค่า OOB คุณสามารถสร้างพารามิเตอร์ด้วย DlTdoaRangingParams.Builder ตามที่แสดงในข้อมูลโค้ดต่อไปนี้ คุณใช้พารามิเตอร์เหล่านี้แทน 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();