ویژگی‌ها و میاناهای برنامه‌سازی کاربردی

‫Android 17 ویژگی‌ها و میاناهای برنامه‌سازی کاربردی جدید و فوق‌العاده‌ای را برای توسعه‌دهندگان معرفی می‌کند. بخش‌های زیر این ویژگی‌ها را خلاصه می‌کند تا به شما کمک کند با میاناهای برنامه‌سازی کاربردی مرتبط شروع کنید.

برای مشاهده فهرست دقیق میاناهای برنامه‌سازی کاربردی جدید، اصلاح‌شده، و حذف‌شده، گزارش تفاوت میانای برنامه‌سازی کاربردی را بخوانید. برای جزئیات درباره میاناهای برنامه‌سازی کاربردی جدید، به مرجع میانای برنامه‌سازی کاربردی Android مراجعه کنید — میاناهای برنامه‌سازی کاربردی جدید برای دید بهتر برجسته شده‌اند.

همچنین باید بخش‌هایی را که تغییرات پلاتفرم ممکن است بر برنامه‌هایتان تأثیر بگذارد مرور کنید. برای اطلاعات بیشتر، صفحه‌های زیر را ببینید:

عملکرد اصلی

‫Android 17 ویژگی‌های جدید زیر را دررابطه‌با عملکرد اصلی Android اضافه می‌کند.

راه‌اندازهای جدید ProfilingManager

Android 17 向 ProfilingManager 添加了多个新的系统触发器,可帮助您收集深入的数据来调试性能问题。

新触发条件包括:

如需了解如何设置系统触发器,请参阅有关基于触发器的性能分析以及如何检索和上传配置文件和分析性能分析数据的文档。

应用异常性能分析触发器

Android 17 引入了设备端异常值检测服务,用于监控资源密集型行为和潜在的兼容性回归。此服务与 ProfilingManager 集成,可让您的应用接收由系统检测到的特定事件触发的性能分析工件。

使用 TRIGGER_TYPE_ANOMALY 触发器检测系统性能问题,例如 Binder 调用过多和内存用量过多。当应用超出操作系统定义的内存限制时,异常触发器可让开发者接收应用专属堆转储,以帮助识别和修复内存问题。此外,对于过多的 binder 垃圾内容,异常触发器会提供 binder 事务的堆栈采样分析。

此 API 回调会在系统强制执行任何操作之前发生。例如,它可以帮助开发者在应用因超出内存限制而被系统终止之前收集调试数据。

fun registerAnomalyTrigger(context: Context) {
    val profilingManager =
        context.getSystemService(ProfilingManager::class.java) ?: return
    val triggers = listOf(
        ProfilingTrigger.Builder(ProfilingTrigger.TRIGGER_TYPE_ANOMALY).build()
    )
    val callbackExecutor: Executor = Executors.newSingleThreadExecutor()
    val resultCallback = Consumer<ProfilingResult> { profilingResult ->
        if (profilingResult.errorCode == ProfilingResult.ERROR_NONE) {
            // Upload profile result to server for further analysis
            profilingResult.resultFilePath?.let { setupProfileUploadWorker(it) }
        }
    }
    profilingManager.registerForAllProfilingResults(
        callbackExecutor,
        resultCallback
    )
    profilingManager.addProfilingTriggers(triggers)
}

JobDebugInfo APIs

Android 17 引入了新的 JobDebugInfo API,可帮助开发者调试其 JobScheduler 作业,例如作业未运行的原因、作业运行了多长时间以及其他聚合信息。

扩展后的 JobDebugInfo API 的第一个方法是 getPendingJobReasonStats(),它会返回一个映射,其中包含作业处于待执行状态的原因及其各自的累计待处理时长。此方法结合了 getPendingJobReasonsHistory() 和 getPendingJobReasons() 方法,可让您深入了解预定作业未按预期运行的原因,但通过在单个方法中提供时长和作业原因,简化了信息检索。

例如,对于指定的 jobId,该方法可能会返回 PENDING_JOB_REASON_CONSTRAINT_CHARGING 和 60000 毫秒的时长,表示由于充电限制未得到满足,作业处于待处理状态的时长为 60000 毫秒。

کاهش قفل‌های بیداری با پشتیبانی شنونده برای هشدارهای «مجاز درحالت بیکار»

Android 17 引入了 AlarmManager.setExactAndAllowWhileIdle 的新变体,该变体接受 OnAlarmListener 而不是 PendingIntent。这种基于回调的新机制非常适合目前依赖持续唤醒锁来执行周期性任务的应用,例如维护套接字连接的即时通讯应用。

حریم خصوصی

‫Android 17 شامل ویژگی‌های جدید زیر برای بهبود حریم خصوصی کاربر است.

پشتیبانی پلاتفرم از Encrypted Client Hello (ECH)

اندروید ۱۷ پشتیبانی پلتفرم از Encrypted Client Hello (ECH) را معرفی می‌کند، که یک بهبود قابل توجه در حریم خصوصی ارتباطات شبکه است. ECH یک افزونه TLS 1.3 است که نشانگر نام سرور (SNI) را در طول اولین اتصال TLS رمزگذاری می‌کند. این رمزگذاری با دشوارتر کردن شناسایی دامنه خاصی که یک برنامه به آن متصل می‌شود، برای واسطه‌های شبکه، به محافظت از حریم خصوصی کاربر کمک می‌کند.

این پلتفرم اکنون شامل APIهای لازم برای کتابخانه‌های شبکه برای پیاده‌سازی ECH است. این شامل قابلیت‌های جدید در DnsResolver برای جستجوی رکوردهای HTTPS DNS حاوی پیکربندی‌های ECH و روش‌های جدید در SSLEngines و SSLSockets متعلق به Conscrypt برای فعال کردن ECH با ارسال این پیکربندی‌ها هنگام اتصال به یک دامنه است. توسعه‌دهندگان می‌توانند تنظیمات ECH، مانند فعال کردن آن به صورت فرصت‌طلبانه یا اجباری کردن استفاده از آن را از طریق عنصر جدید <domainEncryption> در فایل پیکربندی امنیت شبکه، که به صورت جهانی یا بر اساس هر دامنه قابل اجرا است، پیکربندی کنند.

انتظار می‌رود کتابخانه‌های شبکه محبوب مانند HttpEngine، WebView و OkHttp این APIهای پلتفرم را در به‌روزرسانی‌های آینده ادغام کنند و پذیرش ECH و افزایش حریم خصوصی کاربران را برای برنامه‌ها آسان‌تر کنند.

برای اطلاعات بیشتر، به مستندات Encrypted Client Hello مراجعه کنید.

انتخاب‌گر مخاطبین Android

«انتخابگر مخاطب Android» واسطی استانداردشده و قابل‌مرور است که کاربران می‌توانند ازطریق آن مخاطبین را با برنامه شما هم‌رسانی کنند. این انتخابگر که در دستگاه‌های دارای Android 17 (سطح میانای برنامه‌سازی کاربردی 37) یا بالاتر دردسترس است، جایگزینی حافظ حریم خصوصی برای اجازه گسترده READ_CONTACTS ارائه می‌دهد. به‌جای درخواست دسترسی به کل دفترچه تلفن کاربر، برنامه‌تان فیلدهای داده موردنیازش را مشخص می‌کند (مثلاً شماره تلفن یا نشانی ایمیل) و کاربر مخاطبین خاصی را برای هم‌رسانی انتخاب می‌کند. این کار به برنامه شما اجازه خواندن فقط داده‌های انتخاب‌شده را می‌دهد، کنترل جزئی را تضمین می‌کند و درعین‌حال تجربه کاربری ثابتی را با قابلیت‌های جستجوی داخلی، تعویض نمایه، و چندانتخابی بدون نیاز به ساختن یا نگهداری واسط کاربر ارائه می‌دهد.

برای اطلاعات بیشتر، اسناد انتخابگر مخاطب را ببینید.

امنیت

Android 17 ویژگی‌های جدید زیر را برای بهبود امنیت دستگاه و برنامه اضافه می‌کند.

حالت محافظت پیشرفته Android (AAPM)

حالت حفاظت پیشرفته اندروید (Android Advanced Protection Mode) مجموعه‌ای قدرتمند و جدید از ویژگی‌های امنیتی را در اختیار کاربران اندروید قرار می‌دهد که گامی مهم در جهت محافظت از کاربران - به‌ویژه کاربران در معرض خطر بیشتر - در برابر حملات پیچیده است. AAPM که به عنوان یک ویژگی اختیاری طراحی شده است، با یک تنظیم پیکربندی واحد فعال می‌شود که کاربران می‌توانند در هر زمان آن را فعال کنند تا مجموعه‌ای از حفاظت‌های امنیتی دلخواه را اعمال کنند.

این تنظیمات اصلی شامل مسدود کردن نصب برنامه‌ها از منابع ناشناخته (سایدلودینگ)، محدود کردن سیگنال‌دهی داده‌های USB و اجباری کردن اسکن Google Play Protect است که به طور قابل توجهی سطح حمله دستگاه را کاهش می‌دهد. توسعه‌دهندگان می‌توانند با استفاده از AdvancedProtectionManager API با این ویژگی ادغام شوند تا وضعیت حالت را تشخیص دهند و برنامه‌ها را قادر سازند تا به طور خودکار یک وضعیت امنیتی سخت‌گیرانه را اتخاذ کنند یا عملکردهای پرخطر را هنگامی که کاربر انتخاب کرده است، محدود کنند.

امضای APK با PQC

Android اکنون از طرح امضای APK ترکیبی پشتیبانی می‌کند تا هویت امضای برنامه‌تان را در آینده دربرابر تهدید احتمالی حملاتی که از محاسبات کوانتومی استفاده می‌کنند مقاوم کند. این ویژگی «طرح امضای APK» جدیدی را معرفی می‌کند که به شما امکان می‌دهد کلید امضای کلاسیک (مثل RSA یا EC) را با الگوریتم جدید رمزنگاری پساکوانتومی (PQC) (ML-DSA) جفت کنید.

این رویکرد ترکیبی تضمین می‌کند که برنامه شما دربرابر حملات کوانتومی آینده ایمن بماند و درعین‌حال سازگاری کامل با نسخه‌های قدیمی‌تر Android و دستگاه‌هایی که به درستی‌سنجی امضای کلاسیک متکی هستند حفظ شود.

تأثیر بر توسعه‌دهندگان

  • برنامه‌هایی که از «امضای برنامه» Play استفاده می‌کنند: اگر از «امضای برنامه» Play استفاده می‌کنید، می‌توانید منتظر بمانید تا Google Play گزینه ارتقا به امضای ترکیبی بااستفاده از کلید «رمزنگاری پسا کوانتومی» تولیدشده توسط Google Play را به شما ارائه دهد. این کار تضمین می‌کند که برنامه‌تان بدون نیاز به مدیریت دستی کلید محافظت می‌شود.
  • برنامه‌هایی که از کلیدهای خودمدیریتی استفاده می‌کنند: توسعه‌دهندگانی که کلیدهای امضای خودشان را مدیریت می‌کنند می‌توانند از ابزارهای به‌روزشده ساخت Android (مانند apksigner) برای چرخش به هویت ترکیبی استفاده کنند که کلید «رمزنگاری پسا کوانتومی» را با کلید کلاسیک جدید ترکیب می‌کند. (باید کلید کلاسیک جدیدی ایجاد کنید، نمی‌توانید از کلید قدیمی‌تر دوباره استفاده کنید.)

اتصال‌پذیری

Android 17 ویژگی‌های زیر را برای بهبود اتصال‌پذیری دستگاه و برنامه اضافه می‌کند.

شبکه‌های ماهواره‌ای محدودشده

实现优化,使应用能够在低带宽卫星网络上有效运行。

تجربه کاربری و واسط کاربر سیستم

Android 17 شامل تغییرات زیر برای بهبود تجربه کاربری است.

جاری‌سازی اختصاصی میزان صدای «دستیار»

Android 17 یک جریان اختصاصی میزان صدای «دستیار» برای برنامه‌های «دستیار» معرفی می‌کند، برای بازپخش با USAGE_ASSISTANT. این تغییر صدای «دستیار» را از جاری‌سازی رسانه استاندارد جدا می‌کند و به کاربران امکان می‌دهد هریک از این صداها را به‌طور جداگانه کنترل کنند. این کار سناریوهایی مانند بی‌صدا کردن بازپخش رسانه را درحین حفظ شنیداری برای پاسخ‌های «دستیار» و برعکس فعال می‌کند.

برنامه‌های «دستیار» که به حالت صوتی جدید MODE_ASSISTANT_CONVERSATION دسترسی دارند می‌توانند ثبات کنترل میزان صدا را بیشتر بهبود بخشند. برنامه‌های «دستیار» می‌توانند از این حالت برای ارائه راهنمایی به سیستم درباره جلسه فعال «دستیار» استفاده کنند، و مطمئن شوند که جریان «دستیار» می‌تواند خارج از بازپخش فعال USAGE_ASSISTANT یا با لوازم جانبی بلوتوث متصل کنترل شود.

Handoff

«انتقال» ویژگی و میانای برنامه‌سازی کاربردی جدیدی است که در Android 17 ارائه می‌شود و توسعه‌دهندگان نرم‌افزار می‌توانند آن را ادغام کنند تا تداوم بین‌دستگاهی را برای کاربرانشان فراهم کنند. این ویژگی به کاربر اجازه می‌دهد فعالیت برنامه را در یک دستگاه Android شروع کند و آن را به دستگاه Android دیگری منتقل کند. Handoff در پس‌زمینه دستگاه کاربر اجرا می‌شود و فعالیت‌های دردسترس را از دیگر دستگاه‌های اطراف کاربر ازطریق نقاط ورودی مختلف، مانند راه‌انداز و نوار وظیفه، در دستگاه گیرنده نمایش می‌دهد.

برنامه‌ها می‌توانند «انتقال» را برای راه‌اندازی همان برنامه Android بومی تعیین کنند، اگر در دستگاه گیرنده نصب شده و دردسترس باشد. در این جریان برنامه به برنامه، کاربر به فعالیت تعیین‌شده پیوند عمیق می‌شود. یا اینکه «انتقال برنامه به وب» می‌تواند به‌عنوان گزینه جایگزین ارائه شود یا مستقیماً با «انتقال نشانی وب» پیاده‌سازی شود.

پشتیبانی از «چنددستگاهی» براساس هر فعالیت پیاده‌سازی می‌شود. برای فعال کردن Handoff، روش setHandoffEnabled() را برای فعالیت فراخوانی کنید. ممکن است لازم باشد داده‌های اضافی همراه با انتقال ارسال شود تا فعالیت بازآفرینی‌شده در دستگاه گیرنده بتواند وضعیت مناسب را بازیابی کند. فراخوانی برگشتی onHandoffActivityDataRequested() را پیاده‌سازی کنید تا شیء HandoffActivityData برگردانده شود که حاوی جزئیاتی است که مشخص می‌کند «انتقال» چگونه باید فعالیت را در دستگاه گیرنده مدیریت و بازآفرینی کند.

Live Update - Semantic color API

在 Android 17 中,实时动态推出了语义着色 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) به دستگاه امکان می‌دهد موقعیت خود را نسبت به چندین لنگر با اندازه‌گیری زمان رسیدن نسبی سیگنال‌ها تعیین کند.

قطعه کد زیر نحوه مقداردهی اولیه مدیر فاصله‌یابی، درستی‌سنجی قابلیت‌های دستگاه، و شروع جلسه DL-TDoA را نشان می‌دهد:

کاتلین

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
    }
}

جاوا

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
        }
    }
}

پیکربندی‌های خارج‌از باند (OOB)

تکه‌کد زیر نمونه‌ای از داده‌های پیکربندی DL-TDoA OOB برای Wi-Fi و BLE ارائه می‌دهد:

جاوا

// 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() استفاده کنید:

کاتلین

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()

جاوا

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();