Android XR

איך יוצרים חוויות שמעוגנות בעולם האמיתי למשקפי XR עם חיבור חוטי

‫

רמקולים

מידע כללי

מידע על ההרצאה

עם Android XR, אתם יכולים לצאת מגבולות המסך ולעגן את האפליקציות שלכם בעולם האמיתי. בשיעור הזה נסביר איך ליצור חוויות Android XR עם מודעות מרחבית באמצעות Jetpack Compose Glimmer ו-Geospatial API של ARCore. נתחיל בהסבר על איך לקבל את התנוחה הגיאו-מרחבית של המכשיר באמצעות ARCore. לאחר מכן, תראו איך אפשר לעגן את רכיבי ממשק המשתמש המינימליים של Glimmer למיקומים בעולם האמיתי באמצעות מערכת המיקום החזותי (VPS). אנחנו נשלב את כל אלה כדי ליצור חוויה מרחבית פשוטה שמבוססת על מיקום.

סיכום

  • מערכת Android XR מאפשרת ליהנות מחוויות דיגיטליות בסביבות פיזיות במגוון מכשירים, ממשקפיים חכמים ועד משקפי XR עם חיבור חוטי. אפליקציות דו-ממדיות קיימות שתואמות ל-Android פועלות במשקפי VR עם Android XR ובמשקפי XR עם חיבור חוטי, עם שינויים מינימליים.
  • ‫Jetpack Compose Glimmer מספק רכיבים וסגנונות שמותאמים למסכים אופטיים שקופים. פונקציות עזר מובנות מתאימות את צבעי המותג לגוונים שמתאימים למשקפיים, כדי לשמור על הניראות והניגודיות בתנאי תאורה שונים.
  • ספריית Glimmer מוסיפה רכיבים חדשים כמו כלים לדפדוף וקבוצות של לחצנים. Depth API עוזר להפריד בין רכיבים שנערמים בתצוגות שקופות שבהן הצבע השחור הוא שקוף.
  • רכיבי Subspace composable ממקמים ממשקים במרחב תלת-ממדי ויכולים לעקוב אחרי עוגני ARCore באמצעות יעד מעקב, כמו קוד QR במעקב.
  • ‫Geospatial API ב-ARCore משלב נתונים מ-Street View ומדידות GPS כדי למקם מכשירים בצורה מדויקת באזורים נתמכים. אתם יכולים לצרף רכיבי Glimmer לעוגנים גיאו-מרחביים בעולם האמיתי באמצעות קואורדינטות משאילתות של Places API.

משאבים

Gemini Notebook

נושאים

  • android-xr
  • jetpack-compose
  • glimmer
  • arcore
  • geospatial-api
  • augmented-reality

תמליל

הורדת התמליל

מבוא ל-Android XR

  • שלום לכולם, ברוכים הבאים לסשן הראשון שלכם במסלול Android XR כאן במפגש של מפתחי Android.

  • כן!

  • אנחנו שמחים לראות שכל כך הרבה מכם מתעניינים ב-Android XR.

  • קוראים לי יסמין קווינטנה אווג'ן, ואיתי נמצאים פול הובר ודרק בריידי, שיצטרפו אלינו בהמשך השיחה.

  • הנושא של הסשן הזה הוא Android XR, ואיך אתם יכולים ליצור חוויות בעולם האמיתי עם עיגון מרחבי באמצעות Jetpack Compose Glimmer ו-ARCore for Jetpack XR.

  • אבל קודם, נציג בקצרה את Android XR.

  • ‫Android XR היא פלטפורמה חדשה שמשנה את האופן שבו המשתמשים יוצרים אינטראקציה עם האפליקציה שלכם, מעבר למסך ולמרחב שסביבם.

  • אנחנו מעצבים את הפלטפורמה כדי להביא חוויות דיגיטליות ישירות לסביבה הפיזית.

  • זה יכול להיות שכבות-על שמופיעות לרגע ומשפרות את הנוכחות בעולם האמיתי, או סביבה אינסופית וסוחפת.

  • זו אותה סביבה עסקית פתוחה של Android שאנחנו בונים ביחד כבר שנים, ועכשיו אזור העבודה גדול כמו החדר ורחב כמו הדמיון שלכם.

  • אנחנו רואים ב-XR מגוון של מכשירים, החל ממשקפיים חכמים שמאפשרים חוויות קלות ומשופרות של אודיו ותצוגה, ועד לקסדות VR ומשקפי XR עם חיבור חוטי, שמאפשרים להתמקד, להיות פרודוקטיביים וליהנות מבידור סוחף.

  • המכשיר החדש ביותר במשפחת Android XR הוא XREAL AURA, שאפשר לרכוש כבר היום.

  • המכשיר הזה קל ומתקדם, ומאפשר ליהנות מחוויות XR עם הממשק המוכר של Android.

  • החזון שלנו לפלטפורמה הוא שאם אתם כבר מפתחים ל-Android, אתם מוכנים לפתח ל-XR.

  • אנחנו רוצים שיהיה לכם קל לפתח ב-Android XR, ולכן אנחנו משתמשים באותו מודל של אפליקציה, באותה ספרייה ובאותם כלים שאתם מכירים.

  • האפליקציה הדו-ממדית הקיימת שלכם שתואמת ל-Android תפעל במשקפי VR עם Android XR ובמשקפי XR עם חיבור קווי, בלי שינויים או עם שינויים קלים בלבד.

‫Jetpack XR SDK וכלים למפתחים

  • כדי ליצור חוויות XR מדהימות שמתאימות לפלטפורמה, אנחנו מספקים קבוצה של ספריות שנוצרו במיוחד בשביל פלטפורמת XR.

  • מפתחים שרגילים ליצור חוויות בפלטפורמות סוחפות אחרות יכולים להשתמש ב-OpenXR ובתמיכה שלנו במנועי תלת-ממד, כמו Unity,‏ Godot ו-Unreal.

  • בואו נדבר על פיתוח באמצעות ספריות Android.

  • אנחנו מספקים את Jetpack XR SDK, קבוצה של ספריות Kotlin שעוזרות להרחיב את האפליקציות ל-XR בחוויות סוחפות ומועשרות.

  • בואו נראה מה יש בספריות שלנו.

  • השנה השקנו את ספריות Jetpack XR בגרסת בטא ובגרסה יציבה, כדי שתוכלו להתחיל ליצור חוויות XR סוחפות בראש שקט.

  • שכבת התפיסה היא ARCore for Jetpack XR.

  • הספרייה הזו מספקת מידע על העולם האמיתי, כמו מיקום של משטחים שטוחים כמו שולחן, ומיקום הידיים של המשתמשים.

  • הוא יכול לעקוב אחרי נקודות במרחב תלת-ממדי, ולספק את המידע הזה לאפליקציות, כמובן אם ניתנו לו ההרשאות המתאימות.

  • בנוסף, יש את Jetpack XR SceneCore, שמספק תרשים סצנה להצבת התוכן המרחבי.

  • הספרייה הזו יכולה להציג ישויות במרחב תלת-ממדי, ומספקת התנהגויות מרחביות למיקום מדויק של תרשים הסצנה.

  • ב-Jetpack Compose ל-XR יש רכיבים חדשים של Subspace Composable שנוצרו במיוחד לתלת-ממד.

  • מפתחי Android שכבר מכירים פריסות של Compose, כמו בנייה עם שורות ועמודות, יגלו שפריסת ממשק משתמש מרחבי היא אינטואיטיבית.

  • כשיוצרים שורה מרחבית, אפשר לפרוס כמה חלוניות מרחביות זו לצד זו באופן הצהרתי, בלי לחשב באופן ידני את המיקום או הגודל שלהן.

  • בעזרת רכיבים של מרחב משנה, כמו חלונית מרחבית או רכיב מסתובב, אתם יכולים להרחיב בקלות את הרכיבים הדו-ממדיים שלכם למרחב התלת-ממדי החדש הזה.

  • וכמובן, רכיבי Subspace יכולים לעשות יותר מאשר רק להציג תוכן דו-ממדי.

  • ‫Compose for XR תומך בסרטונים מרחביים ובמודלים תלת-ממדיים באמצעות משטח חיצוני מרחבי ומודל glTF מרחבי.

פיתוח ממשק משתמש באמצעות Jetpack Compose Glimmer

  • עכשיו, בואו נדבר על אפליקציות משופרות.

  • בעזרת ספריית Jetpack Projected, אתם יכולים לשפר את האפליקציה הקיימת לנייד כדי להשתמש בחומרה של משקפיים חכמים, כמו חיישנים ומסך.

  • ולבסוף, Jetpack Compose Glimmer, ערכת כלים לבניית ממשק משתמש שנועדה ליצירה של חוויות Android XR שמותאמות למשקפיים.

  • ‫Jetpack Compose Glimmer כולל סגנונות ורכיבים מוכנים לשימוש ליצירת חוויות XR.

  • השקנו את Glimmer בשנה שעברה והמשכנו להרחיב את היכולות שלו, כולל מיומנות של סוכן שעוזרת לכם לפתח אפליקציות למשקפיים עם תצוגה פנימית באמצעות Glimmer.

    android skills add display-glasses-with-jetpack-compose-glimmer
  • מאז ההשקה, אנחנו מקשיבים למשוב שלכם.

  • קיבלנו בקשות להרחיב את Jetpack Compose Glimmer מעבר למשקפיים חכמים.

  • אנחנו שמחים להודיע שביצענו שינויים כדי לשפר את התמיכה בחוויות עם עיגון מרחבי באמצעות Glimmer, ונעמיק בנושא הזה בהמשך השיחה.

  • התחלנו את העבודה על אופטימיזציה של Glimmer ביצירת ממשק חדש להצגה במגוון גורמי צורה של XR, ממסך ועד משקפי XR עם חיבור קווי.

  • הוספת המיקום החדש הזה מאפשרת לכם להתאים אישית את ממשק המשתמש בצורה גמישה יותר.

  • כדי להבליט את המותג של האפליקציות, הוספנו צבעים בהתאמה אישית לרכיבי Glimmer.

  • אתם יכולים להשתמש בהם כדי לבטא את הסגנון של המותג שלכם באפליקציות XR.

  • ספריית Jetpack Compose Glimmer מספקת פונקציות עזר שממירות את צבעי היעד וצבעי המותג לצבעים שמתאימים למשקפיים.

  • כך אפשר לוודא שהנראות תהיה אופטימלית בתצוגות אופטיות שקופות.

  • בואו נראה איך זה עובד בפועל.

  • אנחנו רוצים לשנות את הצבע של הלחצן הממוקד באפליקציה הזו של המשקפיים, ואני אבחר באחד מהצבעים האהובים עליי.

    val brandColor = Color(0xFFFFAABB)
    val focusedColor = ButtonDefaults.focusedColor(brandColor)
    
    Column(…) {
       LeadingImageCard(
           focusable = false,
           …
       ) {
           …
       }
       ButtonGroup(...) {
           Button(
               onClick = {},
               leadingIcon = { … },
               focusedColor = focusedColor,
           ) { Text("Add to cart") }
    
           /* Rest of the buttons */
       }
    }
  • שימו לב שכשהצבע מתווסף לקוד, פונקציות העזר של Glimmer מתאימות אותו לצבע שמתאים למשקפיים כדי לשפר את הניראות.

  • כל זה מובנה בספריית Jetpack Compose Glimmer, כדי שתוכלו ליצור חוויות שנראות נהדר בסביבות שונות.

  • ב-Android Studio, אתם יכולים להשתמש באמולטור כדי לראות איך ממשק המשתמש של המשקפיים ייראה ברקעים שונים, כמו סביבות בהירות, כהות או עמוסות.

  • העדכונים האלה הם רק קצה הקרחון.

  • אוקיי, לא.

  • הצוות שלי אמר לי שהבדיחה הזו לא תצחיק אותך, אבל בכל זאת שמרתי אותה.

  • אבל עכשיו, אני מעביר את השרביט לפול, שיספר לכם עוד על Jetpack Compose Glimmer.

עקרונות לעיצוב ממשק המשתמש של משקפיים עם תצוגה פנימית

  • בדיקה, בדיקה, אחת שתיים!

  • אני צריך ללחוץ על הכפתור "הבא".

  • אוקיי, תודה יסמין.

  • טוב.

  • כמו שיסמין אמרה, Jetpack Compose Glimmer מספק את אבני הבניין הבסיסיות לפיתוח אפליקציות שמותאמות למשקפיים עם תצוגה פנימית.

  • הרכיבים שלנו משלבים שיטות מומלצות שנוצרו עבור תצוגות אופטיות שקופות, ובנינו אותם ישירות לתוך ממשקי ה-API בשבילכם, כדי לאפשר לכל המפתחים ליצור חוויות אופטיות שקופות יפות ופונקציונליות.

  • כשמעצבים ומפתחים אפליקציות למכשירים עם עדשות שקופות כמו המכשיר הזה, צריך לזכור כמה דברים.

  • קודם כל, זה מסך שקוף, כלומר אין בו צבע שחור.

  • כשהעולם גלוי, השחור שקוף.

  • לכן, אי אפשר להסתמך על רקעים כהים כדי לשמור על ניגודיות בממשק המשתמש, בטקסט ובתוכן.

  • למרות שהצבע השחור לא נראה, אפשר להשתמש בו כדי להסתיר תוכן דיגיטלי אחר.

  • במסגרת ממשק המשתמש של Glimmer, יש לנו ממשק API של עומק שמאפשר להפריד בקלות בין רכיבים בממשק המשתמש וליצור תחושה של היררכיה.

  • כאן אפשר לראות איך העומק של הכרטיסים בערימה הזו עוזר להם להישאר מופרדים זה מזה.

  • מדעני הראייה שלנו סיפקו יחסי ניגודיות מומלצים לטקסט ולסמלים שניתן לראות ברוב תנאי התאורה.

  • כמו שיסמין הראתה, אנחנו יכולים לבנות את זה או שבנינו את זה בתוך המסגרת, כך שכאשר אתם מתאימים אישית את צבעי המשטח, אתם יכולים להיות בטוחים שהממשק שלכם יהיה קריא למשתמשים.

  • הטמענו את השיטות המומלצות האלה ואחרות בספריית הרכיבים המתרחבת שלנו.

  • לאחרונה השקנו הרבה רכיבים חדשים.

  • אחד הרכיבים החדשים ביותר שהוספנו הוא רכיב הדפדוף, שכולל מעברי תנועה חלקים ותנועות מובנות.

    val pagerState =
      rememberGlimmerPagerState(pageCount = { 10 })
    
    GlimmerHorizontalPager(pagerState) { page ->
       /* Card Content */
    }
  • אם אתם מכירים את הכלי לדפדוף אופקי של Compose, הרכיב הזה יהיה מוכר לכם מאוד.

  • הוספנו גם ארבע גרסאות חדשות של כרטיסים שנועדו להשתלב בצורה חלקה עם כלים לדפדוף, ערימות ורכיבים אחרים של ממשק המשתמש של Glimmer.

  • בכרטיסי תמונה מובילה ובכרטיסי תמונה נגררת, הטקסט והתמונות מוצגים זה לצד זה.

  • לכן, כדאי להשתמש בווריאציות האלה של הכרטיסים כשיש כמות שווה של טקסט ומידע חזותי.

  • הפרדנו את כרטיס התמונה לגרסה משלו.

  • האפשרות הזו הכי מתאימה כשרוצים להציג תמונה גדולה עם שורה אחת של טקסט או כיתוב, כמו בבורר הסרטונים הזה.

  • גרסת כרטיס הפעולה מטמיעה כפתור אחד בכרטיס.

  • כדאי להשתמש בזה כשרוצים שהמשתמשים ידעו בדיוק מה יקרה כשהם יפעילו את הכרטיס, כמו בבורר היעדים הזה.

  • קבוצות של כפתורים מאפשרות לכם להכניס הרבה כפתורים לשטח קטן.

    ButtonGroup {
       Button(onClick = {}) { Text("Button 1") }
       Button(onClick = {}) { Text("Button 2") }
       Button(onClick = {}) { Text("Button 3") }
       Button(onClick = {}) { Text("Button 4") }
       Button(onClick = {}) { Text("Button 5") }
    }
  • רק עם הקוד הפשוט הזה, אתם מקבלים את המעברים היפים האלה, התנהגויות גלילה, מסכים שמסתירים את הקצוות, והם מוצגים רק כשצריך, וקלט שמועבר אוטומטית מהמשקפיים לפקד.

  • קבוצות של כפתורים יכולות להכיל גם את כפתורי הסמלים ומתגי ההחלפה החדשים שלנו.

    var buttonChecked by remember { mutableStateOf(false) }
    
    ToggleButton(
      checked = buttonChecked,
      leadingIcon = { Icon(FavoriteIcon) },
      onCheckedChange = { buttonChecked = it }
    ) {
      Text(if (buttonChecked) "On" else "Off")
    }
  • כאן אפשר לראות את כל סוגי הכפתורים שלנו שמשמשים ליצירת ממשק השליטה במדיה.

  • עכשיו קל לבדוק את ממשק המשתמש על רקעים שונים.

  • האמולטור של המשקפיים מאפשר להכניס תמונות ב-360 מעלות ולהזיז את התמונה כדי לבדוק אותה על רקעים שונים, רקעים עמוסים, וגם, אתם יודעים, בהירים, כהים.

  • קבוצות של לחצנים מתאימות מאוד לשימוש בתצוגת פרטים כזו כדי להציג פעולות לפי הקשר.

  • בלחיצה, אתם יכולים להשתמש במעברים של רכיבים משותפים כדי לנווט למצב צפייה מפורט, ואז להשתמש בתנועת החזרה של המערכת כדי לחזור לתצוגה הקודמת.

  • איזה כיף.

  • בנוסף, הוספנו אינדיקטור לקלט קולי ותיבות דו-שיח של התראות.

  • אז כן, יש הרבה דברים חדשים.

  • אחרי שראינו כמה מהדברים החדשים, בואו ניצור משהו.

סקירה כללית של עוגנים מבוססי-מיקום

  • בנוסף לשימוש ב-Glimmer כדי ליצור משקפיים חכמים, אנחנו יכולים להשתמש ב-Glimmer כדי ליצור חוויות למשקפי XR עם חיבור קווי.

  • אנחנו רוצים שתפתחו חוויות שמעשירות את העולם שסביבכם, החל מעוגנים מבוססי-מיקום בעולם האמיתי.

  • נניח שאתם נמצאים בעיר חדשה, אולי בנסיעה לכנס מפתחים, ואתם רוצים למצוא מקום לאכול בעיר.

  • אתם יכולים לבקש מאפליקציית הניווט המועדפת עליכם למצוא מסעדות בקרבת מקום ואת הדירוגים שלהן.

  • אפשר להציג מידע ישירות על המיקום, כדי לספק הקשר, מידע והנחיות.

  • כאן אפשר לראות את רכיב Glimmer החדש שלנו שנקרא "סמן סמל".

  • הוא מאפשר להדגיש אלמנטים מרכזיים בעולם הפיזי ולשלב אותם עם רכיבים אחרים של Glimmer, כמו הכרטיס הזה.

  • בדוגמה הזו, הוא מוסיף הערות לנקודות עניין באמצעות ממשקי ה-API של מפות Google, של Places ושל Geospatial.

  • היי, דרק, בוא נראה להם איך מגדירים את זה.

  • אני בעניין.

  • טוב.

  • טוב.

  • אז כמו שפול אמר, בואו נתחיל לבנות.

  • לכן, נשתמש במאמרי עזרה למפתחים בכתובת developer.android.com/xr, ונסתכל על ספריית הרכיבים של Jetpack Compose Glimmer.

  • כך תוכלו לראות סקירה חזותית של כל הרכיבים שזמינים ב-Glimmer.

  • נתחיל עם החלק הזה בממשק המשתמש שפול הראה קודם.

  • נשתמש ב-Glimmer UI כדי ליצור אינדיקטור מרחבי ותיבת מידע.

  • אז נתחיל בזיהוי הרכיבים שבהם נשתמש.

  • בצד ימין יופיע סמן של סמל, ובצד שמאל נשתמש בכרטיס שיתאר את המקום.

  • אז אם תעברו ל-Android Studio, תוכלו לראות תצוגה מקדימה של החלונית הזו בדיוק כמו כל רכיב אחר של Compose, ולראות את השינויים בזמן אמת.

  • כמו שציינתי קודם, אתם יכולים לראות תצוגה מקדימה של ממשק המשתמש בכל מיני סוגים של סביבות רקע, ולוודא שהניגודיות של ממשק המשתמש מספיקה בתרחישים שונים, כמו סביבות כהות ובהירות.

  • עכשיו, אחרי שהגדרנו את אזור הציור, ניצור שורה, נמקם בה סמן סמל עם מרווחים, וכרטיס עם טקסט לדוגמה.

  • זה הכול, בעצם.

  • אם אתם מרוצים מהתצוגה המקדימה בדו-ממד, אפשר להתחיל לסמן משהו בעולם האמיתי, ונעשה את זה על ידי הוספת מרחב לממשק המשתמש.

  • כלומר, נציג את זה בתלת-ממד במקום בדו-ממד.

  • לכן, ממשקי משתמש מרחביים נמצאים במרחבי משנה, שהם מרחב תלת-ממדי כלשהו מול המשתמש.

    Subspace {
      SpatialPanel {
        VideoPlayer()
      }
    }
  • כברירת מחדל, מרחב משנה מציג את התוכן שלו במרחק נוח מהמשתמש.

  • אז לפני שנראה לכם איך להשתמש ב-Geospatial API, בואו נמקם משהו בקרבת מקום.

  • אז, לרכיב ה-composable של תת-המרחב שדיברתי עליו קודם יש פרמטר אופציונלי שמאפשר לציין יעד מעקב.

    val state by
      qrCode.state.collectAsState()
    Subspace(FollowTarget.anchor(anchor)) {
      SpatialPanel {
        Row {
          IndicatorDot()
          Spacer()
          QrCodeCard(state)
        }
      }
    }
  • כדי להצמיד משהו לעולם האמיתי, קודם צריך ליצור עוגן שמתקבל מ-ARCore for Jetpack XR.

  • ובדוגמה הזו, אני משתמש בתכונה של זיהוי קוד QR.

  • זה יאפשר לכם לקרוא ולעקוב אחרי קודי QR, כך שהתוכן שלכם יוכל לעקוב אחרי קוד ה-QR הזה במרחב, ואנחנו נצרף את ממשק המשתמש שראינו קודם.

שילוב של Geospatial API והפלטפורמה של מפות Google

  • אוקיי.

  • אז הראיתי לכם איך להציב תוכן דיגיטלי בעולם האמיתי בסביבה שלכם.

  • נחזור לדוגמה של פול.

  • אני, למשל, מהולנד.

  • אני לא ממש מכיר את מאונטיין ויו.

  • אז אחרי האירוע הזה, אני רוצה לעזור לך ליצור אפליקציה שתעזור לך למצוא בתי קפה נחמדים.

  • בואו נראה איך אנחנו יכולים לעזור למשתמשים שלנו למצוא כמה כאלה באמצעות Geospatial API, שנמצא עכשיו ב-ARCore for Jetpack XR.

  • לכן, Geospatial API שהושק במקור בסמארטפונים זמין עכשיו גם ב-Android XR.

  • התכונה משתמשת בנתונים מ-Google Street View ומשלבת אותם עם מדידות GPS כדי למקם את המכשיר באזורים נתמכים.

  • לכן, במשקפיים חכמים, אפשר להשתמש ב-Geospatial API כדי לקבוע במדויק את המיקום והכיוון של המשתמש, וכך לאפשר ניווט מדויק מאוד עם הנחיות מפורטות.

  • במכשירים שמאפשרים חוויה מציאותית, כמו משקפי XR עם חיבור קווי, Geospatial API מאפשר ליצור חוויות שממוקמות בצורה מדויקת בעולם האמיתי.

  • לדוגמה, אתם יכולים לעגן תוכן מרחבי על מבנים או ליצור סיורים מיוחדים בעיר.

  • אז בואו נתחיל להשתמש ב-Geospatial API בשלושת השלבים הבאים.

  • השלב הראשון הוא ליצור פרויקט ב-Google Cloud Platform ולהגדיר אימות באפליקציה.

  • לאחר מכן, כשה-Geospatial API מוגדר ומופעל באפליקציה, מבקשים מהמשתמש הרשאה לאחזר את המיקום שלו באמצעות רמת הפירוט הגבוהה.

  • אחרי שמגדירים את הסשן לשימוש ב-Geospatial API, הכול מוכן.

  • לכן, תוכלו למצוא את כל הפרטים על מאמרי העזרה למפתחים של Geospatial API בדף המפתחים החדש והמעודכן של Android XR.

  • אז נתחיל בשימוש במיקום של המשתמש כדי לבקש מ-Places API מהפלטפורמה של מפות Google למצוא בתי קפה טובים בקרבת המשתמש.

  • קודם כול, איפה המשתמש נמצא?

  • נבקש מ-Geospatial API לקבל עדכונים שוטפים על מיקום המשתמש.

    produceState<AppStatus>(Initializing) {
      val geospatial = Geospatial.getInstance(session)
    
      val wait = geospatial.state.onEach {
         value = WaitingForGeospatial(it.geospatialTrackingState)
      }.first {
         it.geospatialTrackingState == Geospatial.GeospatialTrackingState.RUNNING
      }
    
      val accuracyWait = geospatial.state.onEach {
         value = WaitingForGeospatialAccuracy(it)
      }.first { it.horizontalAccuracy < horizontalAccuracyRequirement }
    
      value = WaitingForPlacesResults
      val result = client.findNearby(context, accWait.geospatialPose)
      value = Done(result)
    
    }
  • לכן, ניגש לאובייקט הגיאוגרפי דרך סשן ה-XR.

  • אחרי זה, נחכה ש-Geospatial יתחיל לפעול בזמן שהוא מאתחל את החיישנים הנדרשים ומתחבר ל-Cloud API.

  • ואז נמתין עד שנגיע לרמת דיוק מסוימת.

  • לכן, רמות הדיוק יכולות להשתפר ככל שמתקבלות מדידות GPS או כשהמערכת למיקום חזותי מוצאת התאמות במיקום של המשתמש.

  • חשוב להמתין עד שרמת הדיוק תהיה גבוהה כדי לוודא שהחוויות שקשורות למיקום מעוגנות במקום הנכון, ושהתוצאות הן מהאזור הקרוב של המשתמש.

  • עכשיו אנחנו מוכנים לבצע את החיפוש ב-Places API באמצעות ערכי המיקום מ-Geospatial API.

    val bounds = CircularBounds.newInstance(
      LatLng(pose.latitude, pose.longitude),
      100.0, // radius, in meters
    )
    val placeFields = listOf(
      Place.Field.ID, Place.Field.DISPLAY_NAME,
      Place.Field.RATING, Place.Field.LOCATION,
    )
    return placesClient.searchNearby(
      SearchNearbyRequest.builder(bounds, placeFields)
        .setIncludedTypes(listOf(PlaceTypes.CAFE))
        .setMaxResultCount(10)
        .build()
    ).await()
  • לכן, נשתמש ב-SearchNearbyRequest עם Places API כדי לשלוח שאילתה לגבי מקומות בסביבת המיקום של המשתמש שקיבלנו קודם, ונמצא תוצאות בטווח של 100 מטרים.

  • נקבל את מזהה המקום, השם המוצג שלו, הדירוג שלו וכמובן, המיקום שלו.

  • ולבסוף, נבצע את החיפוש עם הפרמטרים שצוינו, כולל מסנן של סוג המקום.

  • זהו, סיימנו עם הנתונים. בואו נחזור לממשק המשתמש.

  • לכן, נצטרך להבין איך למקם את הסמן ואת תיבת המידע שלנו מקודם, ולשם כך נשתמש בעוגנים גיאו-מרחביים.

  • אז נחזור לקוד. שוב, ניגש ל-Geospatial API באמצעות סשן ה-XR, ואז ניצור עוגן גיאו-מרחבי באמצעות קו רוחב וקו אורך ספציפיים שהתקבלו מתוצאות החיפוש קודם לכן.

    val anchorResult by produceState<AnchorResult?>(null) {
     val geospatial = Geospatial.getInstance(session)
     value = geospatial.createAnchorOnSurface(
       place.location.latitude, place.location.longitude,
       surface = GeospatialSurface.TERRAIN,
       altitudeAboveSurface = 3.0,
       eastUpSouthQuaternion = Quaternion()
     )
    }
  • בדוגמה הזו, הגדרנו את הגובה ל-3 מטרים מעל פני השטח בקואורדינטות האלה, אבל אפשר גם להצמיד לגגות נתמכים, כלומר ערך הגובה ייקבע ביחס לגג של הבניין במיקום הזה.

  • לכן, אפשר גם לסובב את העוגן באמצעות קווטרניון, שמציין את ערכי הסיבוב של העוגן.

  • אבל בדוגמה הזו נשתמש בברירות המחדל, כי נגרום לממשק המשתמש להסתובב כדי לפנות למשתמש.

  • ואז נצרף את ממשק המשתמש של Glimmer מהשלב הקודם לעוגן הזה, וזה באמת נותן לכם את אבני הבניין לחוויה מעוגנת במרחב.

    when (anchorResult) {
     is AnchorCreateSuccess ->
       Subspace(FollowTarget.anchor(anchorResult.anchor)) {
         SpatialPanel(SubspaceModifier.rotateToLookAtUser()) {
           PlaceIndicator(place)
         }
       }
    
     else ->
       Log.e("Demo", "Failed to create anchor $anchorResult")
    }
  • לכן, אנחנו מאמינים ש-Geospatial API יכול לאפשר חוויות ניווט נהדרות, ועיצוב עם Glimmer יעזור ליצור חוויות משתמש שניתן להבין במבט חטוף, שנוצרו במיוחד עבור מסכים שקופים.

  • מידע נוסף על Geospatial API זמין בכתובת developer.android.com/xr, שעודכנה לאחרונה.

  • אני מעביר את רשות הדיבור ליסמין כדי לסיים את המצגת.

סיכום ומשאבים למפתחים

  • בסשן הזה עברנו על כמה מהיכולות של Android XR: ‏ARCore for Jetpack XR ו-Jetpack Compose Glimmer.

  • אנחנו נרגשים מהתכונות החדשות ש-Android XR יביא למשקפי XR עם חיבור קווי.

  • מפתחים כבר יוצרים אפליקציות ל-Android XR, ואנחנו מקווים לראות את היצירות שלכם בחנות Google Play.

  • כדי להתחיל, כדאי לעיין במאמרי העזרה למפתחים, לקבל השראה מהניסויים שלנו ב-XR ולהתנסות ב-Codelabs.

  • תכננו בשבילכם המון סדנאות, הדגמות וסשנים מעולים בנושא XR.

  • כדאי להצטרף וללמוד איך לפתח ל-Android XR חוויות סוחפות וחוויות של מציאות רבודה.

  • בשם צוות Android XR, תודה רבה לכולכם שהגעתם, ואנחנו מקווים שתיהנו מהזמן שנותר לכם כאן במפגש של מפתחי Android.

  • אז תודה.

קוד

קטעי קוד

קטע קוד של Shell בדקה 04:39 בסרטון "פיתוח ממשק משתמש באמצעות Jetpack Compose Glimmer"
android skills add display-glasses-with-jetpack-compose-glimmer
קטע קוד ב-Kotlin בדקה 05:49 בסרטון "פיתוח ממשק משתמש באמצעות Jetpack Compose Glimmer"
val brandColor = Color(0xFFFFAABB)
val focusedColor = ButtonDefaults.focusedColor(brandColor)

Column(…) {
   LeadingImageCard(
       focusable = false,
       …
   ) {
       …
   }
   ButtonGroup(...) {
       Button(
           onClick = {},
           leadingIcon = { … },
           focusedColor = focusedColor,
       ) { Text("Add to cart") }

       /* Rest of the buttons */
   }
}
קטע קוד ב-Kotlin בדקה 08:37 בסרטון "עקרונות לעיצוב ממשק משתמש למשקפיים עם תצוגה פנימית"
val pagerState =
  rememberGlimmerPagerState(pageCount = { 10 })

GlimmerHorizontalPager(pagerState) { page ->
   /* Card Content */
}
קטע קוד ב-Kotlin בדקה 09:50 בסרטון "עקרונות לעיצוב ממשק משתמש למשקפיים עם תצוגה פנימית"
ButtonGroup {
   Button(onClick = {}) { Text("Button 1") }
   Button(onClick = {}) { Text("Button 2") }
   Button(onClick = {}) { Text("Button 3") }
   Button(onClick = {}) { Text("Button 4") }
   Button(onClick = {}) { Text("Button 5") }
}
קטע קוד ב-Kotlin בדקה 10:13 בסרטון "עקרונות לעיצוב ממשק משתמש למשקפיים עם תצוגה פנימית"
var buttonChecked by remember { mutableStateOf(false) }

ToggleButton(
  checked = buttonChecked,
  leadingIcon = { Icon(FavoriteIcon) },
  onCheckedChange = { buttonChecked = it }
) {
  Text(if (buttonChecked) "On" else "Off")
}
קטע קוד ב-Kotlin בדקה 13:55 בסרטון Overview of location-based anchors
Subspace {
  SpatialPanel {
    VideoPlayer()
  }
}
קטע קוד ב-Kotlin בדקה 14:16 בסרטון Overview of location-based anchors
val state by
  qrCode.state.collectAsState()
Subspace(FollowTarget.anchor(anchor)) {
  SpatialPanel {
    Row {
      IndicatorDot()
      Spacer()
      QrCodeCard(state)
    }
  }
}
קטע קוד ב-Kotlin בדקה 16:43 בסרטון Geospatial API and Google Maps Platform integration
produceState<AppStatus>(Initializing) {
  val geospatial = Geospatial.getInstance(session)

  val wait = geospatial.state.onEach {
     value = WaitingForGeospatial(it.geospatialTrackingState)
  }.first {
     it.geospatialTrackingState == Geospatial.GeospatialTrackingState.RUNNING
  }

  val accuracyWait = geospatial.state.onEach {
     value = WaitingForGeospatialAccuracy(it)
  }.first { it.horizontalAccuracy < horizontalAccuracyRequirement }

  value = WaitingForPlacesResults
  val result = client.findNearby(context, accWait.geospatialPose)
  value = Done(result)

}
קטע קוד ב-Kotlin בדקה 17:27 בסרטון Geospatial API and Google Maps Platform integration
val bounds = CircularBounds.newInstance(
  LatLng(pose.latitude, pose.longitude),
  100.0, // radius, in meters
)
val placeFields = listOf(
  Place.Field.ID, Place.Field.DISPLAY_NAME,
  Place.Field.RATING, Place.Field.LOCATION,
)
return placesClient.searchNearby(
  SearchNearbyRequest.builder(bounds, placeFields)
    .setIncludedTypes(listOf(PlaceTypes.CAFE))
    .setMaxResultCount(10)
    .build()
).await()
קטע קוד ב-Kotlin בדקה 18:09 בסרטון "שילוב של Geospatial API ו-Google Maps Platform"
val anchorResult by produceState<AnchorResult?>(null) {
 val geospatial = Geospatial.getInstance(session)
 value = geospatial.createAnchorOnSurface(
   place.location.latitude, place.location.longitude,
   surface = GeospatialSurface.TERRAIN,
   altitudeAboveSurface = 3.0,
   eastUpSouthQuaternion = Quaternion()
 )
}
קטע קוד ב-Kotlin בדקה 18:53 בסרטון "שילוב של Geospatial API ו-Google Maps Platform"
when (anchorResult) {
 is AnchorCreateSuccess ->
   Subspace(FollowTarget.anchor(anchorResult.anchor)) {
     SpatialPanel(SubspaceModifier.rotateToLookAtUser()) {
       PlaceIndicator(place)
     }
   }

 else ->
   Log.e("Demo", "Failed to create anchor $anchorResult")
}