النطاق بين الأجهزة

يقدّم نظام التشغيل Android 16 وحدة Ranging التي توفّر واجهة موحّدة ومعيارية لتحديد المسافة بدقة بين الأجهزة. يمكنك استخدام واجهة برمجة التطبيقات هذه لقياس المسافة والموضع بين الأجهزة المتجاورة بدون الحاجة إلى التعامل مع كل تقنية تحديد مدى على حدة.

يتوافق "وحدة تحديد المدى" مع التقنيات التالية:

إمكانات تحديد النطاق ومدى التوفّر

توفّر الفئة RangingManager للتطبيقات معلومات حول تكنولوجيات تحديد المدى المتوافقة مع الجهاز المحلي، بالإضافة إلى مدى توفّر كل تكنولوجيا وإمكاناتها. يمكن للتطبيقات التسجيل للحصول على Callback لتلقّي إشعارات بشأن أي تغييرات في مدى توفّر أي تقنيات متوافقة أو إمكاناتها.

أدوار الأجهزة

يجب أن يكون الجهاز المشارك في جلسة تحديد المدى إما مُطلقًا أو مستجيبًا. يبدأ الجهاز المبادِر جلسة تحديد المدى مع جهاز واحد أو أكثر من الأجهزة المستجيبة. يستجيب الجهاز المستجيب لطلبات تحديد المدى من جهاز مبادر واحد فقط في كل مرة. يمكنك تحديد دور لجهاز معيّن في جلسة تحديد المدى باستخدام الفئة RangingPreference.

أنواع الجلسات التي تتضمّن نطاقات

عند بدء جلسة تحديد مدى بين الأجهزة، من الضروري غالبًا إنشاء قناة نقل بيانات خارج النطاق (OOB) لتبادل المَعلمات الخاصة بالجلسة.

يمكن لوحدة Ranging التعامل مع عمليات التفاوض خارج النطاق نيابةً عنك، ولكنّها تتيح أيضًا عمليات تنفيذ مخصّصة خارج النطاق.

الشكل 1. مسار OOB لأنواع الجلسات

التنفيذ التلقائي لتجربة OOB

في نوع الجلسة هذا (RANGING_SESSION_OOB)، تتولّى وحدة Ranging معالجة عمليات التفاوض خارج النطاق لبدء جلسة تحديد المدى. يختار الجهاز معلَمات مناسبة استنادًا إلى إعدادات النطاق المفضّلة التي يوفّرها التطبيق، ويستخدم التقنيات المناسبة استنادًا إلى ما يتوافق معه كلا الجهازين. يستخدم نوع الجلسة هذا OOB specification موحّدًا.

لا تحدّد وحدة Ranging سوى تنسيق بيانات النطاق خارج النطاق وتسلسله المطلوب استخدامهما للتفاعل مع جهاز آخر. ولا يتعامل مع عملية اكتشاف الأجهزة المجاورة أو إنشاء اتصال بها.

تنفيذ مخصّص لتجربة استخدام المنتج خارج الصندوق

في نوع الجلسة هذا (RANGING_SESSION_RAW)، يتجاوز التطبيق مسار OOB الخاص بوحدة Ranging ويتعامل مع عملية التفاوض بشأن OOB ومعامِلاته. وهذا يعني أنّ التطبيق يجب أن يحدّد التقنيات التي يتيحها الجهاز المجاور، وأن يتفاوض على معلَمات تحديد المدى، وأن يبدأ جلسة تحديد المدى.

إعدادات النطاق المفضَّلة

استخدِم عنصر RangingPreference لتحديد المَعلمات المحدّدة لجلسة تحديد المدى. ويتضمن ذلك ما يلي:

  • دور الجهاز: يشير هذا الإعداد إلى ما إذا كان الجهاز سيُستخدم كجهاز بدء أو كجهاز استجابة.
  • إعدادات تحديد المدى يحدّد عنصر RangingConfig نوع جلسة تحديد المدى والمعلمات الأخرى اللازمة لبدء جلسة تحديد المدى.
  • إعدادات الجلسة: يحدّد عنصر SessionConfig المَعلمات التي سيتم فرضها على جلسة تحديد المدى، مثل حد القياس ودمج البيانات الحسية وإعدادات السياج الجغرافي وغير ذلك.

إذن تحديد النطاق

تتطلّب وحدة Ranging إذنًا موحّدًا جديدًا (android.permission.RANGING) للوصول إلى جميع تقنيات تحديد المدى الحالية والمستقبلية. يتوفّر هذا الإذن في قائمة NEARBY_DEVICES_PERMISSIONS.

<uses-permission android:name="android.permission.RANGING" />

القيود والأحكام

قد يفرض وحدة &quot;تحديد المدى&quot; قيودًا على تحديد المدى لعدة أسباب، بما في ذلك ما يلي:

  • يُسمح للتطبيقات التابعة لجهات خارجية بإجراء تحديد المدى في الخلفية باستخدام النطاق الفائق العرض فقط، وعلى الأجهزة المتوافقة فقط. لا يُسمح باستخدامها في الخلفية مع تقنيات أخرى.
  • لا يُسمح بتحديد المدى عندما يتم الوصول إلى الحد الأقصى لعدد جلسات تحديد المدى المتزامنة لكل جهاز.
  • قد يتم حظر تحديد المدى بسبب مشاكل في سلامة النظام، مثل البطارية أو الأداء أو الذاكرة.

تتضمّن وحدة Ranging أيضًا القيود المعروفة التالية:

  • لا يتيح "وحدة تحديد المدى" سوى إرسال بيانات تحديد المدى إلى الأجهزة المجاورة عبر الناطق الواسع جدًا. بالنسبة إلى التقنيات الأخرى، لا يقدّم وحدة Ranging سوى بيانات تحديد المدى إلى الجهاز البادئ.
  • لا تتيح وحدة "تحديد المدى" إضافة الأجهزة بشكل ديناميكي إلا في وضع تحديد المدى الأولي، وذلك فقط بالنسبة إلى النطاق الفائق العرض.
  • لا تتوافق وحدة Ranging مع جلسات النطاق الفائق العرض المتعددة إلى واحد في عمليات التنفيذ التلقائية لوظيفة OOB. إذا مرّرت عدة معرّفات للأجهزة، ينشئ التطبيق جلسة فردية لكل جهاز من الأجهزة المتصلة التي تتوافق مع النطاق الفائق العرض.

إجراء جلسة تحديد المدى

لإجراء جلسة تحديد المدى باستخدام وحدة Ranging، اتّبِع الخطوات التالية:

  1. تأكَّد من أنّ جميع الأجهزة تعمل بالإصدار 16 من نظام التشغيل Android أو إصدار أحدث.
  2. اطلب android.permission.RANGING الإذن في ملف بيان التطبيق.
  3. تقييم إمكانات تكنولوجيات تحديد المدى ومدى توفّرها
  4. اكتشاف جهاز مجاور لإجراء عمليات تحديد المدى
  5. إنشاء اتصال لتبادل البيانات خارج النطاق باستخدام أحد نوعَي الجلسات الموضّحَين في أنواع جلسات تحديد المدى
  6. ابدأ عملية تحديد المدى واكتسب بيانات تحديد المدى بشكل مستمر.
  7. إنهاء جلسة تحديد المدى

يوضّح نموذج الرمز التالي هذه الخطوات لكل من دور المبدئ ودور المستجيب.

Kotlin

class RangingApp {

    // Starts a ranging session on the initiator side.
    fun startRangingInitiator(
        context: Context,
        deviceHandle: DeviceHandle,
        executor: Executor,
        callback: RangingSessionCallback
    ) {

        // Get the RangingManager which is the entry point for ranging module.
        val manager = context.getSystemService(RangingManager::class.java)

        // Create a new RangingSession using the provided executor and callback.
        val session = manager.createRangingSession(executor, callback)

        // Create an OobInitiatorRangingConfig, which specifies the ranging parameters for
        // the initiator role.
        val config = OobInitiatorRangingConfig.Builder()
            .setFastestRangingInterval(Duration.ofMillis(100))
            .setSlowestRangingInterval(Duration.ofMillis(5000))
            .setRangingMode(RANGING_MODE_AUTO)
            .setSecurityLevel(SECURITY_LEVEL_BASIC)
            .addDeviceHandle(deviceHandle)
            .build()

        // Create a RangingPreference, which specifies the role (initiator) and
        // configuration for the ranging session.
        val preference =
            RangingPreference.Builder(DEVICE_ROLE_INITIATOR, config).build()

        // Start ranging session.
        session.start(preference)

        // If successful, the ranging data will be sent through callback#onResults

        // Stop ranging session
        session.stop()
    }

    // Starts a ranging session on the responder side.
    fun startRangingResponder(
        context: Context,
        deviceHandle: DeviceHandle,
        executor: Executor,
        callback: RangingSessionCallback
    ) {

        // Get the RangingManager which is the entry point for ranging module.
        val manager = context.getSystemService(RangingManager::class.java)

        // Create a new RangingSession using the provided executor and callback.
        val session = manager.createRangingSession(executor, callback)

        // Create an OobResponderRangingConfig, which specifies the ranging parameters for
        // the responder role.
        val config = OobResponderRangingConfig.Builder(deviceHandle).build()

        // Create a RangingPreference, which specifies the role (responder) and
        // configuration for the ranging session.
        val preference =
            RangingPreference.Builder(DEVICE_ROLE_RESPONDER, config).build()

        // Start the ranging session.
        session.start(preference)

        // Stop the ranging session
        session.stop()
    }
}

Java

public class RangingApp {

    // Starts a ranging session on the initiator side.
    void startRangingInitiator(Context context, DeviceHandle deviceHandle, Executor executor, RangingSessionCallback callback) {

        // Get the RangingManager which is the entry point for ranging module.
        RangingManager manager = context.getSystemService(RangingManager.class);

        // Create a new RangingSession using the provided executor and callback.
        RangingSession session = manager.createRangingSession(executor, callback);

        // Create an OobInitiatorRangingConfig, which specifies the ranging parameters for
        // the initiator role.
        OobInitiatorRangingConfig config = new OobInitiatorRangingConfig.Builder()
                .setFastestRangingInterval(Duration.ofMillis(100))
                .setSlowestRangingInterval(Duration.ofMillis(5000))
                .setRangingMode(RANGING_MODE_AUTO)
                .setSecurityLevel(SECURITY_LEVEL_BASIC)
                .addDeviceHandle(deviceHandle)
                .build();

        // Create a RangingPreference, which specifies the role (initiator) and
        // configuration for the ranging session.
        RangingPreference preference =
                new RangingPreference.Builder(DEVICE_ROLE_INITIATOR, config).build();

        // Start ranging session.
        session.start(preference);

        // If successful, the ranging data will be sent through callback#onResults

        // Stop ranging session
        session.stop();

    }

    // Starts a ranging session on the responder side.
    void startRangingResponder(Context context,  DeviceHandle deviceHandle, Executor executor, RangingSessionCallback callback) {

        // Get the RangingManager which is the entry point for ranging module.
        RangingManager manager = context.getSystemService(RangingManager.class);

        // Create a new RangingSession using the provided executor and callback.
        RangingSession session = manager.createRangingSession(executor, callback);

        // Create an OobResponderRangingConfig, which specifies the ranging parameters for
        // the responder role.
        OobResponderRangingConfig config = new OobResponderRangingConfig.Builder(  deviceHandle).build();

        // Create a RangingPreference, which specifies the role (responder) and
        // configuration for the ranging session.
        RangingPreference preference =
                new RangingPreference.Builder(DEVICE_ROLE_RESPONDER, config).build();

        // Start the ranging session.
        session.start(preference);

        // Stop the ranging session
        session.stop();
    }
}

إمكانية التشغيل التفاعلي للنطاق الفائق العرض (UWB) مع أجهزة iOS

تتيح وحدة Ranging إمكانية التشغيل التفاعلي مع أجهزة iOS باستخدام تقنية النطاق الفائق العرض (UWB). لإجراء عملية تحديد المدى باستخدام جهاز iOS، عليك استخدام عملية تنفيذ مخصّصة لبروتوكول OOB وضبط جلسة تحديد المدى باستخدام مَعلمات محدّدة تتطابق مع بروتوكول Apple Nearby Interaction Accessory. يمكنك الرجوع إلى تطبيق العيّنة للحصول على معلومات مرجعية.

عند إنشاء RangingPreference، استخدِم RawRangingDevice وUwbRangingParams لتحديد الإعدادات. المَعلمات التالية ضرورية للتوافق مع نظام التشغيل iOS:

  • رقم تعريف الإعدادات: استخدِم UwbRangingParams.CONFIG_UNICAST_DS_TWR.
  • معلومات مفتاح الجلسة: قدِّم مصفوفة بايت تحتوي على معرّف المورّد وStatic STS IV.
  • القناة المعقّدة: اضبط رقم القناة وفهرس الديباجة ليتطابقا مع إعدادات جهاز iOS.

يوضّح مقتطف الرمز التالي كيفية إنشاء RangingPreference لجهاز بدء النطاق مع جهاز استجابة iOS:

Kotlin

// Create UwbRangingParams with iOS-specific configuration
val uwbRangingParams = UwbRangingParams.Builder(
    sessionId,
    UwbRangingParams.CONFIG_UNICAST_DS_TWR,
    sourceAddress,
    destinationAddress
)
    .setComplexChannel(
        UwbComplexChannel.Builder()
            .setChannel(channelNumber)
            .setPreambleIndex(preambleIndex)
            .build()
    )
    .setRangingUpdateRate(updateRate)
    .setSessionKeyInfo(sessionKeyInfo) // Vendor ID + STS IV
    .setSlotDuration(slotDuration)
    .build()

// Create RawRangingDevice
val rawRangingDevice = RawRangingDevice.Builder()
    .setRangingDevice(RangingDevice.Builder().build())
    .setUwbRangingParams(uwbRangingParams)
    .build()

// Create SessionConfig
val sessionConfig = SessionConfig.Builder()
    .setAngleOfArrivalNeeded(true)
    .setDataNotificationConfig(DataNotificationConfig.Builder()
        .setNotificationConfigType(DataNotificationConfig.NOTIFICATION_CONFIG_ENABLE)
        .build())
    .build()

// Create RangingPreference for the initiator
val preference = RangingPreference.Builder(
    RangingPreference.DEVICE_ROLE_INITIATOR,
    RawInitiatorRangingConfig.Builder()
        .addRawRangingDevice(rawRangingDevice)
        .build()
)
    .setSessionConfig(sessionConfig)
    .build()

Java

// Create UwbRangingParams with iOS-specific configuration
UwbRangingParams uwbRangingParams = new UwbRangingParams.Builder(
        sessionId,
        UwbRangingParams.CONFIG_UNICAST_DS_TWR,
        sourceAddress,
        destinationAddress)
        .setComplexChannel(new UwbComplexChannel.Builder()
                .setChannel(channelNumber)
                .setPreambleIndex(preambleIndex)
                .build())
        .setRangingUpdateRate(updateRate)
        .setSessionKeyInfo(sessionKeyInfo) // Vendor ID + STS IV
        .setSlotDuration(slotDuration)
        .build();

// Create RawRangingDevice
RawRangingDevice rawRangingDevice = new RawRangingDevice.Builder()
        .setRangingDevice(new RangingDevice.Builder().build())
        .setUwbRangingParams(uwbRangingParams)
        .build();

// Create SessionConfig
SessionConfig sessionConfig = new SessionConfig.Builder()
        .setAngleOfArrivalNeeded(true)
        .setDataNotificationConfig(new DataNotificationConfig.Builder()
                .setNotificationConfigType(DataNotificationConfig.NOTIFICATION_CONFIG_ENABLE)
                .build())
        .build();

// Create RangingPreference for the initiator
RangingPreference preference = new RangingPreference.Builder(
        RangingPreference.DEVICE_ROLE_INITIATOR,
        new RawInitiatorRangingConfig.Builder()
                .addRawRangingDevice(rawRangingDevice)
                .build())
        .setSessionConfig(sessionConfig)
        .build();

UWB Downlink-TDoA API

بالنسبة إلى واجهة برمجة التطبيقات UWB DL-TDoA، يُرجى الاطّلاع على الميزات الجديدة في Android 17.

تطبيق نموذجي

للاطّلاع على مثال شامل حول كيفية استخدام وحدة Ranging، راجِع التطبيق النموذجي في مشروع Android مفتوح المصدر (AOSP). يغطي هذا التطبيق النموذجي جميع تقنيات تحديد المدى التي يتيحها وحدة Ranging ويتضمّن مسارات لنوعَي الجلسات المتاحتَين.

إمكانية التشغيل التفاعلي للنطاق الفائق العرض (UWB) مع أجهزة iOS

يتيح تطبيق Android النموذجي بدء جلسة تحديد مدى باستخدام تقنية النطاق الفائق العرض مع تطبيق iOS النموذجي.

الشكل 2. استخدام تقنية النطاق الفائق العرض (UWB) على أجهزة Android وiOS