ฟีเจอร์และ API

Android 17 มาพร้อมฟีเจอร์และ API ใหม่ๆ ที่ยอดเยี่ยมสำหรับนักพัฒนาแอป ส่วนต่อไปนี้ จะสรุปฟีเจอร์เหล่านี้เพื่อช่วยให้คุณเริ่มต้นใช้งาน API ที่เกี่ยวข้องได้

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

นอกจากนี้ คุณควรตรวจสอบส่วนที่การเปลี่ยนแปลงของแพลตฟอร์มอาจส่งผลต่อแอปด้วย ดูข้อมูลเพิ่มเติมได้ที่หน้าต่อไปนี้

ฟังก์ชันหลัก

Android 17 เพิ่มฟีเจอร์ใหม่ต่อไปนี้ที่เกี่ยวข้องกับฟังก์ชันหลักของ Android

ทริกเกอร์ ProfilingManager ใหม่

Android 17 adds several new system triggers to ProfilingManager to help you collect in-depth data to debug performance issues.

The new triggers are:

To understand how to set up the system trigger, see the documentation on trigger-based profiling and how to retrieve and analyze profiling data documentation.

Profiling trigger for app anomalies

Android 17 introduces an on-device anomaly detection service that monitors for resource-intensive behaviors and potential compatibility regressions. Integrated with ProfilingManager, this service allows your app to receive profiling artifacts triggered by specific system-detected events.

Use the TRIGGER_TYPE_ANOMALY trigger to detect system performance issues such as excessive binder calls and excessive memory usage. When an app breaches OS-defined memory limits, the anomaly trigger allows developers to receive app-specific heap dumps to help identify and fix memory issues. Additionally, for excessive binder spam, the anomaly trigger provides a stack sampling profile on binder transactions.

This API callback occurs prior to any system imposed enforcements. For example, it can help developers collect debug data before the app is terminated by the system for exceeding memory limits.

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 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 introduces a new variant of AlarmManager.setExactAndAllowWhileIdle that accepts an OnAlarmListener instead of a PendingIntent. This new callback-based mechanism is ideal for apps that currently rely on continuous wakelocks to perform periodic tasks, such as messaging apps maintaining socket connections.

ความเป็นส่วนตัว

Android 17 มีฟีเจอร์ใหม่ต่อไปนี้เพื่อปรับปรุงความเป็นส่วนตัวของผู้ใช้

การรองรับแพลตฟอร์มสำหรับ ClientHello ที่เข้ารหัส (ECH)

Android 17 introduces platform support for Encrypted Client Hello (ECH), a significant privacy enhancement for network communications. ECH is a TLS 1.3 extension that encrypts the Server Name Indication (SNI) during the initial TLS handshake. This encryption helps protect user privacy by making it more difficult for network intermediaries to identify the specific domain an app is connecting to.

The platform now includes the necessary APIs for networking libraries to implement ECH. This includes new capabilities in DnsResolver to query for HTTPS DNS records containing ECH configurations, and new methods in Conscrypt's SSLEngines and SSLSockets to enable ECH by passing in these configurations when connecting to a domain. Developers can configure ECH preferences, such as enabling it opportunistically or mandating its use, through the new <domainEncryption> element within the Network Security Configuration file, applicable globally or on a per-domain basis.

Popular networking libraries such as HttpEngine, WebView, and OkHttp are expected to integrate these platform APIs in future updates, making it easier for apps to adopt ECH and enhance user privacy.

For more information, see the Encrypted Client Hello documentation.

เครื่องมือเลือกรายชื่อติดต่อ 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 เพิ่มฟีเจอร์ต่อไปนี้เพื่อปรับปรุงการเชื่อมต่ออุปกรณ์และแอป

เครือข่ายดาวเทียมที่มีข้อจำกัด

ใช้การเพิ่มประสิทธิภาพเพื่อให้แอปทำงานได้อย่างมีประสิทธิภาพผ่านเครือข่ายดาวเทียมที่มีแบนด์วิดท์ต่ำ

ประสบการณ์ของผู้ใช้และ UI ของระบบ

Android 17 มีการเปลี่ยนแปลงต่อไปนี้เพื่อปรับปรุงประสบการณ์ของผู้ใช้

สตรีมระดับเสียงของ Assistant โดยเฉพาะ

Android 17 introduces a dedicated Assistant volume stream for Assistant apps, for playback with USAGE_ASSISTANT. This change decouples Assistant audio from the standard media stream, providing users with isolated control over both volumes. This enables scenarios such as muting media playback while maintaining audibility for Assistant responses, and the other way around.

Assistant apps with access to the new MODE_ASSISTANT_CONVERSATION audio mode can further improve the volume control consistency. Assistant apps can use this mode to provide a hint to the system about an active Assistant session, ensuring the Assistant stream can be controlled outside of the active USAGE_ASSISTANT playback or with connected Bluetooth peripherals.

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 เพื่อ รองรับสีที่มีความหมายสากล

คลาสต่อไปนี้รองรับการระบายสีเชิงความหมาย

เกมระบายสี

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

ตัวอย่างต่อไปนี้แสดงวิธีใช้รูปแบบเชิงความหมายกับข้อความในการแจ้งเตือน

  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)

ตัวอย่างข้อมูลต่อไปนี้แสดงข้อมูลการกำหนดค่า DL-TDoA OOB สำหรับ 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();