תמיכה בסמלי המערכת

בהמשך מפורטים העדכונים שבוצעו בתחומים הספציפיים האלה של המסכים:

קישוטי מערכת

ב-Android 10 נוספה תמיכה בהגדרת מסכים משניים כך שיציגו קישוטים מסוימים של המערכת, כמו טפט, סרגל הניווט והמרכז להפעלת אפליקציות. כברירת מחדל, במסך הראשי מוצגות כל התוספות של המערכת, ובמסכים המשניים מוצגות רק התוספות שהופעלו. אפשר להגדיר תמיכה בעורך שיטות קלט (IME) בנפרד מהקישוט של המערכת.

אפשר להשתמש ב-DisplayWindowSettings#setShouldShowSystemDecorsLocked() כדי להוסיף תמיכה בקישוט המערכת במסך ספציפי, או לספק ערך ברירת מחדל ב-/data/system/display_settings.xml. דוגמאות מפורטות מופיעות בקטע הגדרות חלון התצוגה.

הטמעה

המשתנה DisplayWindowSettings#setShouldShowSystemDecorsLocked() מוצג גם ב-WindowManager#setShouldShowSystemDecors() לצורך בדיקה. הפעלה של השיטה הזו במטרה להפעיל עיצובים של מערכת לא מוסיפה חלונות עיצוב שלא היו קיימים קודם, או מסירה אותם אם הם היו קיימים קודם. ברוב המקרים, השינוי בתמיכה בסמלי המערכת נכנס לתוקף רק אחרי הפעלה מחדש של המכשיר.

בדרך כלל, בדיקות לתמיכה בקישוט המערכת בבסיס הקוד של WindowManager עוברות דרך DisplayContent#supportsSystemDecorations(), ואילו בדיקות לשירותים חיצוניים (כמו System UI כדי לבדוק אם יש להציג את סרגל הניווט) עוברות דרך WindowManager#shouldShowSystemDecors(). כדי להבין מה נשלט על ידי ההגדרה הזו, כדאי לבדוק את נקודות הקריאה של השיטות האלה.

חלונות דקורטיביים של ממשק המשתמש של המערכת

ב-Android 10 נוספה תמיכה בחלון לקישוט המערכת עבור סרגל הניווט בלבד, כי סרגל הניווט חיוני לניווט בין פעילויות ואפליקציות. כברירת מחדל, סרגל הניווט מציג את הלחצנים 'הקודם' ו'דף הבית'. הערך הזה נכלל רק אם מסך היעד תומך בקישוט המערכת (ראו DisplayWindowSettings).

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

חלון המערכת סקירה כללית/פריטים אחרונים לא נתמך במסכים משניים. ב-Android 10, ב-AOSP מוצגת רק הכרטיסייה 'מהזמן האחרון' במסך ברירת המחדל, והיא מכילה פעילויות מכל המסכים. כשמפעילים את האפליקציה מהפעילות האחרונה, הפעילות שהוצגה במסך המשני תוצג בחזית המסך הזה כברירת מחדל. לגישה הזו יש כמה בעיות ידועות, למשל, העדכונים לא מתבצעים באופן מיידי כשאפליקציות מופיעות במסכים אחרים.

הטמעה

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

רכיב של ממשק המשתמש של המערכת שתומך בתצוגה מרובת מסכים (MD) צריך לטפל במקרים הבאים:

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

כשמערכת הממשק של המשתמש מזהה הוספה של מסך לפני WindowManager, נוצר מצב של תחרות. כדי למנוע את הבעיה הזו, אפשר להטמיע קריאה חוזרת בהתאמה אישית מ-WindowManager ל-System UI כשמוסיפים מסך, במקום להירשם לאירועים של DisplayManager.DisplayListener. להטמעה לדוגמה, תוכלו לעיין במאמר CommandQueue.Callbacks#onDisplayReady לגבי תמיכה בסרגל הניווט ובמאמר WallpaperManagerInternal#onDisplayReady לגבי טפטים.

בנוסף, ב-Android 10 יש את העדכונים הבאים:

  • הכיתה NavigationBarController קובעת את כל הפונקציונליות הספציפית לסרגלי הניווט.
  • מידע נוסף על סרגל ניווט בהתאמה אישית זמין במאמר CarStatusBar.
  • TYPE_NAVIGATION_BAR כבר לא מוגבל למכונה אחת, וניתן להשתמש בו לכל מסך.
  • IWindowManager#hasNavigationBar() מתעדכן כך שיכלול את הפרמטר displayId לממשק המשתמש של המערכת בלבד.

מרכז האפליקציות

ב-Android 10, לכל מסך שמוגדר לתמוך בקישוט המערכת יש כברירת מחדל סטאק בית ייעודי לפעילויות של מרכז האפליקציות מסוג WindowConfiguration#ACTIVITY_TYPE_HOME. בכל מסך נעשה שימוש במכונה נפרדת של פעילות מרכז האפליקציות.

איור 1. דוגמה למרכז אפליקציות עם תצוגה מרובת מסכים עבור platform/development/samples/MultiDisplay

רוב מרכזי האפליקציות הקיימים לא תומכים במספר מופעים ולא מותאמים למסכים גדולים. בנוסף, לרוב מצפים לחוויה שונה במסכים משניים או חיצוניים. כדי לספק פעילות ייעודית למסכים משניים, ב-Android 10 נוספה הקטגוריה SECONDARY_HOME למסנני הכוונה. המופעים של הפעילות הזו משמשים בכל המסכים שתומכים בסמלי המערכת, אחד לכל מסך.

<activity>
    ...
    <intent-filter>
        <category android:name="android.intent.category.SECONDARY_HOME" />
        ...
    </intent-filter>
</activity>

לפעילות צריך להיות מצב הפעלה שלא מונע הפעלת כמה מופעים, והיא אמורה להתאים לגדלים שונים של מסכים. אסור להגדיר את מצב ההפעלה בתור singleInstance או singleTask.

הטמעה

ב-Android 10, RootActivityContainer#startHomeOnDisplay() בוחר באופן אוטומטי את הרכיב והכוונה הרצויים, בהתאם למסך שבו מסך הבית הופעל. RootActivityContainer#resolveSecondaryHomeActivity() מכיל את הלוגיקה לחיפוש רכיב הפעילות של מרכז האפליקציות בהתאם למרכז האפליקציות שנבחר כרגע, ויכול להשתמש בברירת המחדל של המערכת במקרה הצורך (ראו ActivityTaskManagerService#getSecondaryHomeIntent()).

הגבלות אבטחה

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

טפטים

ב-Android 10 ואילך, יש תמיכה בשימוש ברקעים במסכים משניים:

איור 2. טפט דינמי במסכים פנימיים (למעלה) ובמסכים חיצוניים (למטה)

מפתחים יכולים להצהיר על תמיכה בתכונה 'טפט' על ידי ציון הערך android:supportsMultipleDisplays="true" בהגדרת ה-XML של WallpaperInfo. מפתחי טפטים גם צפויים לטעון נכסים באמצעות הקשר התצוגה ב-WallpaperService.Engine#getDisplayContext().

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

בחירת טפטים למסכים נפרדים

ב-Android 10 אין תמיכה ישירה בפלטפורמה לבחירת טפטים למסכים נפרדים. כדי לעשות זאת, נדרש מזהה יציב של המסך כדי לשמור את הגדרות הטפט לכל מסך. השדה Display#getDisplayId() הוא דינמי, ולכן לא בטוח שלמסך פיזי יהיה אותו מזהה אחרי הפעלה מחדש.

עם זאת, ב-Android 10 נוספה התכונה DisplayInfo.mAddress, שמכילה מזהים יציבים למסכים פיזיים וניתן להשתמש בה להטמעה מלאה בעתיד. לצערנו, כבר מאוחר מדי להטמיע את הלוגיקה ל-Android 10. הפתרון המוצע:

  1. משתמשים ב-API של WallpaperManager כדי להגדיר את הטפטים.
  2. הערך של WallpaperManager מתקבל מאובייקט Context, וכל אובייקט Context מכיל מידע על המסך התואם (Context#getDisplay()/getDisplayId()). לכן, אפשר לקבל את הערך של displayId ממכונה של WallpaperManager בלי להוסיף שיטות חדשות.
  3. בצד המסגרת, משתמשים ב-displayId שמתקבל מאובייקט Context וממפים אותו למזהה סטטי (למשל, יציאה של מסך פיזי). משתמשים במזהה הסטטי כדי לשמור את הטפט שנבחר.

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

אם צריך להגדיר טפט למסך אחר מלבד המסך הנוכחי, צריך ליצור אובייקט Context חדש למסך היעד (Context#createDisplayContext) ולקבל את המופע WallpaperManager מהמסך הזה.

הגבלות אבטחה

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

הטמעה

ב-Android 10, הממשקים IWallpaperConnection#attachEngine() ו-IWallpaperService#attach() מקבלים את הפרמטר displayId כדי ליצור חיבורים לכל מסך. WallpaperManagerService.DisplayConnector מכיל בתוך עצמו חיבור ומנוע של טפט לכל מסך. ב-WindowManager, בזמן היצירה נוצרים בקרי טפט לכל אובייקט DisplayContent, במקום WallpaperController יחיד לכל המסכים.

חלק מההטמעות הציבוריות של שיטת WallpaperManager (כמו WallpaperManager#getDesiredMinimumWidth()) עודכנו כדי לחשב ולספק מידע למסכים התואמים. נוספו המאפיין WallpaperInfo#supportsMultipleDisplays() ומאפיין משאב תואם, כדי שמפתחי אפליקציות יוכלו לדווח על טפטים שמתאימים למספר מסכים.

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

איור 3. לוגיקה חלופית של טפט למסכים משניים