ב-Android 16 נוסף מודול המדידה, שמספק ממשק מאוחד וסטנדרטי למדידה מדויקת של המרחק בין מכשירים. אתם יכולים להשתמש בממשק ה-API הזה כדי למדוד את המרחק והמיקום של מכשירים סמוכים בלי שתצטרכו לטפל בכל טכנולוגיית מדידה בנפרד.
מודול הטווח תומך בטכנולוגיות הבאות:
- Ultra-wideband
- בדיקת ערוץ Bluetooth
- Wi-Fi NAN RTT
- טווח RSSI של Bluetooth
יכולות וזמינות של טווחים
המחלקות RangingManager מספקות לאפליקציות מידע על טכנולוגיות הטווח שנתמכות במכשיר המקומי, וגם על הזמינות והיכולות של כל טכנולוגיה. אפליקציות יכולות להירשם לCallback כדי לקבל עדכונים על שינויים בזמינות או ביכולות של טכנולוגיות נתמכות.
תפקידים במכשיר
מכשיר שמשתתף בסשן מדידה צריך להיות יוזם או משיב. המכשיר היוזם מתחיל את סשן מדידת המרחק עם מכשיר משיב אחד או יותר. מכשיר מגיב מגיב לבקשות לחישוב מרחק רק ממכשיר יוזם אחד בכל פעם. אפשר לציין את התפקיד של מכשיר מסוים בסשן של מדידת מרחק באמצעות המחלקה RangingPreference.
סוגי סשנים בטווח
כשמתחילים סשן של מדידת מרחק בין מכשירים, לעיתים קרובות צריך ליצור העברת נתונים מחוץ לפס (OOB) כדי להחליף פרמטרים לסשן.
מודול מדידת הטווח יכול לנהל בשבילכם משא ומתן מחוץ לתחום, אבל הוא תומך גם בהטמעות מותאמות אישית של OOB.
הטמעה של ברירת המחדל של OOB
בסוג הסשן הזה (RANGING_SESSION_OOB), מודול הטווח מטפל במשא ומתן מחוץ לפס כדי להתחיל סשן של מדידת טווח. היא בוחרת פרמטרים מתאימים על סמך העדפות הטווח שסופקו על ידי האפליקציה, והיא משתמשת בטכנולוגיות המתאימות על סמך מה ששני המכשירים תומכים בו. סוג הסשן הזה משתמש ב-OOB specification סטנדרטי.
מודול הטווח מגדיר רק את הפורמט והרצף של נתוני ה-OOB שבהם יש להשתמש כדי ליצור אינטראקציה עם מכשיר עמית. הוא לא מטפל בגילוי של מכשירים עמיתים או ביצירת חיבור.
הטמעה מותאמת אישית של OOB
בסוג הסשן הזה (RANGING_SESSION_RAW), האפליקציה עוקפת את תהליך ה-OOB של מודול ה-Ranging ומטפלת בעצמה במשא ומתן ובפרמטרים של ה-OOB. כלומר, האפליקציה צריכה לקבוע אילו טכנולוגיות נתמכות במכשיר העמית, לנהל משא ומתן על פרמטרים של טווח ולהתחיל את סשן מדידת הטווח.
העדפות לגבי טווחים
משתמשים באובייקט RangingPreference כדי לציין את הפרמטרים שנבחרו לסשן של טווח. הדוגמאות הבאות ממחישות את המצב הזה:
- תפקיד המכשיר. ההגדרה הזו מציינת אם המכשיר יהיה היוזם או המשיב.
- הגדרת טווח אובייקט
RangingConfigמציין את סוג הסשן של מדידת המרחק ופרמטרים אחרים שנדרשים כדי להתחיל סשן של מדידת מרחק. - הגדרת סשן. אובייקט
SessionConfigמציין פרמטרים שיוחלו על סשן המדידה, כמו מגבלת מדידה, שילוב חיישנים, הגדרת גדר וירטואלית ועוד.
הרשאת טווח
מודול מדידת הטווח דורש הרשאה מאוחדת חדשה (android.permission.RANGING) כדי לגשת לכל הטכנולוגיות הנוכחיות והעתידיות למדידת טווח. ההרשאה הזו מופיעה ברשימה NEARBY_DEVICES_PERMISSIONS.
<uses-permission android:name="android.permission.RANGING" />
הגבלות ומגבלות
יכול להיות שהמודול Ranging יגביל את הטווח מכמה סיבות, כולל:
- אפליקציות של צד שלישי יכולות לבצע מדידת מרחק ברקע רק באמצעות טכנולוגיית Ultra Wideband (UWB), ורק במכשירים נתמכים. אסור להשתמש בטכנולוגיות אחרות כדי להעריך את המרחק ברקע.
- אי אפשר להשתמש בטווח כשמגיעים למספר המקסימלי של סשנים מקבילים של קביעת טווח לפי מכשיר.
- יכול להיות שהטווח מוגבל בגלל בעיות בתקינות המערכת, כמו סוללה, ביצועים או זיכרון.
בנוסף, יש למודול Ranging את המגבלות הידועות הבאות:
- מודול המרחק תומך רק בהעברת נתוני מרחק למכשירים עמיתים באמצעות טכנולוגיית Ultra Wideband (UWB). בטכנולוגיות אחרות, מודול המרחק מספק נתוני מרחק רק למכשיר היוזם.
- מודול מדידת המרחק תומך רק בהוספה דינמית של מכשירים במצב מדידת מרחק גולמי, ורק עבור Ultra Wideband.
- מודול הטווח לא תומך בסשנים של פס רחב במיוחד מסוג 'אחד לרבים' עבור הטמעות ברירת מחדל של OOB. אם מעבירים כמה נקודות אחיזה של מכשירים, המודול יוצר סשן אחד לכל מכשיר עמית שתומך ב-UWB.
איך מבצעים סשן מדידה
כדי להפעיל סשן של מדידת מרחק באמצעות מודול מדידת המרחק:
- מוודאים שכל המכשירים פועלים ב-Android 16 ואילך.
- שולחים בקשה ל
android.permission.RANGINGהרשאה במניפסט של האפליקציה. - הערכת היכולות והזמינות של טכנולוגיות לחישוב מרחקים.
- גילוי מכשיר עמית לפעולות מדידת מרחק.
- יצירת חיבור לחילופי נתונים מחוץ לפס, באמצעות אחד מסוגי הסשנים שמתוארים במאמר סוגי סשנים של טווחים.
- הפעלת מדידת מרחק ואיסוף רציף של נתוני מדידת מרחק.
- סיום סשן המדידה.
בדוגמת הקוד הבאה מוצגים השלבים האלה גם לתפקיד של יוזם הבקשה וגם לתפקיד של המשיב.
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
מודול מדידת המרחק תומך בפעולה הדדית עם מכשירי iOS באמצעות טכנולוגיית Ultra Wideband (UWB). כדי להשתמש בטווח עם מכשיר iOS, צריך להשתמש בהטמעה מותאמת אישית של OOB ולהגדיר את סשן מדידת הטווח עם פרמטרים ספציפיים שתואמים לפרוטוקול האביזרים של Apple Nearby Interaction. אפשר לעיין באפליקציה לדוגמה.
כשיוצרים את RangingPreference, משתמשים ב-RawRangingDevice וב-UwbRangingParams כדי לציין את ההגדרה. הפרמטרים הבאים חיוניים לשילוב עם מערכות חיצוניות ב-iOS:
- מזהה ההגדרה: משתמשים ב-
UwbRangingParams.CONFIG_UNICAST_DS_TWR. - פרטי מפתח סשן: מספקים מערך בייטים שמכיל את מזהה הספק ואת ה-IV הסטטי של STS.
- ערוץ מורכב: מגדירים את מספר הערוץ ואת אינדקס הפתיח כך שיתאימו להגדרות של מכשיר 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 API זמין במאמר תכונות חדשות ב-Android 17.
אפליקציה לדוגמה
דוגמה מלאה לשימוש במודול Ranging מופיעה באפליקציית הדוגמה ב-AOSP. אפליקציית הדוגמה הזו כוללת את כל טכנולוגיות המדידה שנתמכות על ידי מודול המדידה, וכוללת תהליכי עבודה לשני סוגי הסשנים הנתמכים.
יכולת פעולה הדדית של UWB עם מכשירי iOS
אפליקציית הדוגמה ל-Android תומכת בהפעלת סשן של מדידת מרחק באמצעות UWB עם אפליקציית הדוגמה ל-iOS.