ב-Android 17 יש תכונות וממשקי API חדשים ומעולים למפתחים. בקטעים הבאים מפורטות התכונות האלה, כדי לעזור לכם להתחיל לעבוד עם ממשקי ה-API הקשורים.
לרשימה מפורטת של ממשקי API חדשים, ששונו או שהוסרו, קראו את דוח ההבדלים ב-API. לפרטים על ממשקי API חדשים, עיינו במאמרי העזרה של ה-API של Android – ממשקי API חדשים מודגשים כדי שיהיה קל לזהות אותם.
כדאי גם לבדוק תחומים שבהם שינויים בפלטפורמה עשויים להשפיע על האפליקציות שלכם. למידע נוסף, ראו את הדפים הבאים:
- שינויים בהתנהגות שמשפיעים על אפליקציות שמטרגטות ל-Android 17
- שינויים בהתנהגות שמשפיעים על כל האפליקציות, בלי קשר ל-
targetSdkVersion.
פונקציונליות עיקרית
ב-Android 17 נוספו התכונות החדשות הבאות שקשורות לפונקציונליות הליבה של Android.
טריגרים חדשים של ProfilingManager
ב-Android 17 נוספו כמה טריגרים חדשים של המערכת ל-ProfilingManager כדי לעזור לכם לאסוף נתונים מעמיקים לניפוי באגים של בעיות בביצועים.
הטריגרים החדשים הם:
-
TRIGGER_TYPE_COLD_START: הטריגר מופעל במהלך הפעלה קרה של האפליקציה. התשובה כוללת גם דגימה של סטאק ביצוע וגם עקבות המערכת. -
TRIGGER_TYPE_OOM: הטריגר מופעל כשאפליקציה זורקתOutOfMemoryErrorומספקת תמונת מצב של הזיכרון מ-Java בתגובה. -
TRIGGER_TYPE_KILL_EXCESSIVE_CPU_USAGE: הטריגר מופעל כשאפליקציה נסגרת בגלל שימוש חריג ומוגזם במעבד (CPU), ובתגובה מספק דגימה של סטאק ביצוע. -
TRIGGER_TYPE_ANOMALY: זיהוי חריגות בביצועי המערכת, כמו קריאות מוגזמות ל-binder ושימוש מוגזם בזיכרון.
כדי להבין איך מגדירים את הטריגר של המערכת, קראו את המאמר בנושא יצירת פרופילים מבוססי-טריגר ואת המאמר בנושא אחזור וניתוח של נתוני פרופילים.
טריגר ליצירת פרופיל של חריגות באפליקציות
ב-Android 17 יש שירות לזיהוי חריגות במכשיר, שעוקב אחרי התנהגויות שצורכות הרבה משאבים ורגרסיות פוטנציאליות בתאימות. השירות הזה משולב עם ProfilingManager, ומאפשר לאפליקציה לקבל פריטי מידע שנוצרו על ידי אירועים ספציפיים שהמערכת זיהתה.
אפשר להשתמש בטריגר TRIGGER_TYPE_ANOMALY כדי לזהות בעיות בביצועי המערכת, כמו קריאות מוגזמות ל-binder ושימוש מוגזם בזיכרון. כשאפליקציה חורגת ממגבלות הזיכרון שמוגדרות במערכת ההפעלה, הטריגר של החריגה מאפשר למפתחים לקבל תמונות מצב של הזיכרון שספציפיות לאפליקציה, כדי לעזור להם לזהות ולתקן בעיות בזיכרון. בנוסף, במקרה של ספאם מוגזם ב-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)
}
ממשקי API של JobDebugInfo
ב-Android 17 יש ממשקי API חדשים של JobDebugInfo שעוזרים למפתחים לנפות באגים במשימות של JobScheduler – למה הן לא פועלות, כמה זמן הן פועלות ומידע נצבר אחר.
השיטה הראשונה של ממשקי ה-API המורחבים של JobDebugInfo היא getPendingJobReasonStats(), שמחזירה מפה של הסיבות לכך שהמשימה הייתה במצב המתנה לביצוע ומשך הזמן המצטבר של ההמתנה. ה-method הזו מצטרפת ל-methods getPendingJobReasonsHistory() ו-getPendingJobReasons() כדי לספק תובנות לגבי הסיבה לכך שמשימה מתוזמנת לא פועלת כצפוי, אבל היא מפשטת את אחזור המידע בכך שהיא מאפשרת לקבל גם את משך הזמן וגם את הסיבה למשימה ב-method אחת.
לדוגמה, עבור jobId מסוים, יכול להיות שה-method תחזיר את הערך PENDING_JOB_REASON_CONSTRAINT_CHARGING ומשך זמן של 60,000 אלפיות השנייה, מה שמציין שהמשימה הייתה בהמתנה במשך 60,000 אלפיות השנייה כי לא התקיים האילוץ של הטעינה.
צמצום חסימות מצב שינה באמצעות תמיכה במאזינים להתראות שפועלות במצב המתנה
ב-Android 17 יש גרסה חדשה של AlarmManager.setExactAndAllowWhileIdle שמקבלת OnAlarmListener במקום PendingIntent. המנגנון החדש הזה, שמבוסס על קריאות חוזרות (callbacks), אידיאלי לאפליקציות שמסתמכות כרגע על נעילות מצב פעולה רציפות כדי לבצע משימות תקופתיות, כמו אפליקציות להעברת הודעות ששומרות על חיבורי שקעים.
פרטיות
Android 17 כוללת את התכונות החדשות הבאות לשיפור פרטיות המשתמשים.
תמיכה בפלטפורמה של Encrypted Client Hello (ECH)
ב-Android 17 נוספה תמיכה בפלטפורמה בפרוטוקול הצפנת ClientHello (ECH), שיפור משמעותי של הפרטיות בתקשורת ברשת. ECH הוא תוסף ל-TLS 1.3 שמצפין את ה-SNI (אינדיקציה של שם השרת) במהלך לחיצת היד הראשונית של TLS. ההצפנה הזו עוזרת להגן על פרטיות המשתמשים, כי היא מקשה על מתווכים ברשת לזהות את הדומיין הספציפי שאליו מתחברת אפליקציה.
הפלטפורמה כוללת עכשיו את ממשקי ה-API הנדרשים לספריות רשת כדי להטמיע ECH. השינויים כוללים יכולות חדשות ב-DnsResolver לשליחת שאילתות לגבי רשומות DNS של HTTPS שמכילות הגדרות ECH, ושיטות חדשות ב-SSLEngines וב-SSLSockets של Conscrypt להפעלת ECH על ידי העברת ההגדרות האלה כשמתחברים לדומיין. מפתחים יכולים להגדיר העדפות ECH, כמו הפעלה אופציונלית או חובה, באמצעות הרכיב החדש <domainEncryption> בקובץ התצורה של אבטחת הרשת, שרלוונטי באופן גלובלי או לכל דומיין בנפרד.
ספריות רשת פופולריות כמו HttpEngine, WebView ו-OkHttp צפויות לשלב את ממשקי ה-API האלה של הפלטפורמה בעדכונים עתידיים, כדי להקל על האפליקציות לאמץ את ECH ולשפר את פרטיות המשתמשים.
מידע נוסף זמין במאמר בנושא הצפנה של Client Hello.
הכלי לבחירת אנשי קשר ב-Android
הכלי לבחירת אנשי קשר ב-Android הוא ממשק סטנדרטי שמאפשר למשתמשים לשתף אנשי קשר עם האפליקציה שלכם. הכלי זמין במכשירים עם Android בגרסה 17 (רמת API 37) ומעלה, והוא מאפשר לשמור על הפרטיות במקום להשתמש בהרשאה הרחבה READ_CONTACTS. במקום לבקש גישה לכל פנקס הכתובות של המשתמש, האפליקציה מציינת את שדות הנתונים שהיא צריכה, כמו מספרי טלפון או כתובות אימייל, והמשתמש בוחר אנשי קשר ספציפיים לשיתוף. כך האפליקציה מקבלת גישת קריאה רק לנתונים שנבחרו, מה שמבטיח שליטה פרטנית תוך מתן חוויית משתמש עקבית עם יכולות מובנות של חיפוש, החלפת פרופילים ובחירה מרובה, בלי צורך לבנות או לתחזק את ממשק המשתמש.
מידע נוסף זמין במסמכי התיעוד של הכלי לבחירת אנשי קשר.
אבטחה
ב-Android 17 נוספו התכונות החדשות הבאות כדי לשפר את האבטחה של המכשיר והאפליקציות.
מצב ההגנה המתקדמת ב-Android (AAPM)
מצב ההגנה המתקדמת ב-Android מציע למשתמשי Android קבוצה חדשה ועוצמתית של תכונות אבטחה, שמסמנת צעד משמעותי בהגנה על המשתמשים – במיוחד על אלה שנמצאים בסיכון גבוה יותר – מפני מתקפות מתוחכמות. התכונה AAPM היא תכונה אופציונלית, והיא מופעלת באמצעות הגדרת תצורה אחת שהמשתמשים יכולים להפעיל בכל שלב כדי להחיל קבוצה של אמצעי הגנה מבוססי-דעות.
ההגדרות הבסיסיות האלה כוללות חסימה של התקנת אפליקציות ממקורות לא מוכרים (העברה צדדית), הגבלה של העברת נתונים דרך USB ודרישה להפעלת סריקה של Google Play Protect, מה שמצמצם באופן משמעותי את שטח הפנים של המכשיר שחשוף להתקפות.
מפתחים יכולים להשתמש בממשק API AdvancedProtectionManager כדי לזהות את סטטוס המצב, וכך לאפשר לאפליקציות לאמץ באופן אוטומטי עמדה של אבטחה מוגברת או להגביל פונקציונליות בסיכון גבוה כשמשתמש מצטרף.
חתימה על קובצי APK באמצעות PQC
עכשיו Android תומכת בסכימת חתימה היברידית של APK כדי להגן על זהות החתימה של האפליקציה מפני איום פוטנציאלי של התקפות שמשתמשות במחשוב קוונטי. התכונה הזו מציגה סכימת חתימה חדשה של APK, שמאפשרת להתאים בין מפתח חתימה קלאסי (כמו RSA או EC) לבין אלגוריתם חדש של הצפנה פוסט-קוונטית (PQC) (ML-DSA).
הגישה ההיברידית הזו מבטיחה שהאפליקציה תישאר מאובטחת מפני התקפות קוונטיות בעתיד, תוך שמירה על תאימות לדורות קודמים של גרסאות Android ומכשירים ישנים יותר שמסתמכים על אימות חתימה קלאסי.
ההשפעה על המפתחים
- אפליקציות שמשתמשות בחתימת אפליקציה ב-Play: אם אתם משתמשים בחתימת אפליקציה ב-Play, אתם יכולים לחכות ש-Google Play תיתן לכם את האפשרות לשדרג לחתימה היברידית באמצעות מפתח PQC שנוצר על ידי Google Play. כך האפליקציה תהיה מוגנת בלי שתצטרכו לנהל את המפתחות באופן ידני.
- אפליקציות שמשתמשות במפתחות בניהול עצמי: מפתחים שמנהלים את מפתחות החתימה שלהם יכולים להשתמש בכלי פיתוח מעודכנים של Android (כמו apksigner) כדי לעבור לזהות היברידית, שמשלבת מפתח PQC עם מפתח קלאסי חדש. (צריך ליצור מפתח קלאסי חדש, אי אפשר להשתמש שוב במפתח הישן).
קישוריות
ב-Android 17 נוספו התכונות הבאות כדי לשפר את הקישוריות של המכשיר והאפליקציה.
רשתות לוויין מוגבלות
מבצעת אופטימיזציות כדי לאפשר לאפליקציות לפעול ביעילות ברשתות לווייניות עם רוחב פס נמוך.
חוויית המשתמש וממשק המשתמש של המערכת
Android 17 כוללת את השינויים הבאים, שנועדו לשפר את חוויית המשתמש.
ערוץ ייעודי לעוצמת הקול של Assistant
ב-Android 17 יש סטרימינג ייעודי של עוצמת הקול של Assistant לאפליקציות עזרה, להפעלה באמצעות USAGE_ASSISTANT. השינוי הזה מפריד בין האודיו של Assistant לבין האודיו הרגיל של המדיה, ומאפשר למשתמשים לשלוט בנפרד בעוצמת הקול של כל אחד מהם. כך אפשר, למשל, להשתיק את הפעלת המדיה ולהמשיך לשמוע את התשובות של Assistant, ולהיפך.
אפליקציות עזרה עם גישה למצב האודיו החדש MODE_ASSISTANT_CONVERSATION יכולות לשפר עוד יותר את העקביות של בקרת עוצמת הקול. אפליקציות של Assistant יכולות להשתמש במצב הזה כדי לספק רמז למערכת לגבי סשן פעיל של Assistant, וכך להבטיח שאפשר יהיה לשלוט בסטרימינג של Assistant מחוץ להפעלה הפעילה של USAGE_ASSISTANT או באמצעות ציוד היקפי מחובר של Bluetooth.
הפעלה רציפה
Handoff היא תכונה חדשה וממשק API חדש שיופיעו ב-Android 17. מפתחי אפליקציות יכולים לשלב אותם כדי לספק למשתמשים המשכיות בין מכשירים. הוא מאפשר למשתמש להתחיל פעילות באפליקציה במכשיר Android אחד ולהעביר אותה למכשיר Android אחר. התכונה "העברה" פועלת ברקע של מכשיר המשתמש ומציגה פעילויות זמינות ממכשירים אחרים של המשתמש שנמצאים בקרבת מקום, דרך נקודות כניסה שונות, כמו מרכז האפליקציות ושורת המשימות, במכשיר המקבל.
אפליקציות יכולות להגדיר את Handoff כך שתפעיל את אותה אפליקציית Android מקורית, אם היא מותקנת וזמינה במכשיר המקבל. בתהליך הזה, המשתמש מועבר בקישור עומק מאפליקציה לאפליקציה לפעילות הייעודית. לחלופין, אפשר להציע את התכונה "העברה מאפליקציה לאתר" כאפשרות חלופית או להטמיע אותה ישירות באמצעות "העברה באמצעות כתובת URL".
התמיכה בהעברה בין מכשירים מקושרים מיושמת על בסיס כל פעילות בנפרד. כדי להפעיל את Handoff, צריך להפעיל את השיטה setHandoffEnabled() לפעילות. יכול להיות שיהיה צורך להעביר נתונים נוספים יחד עם ההעברה, כדי שהפעילות שנוצרה מחדש במכשיר המקבל תוכל לשחזר את המצב המתאים. מטמיעים את הקריאה החוזרת (callback) של onHandoffActivityDataRequested() כדי להחזיר אובייקט HandoffActivityData שמכיל פרטים שמציינים איך התכונה Handoff צריכה לטפל בפעילות וליצור אותה מחדש במכשיר המקבל.
עדכון בזמן אמת – Semantic color API
ב-Android 17, העדכון בזמן אמת משיק את ממשקי ה-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();