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

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

קישוטים שנוצרו במערכת

ב-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 מציגה את הכרטיסייה 'מהזמן האחרון' רק בתצוגת ברירת המחדל, והיא מכילה פעילויות מכל התצוגות. כשמפעילים פעילות מהכרטיסייה 'אחרונים', הפעילות שהייתה במסך משני מועברת לחזית של המסך הזה כברירת מחדל. יש כמה בעיות ידועות בגישה הזו, כמו אי-עדכון מיידי כשאפליקציות מופיעות במסכים אחרים.

הטמעה

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

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

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

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

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

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

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

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

איור 1. דוגמה להפעלה של אפליקציה במספר מסכים בפלטפורמה/פיתוח/דוגמאות/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() contains the logic to look up the launcher activity component depending on the currently selected launcher and can use the system default, if needed (see 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. משתמשים במחלקת WallpaperManager כדי להגדיר את הטפטים.

    WallpaperManager מתקבל מאובייקט Context, ולכל אובייקט Context יש מידע על התצוגה התואמת (Context#getDisplay()/getDisplayId()). לכן, אפשר לקבל את displayId ממופע WallpaperManager בלי להוסיף שיטות חדשות.

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

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

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

הגבלות אבטחה

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

הטמעה

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

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

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

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