תמיכה ברשת המדיה

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

שינוי הגודל של פעילויות ותצוגות

כדי לציין שייתכן שאפליקציה לא תומכת במצב ריבוי חלונות או בשינוי גודל, פעילויות להשתמש במאפיין resizeableActivity=false. נפוץ בעיות שבהן אפליקציות יכולות להשתמש כאשר משנים את גודל הפעילויות:

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

ב-Android 7 ואילך) ניתן להגדיר אפליקציה resizeableActivity=false כדי לפעול תמיד במצב מסך מלא. לחשבון במקרה כזה, הפלטפורמה מונעת פיצול של פעילויות שלא ניתן לשנות את גודלן מסך. אם המשתמש מנסה להפעיל ממרכז האפליקציות פעילות שלא ניתן לשנות את גודלה בזמן שהפלטפורמה נמצאת במצב מסך מפוצל, הפלטפורמה יוצאת ממצב מסך מפוצל מפעילה את הפעילות שלא ניתן לשנות את גודלה במצב מסך מלא.

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

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

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

הטמעת ברירת המחדל מחילה את המדיניות הבאה:

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

  • הוא כיוון קבוע באמצעות היישום של android:screenOrientation
  • באפליקציה מוגדר יחס גובה-רוחב מקסימלי או מינימלי שמוגדר כברירת מחדל לפי רמת ה-API לטירגוט או מצהיר על יחס גובה-רוחב באופן מפורש

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

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

כשהערך resizeableActivity לא מוגדר (או מוגדר כ-) true), האפליקציה תומכת באופן מלא בשינוי הגודל.

הטמעה

פעילות שלא ניתן לשנות את גודלה, עם כיוון קבוע או יחס גובה-רוחב קבוע, נקראת מצב תאימות גודל (SCM) בקוד. התנאי מוגדר ActivityRecord#shouldUseSizeCompatMode() מתי פעילות SCM היא הופעלה, התצורה שקשורה למסך (כגון גודל או צפיפות) קבועה בתצורת הביטול המבוקשת, כך שהפעילות כבר לא תלויה בהגדרת התצוגה הנוכחית.

אם הפעילות של SCM לא יכולה למלא את כל המסך, היא מיושרת למעלה במרכז אופקית. גבולות הפעילות יחושבו על ידי AppWindowToken#calculateCompatBoundsTransformation()

כשפעילות SCM משתמשת בהגדרות מסך שונות מאלה של פעילות SCM מאגר (לדוגמה, גודל המסך השתנה, או הפעילות הועברה למקום אחר) תצוגה), ActivityRecord#inSizeCompatMode() הוא true ו SizeCompatModeActivityController (בממשק המשתמש של המערכת) מקבל את הפונקציה הקריאה החוזרת (callback) כדי להציג את לחצן ההפעלה מחדש של התהליך.

גודלי תצוגה ויחסי גובה-רוחב

ב-Android 10 יש תמיכה ביחסי גובה-רוחב חדשים מיחסים גבוהים של מסכים ארוכים ודקים ליחס של 1:1. האפליקציות יכולות להגדיר ApplicationInfo#maxAspectRatio ואת ApplicationInfo#minAspectRatio של המסך שהם משתמשים בו שאפשר להתמודד איתם.

יחסי אפליקציות ב-Android 10

איור 1. דוגמאות ליחסי אפליקציות נתמכים ב-Android 10

להטמעות של מכשירים יכולים להיות מסכים משניים עם גדלים וגם רזולוציות קטנות יותר מאלה שנדרשות ב-Android 9 ונמוכות יותר (לפחות 2.5 רוחב או גובה אינץ', מינימום 320DP בשביל smallestScreenWidth), אבל ניתן למקם רק פעילויות שהביעו הסכמה לתמיכה במסכים קטנים האלה שם.

אפליקציות יכולות להצטרף באמצעות הצהרה על גודל נתמך מינימלי הקטן מ- או שווה לגודל התצוגה של היעד. שימוש בandroid:minHeight וב android:minWidth מאפיינים של פריסת הפעילות צריך ללחוץ על 'חזרה' כדי לעשות זאת.

מדיניות בנושא פרסום ברשת המדיה

מערכת Android 10 מפרידה ומזיזה מסכים מסוימים מיישום ברירת המחדל של WindowManagerPolicy PhoneWindowManager למחלקות לכל תצוגה, למשל:

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

ב-Android 9 (וגרסאות קודמות), הכיתה PhoneWindowManager טופלה מדיניות תצוגה, מצב והגדרות, סיבוב, מסגרת חלון לקישוט מעקב ועוד. מערכת Android 10 מעבירה את רוב החלק הזה אל המחלקה DisplayPolicy, חוץ מהמעקב אחר סבב, שכולל הועבר אל DisplayRotation.

הגדרות של חלון התצוגה

ב-Android 10, ההגדרות לכל מסך, שניתן להגדיר הגדרת החלונות הורחבה, ועכשיו היא כוללת:

  • מצב ברירת המחדל של חלון התצוגה
  • ערכי סריקת יתר
  • מצב סבב משתמשים וסיבוב
  • מצב מאולץ של גודל, צפיפות והגדלה
  • מצב הסרת תוכן (כשמסירים את התצוגה)
  • תמיכה בקישוטים וב-IME של המערכת

בכיתה DisplayWindowSettings יש הגדרות לאירועים האלה אפשרויות. הם יישארו דיסקים במחיצה /data ב- display_settings.xml בכל פעם שהגדרה מסוימת משתנה. עבור פרטים נוספים, ראה DisplayWindowSettings.AtomicFileStorage DisplayWindowSettings#writeSettings(). יצרני מכשירים יכולים לספק ערכי ברירת מחדל ב-display_settings.xml למכשיר שלהם הגדרה אישית. עם זאת, מכיוון שהקובץ מאוחסן ב-/data, יכול להיות שתידרש לוגיקה נוספת כדי לשחזר את הקובץ אם הוא יימחק על ידי איפוס.

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

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

מזהים של תצוגה סטטית

ב-Android 9 (וגרסאות קודמות) לא סופקו מזהים יציבים למסכים . כשנוסף מסך למערכת, Display#mDisplayId או DisplayInfo#displayId היו שנוצר עבור התצוגה הזו על ידי הגדלת מונה סטטי. אם המערכת הוסיף והסר את אותה תצוגה, נוצר מזהה שונה.

אם במכשיר היו מספר מסכים זמינים בהפעלה, ייתכן שהמסכים להקצאת מזהים שונים, בהתאם לתזמון. בזמן ש-Android 9 קודם) כלל DisplayInfo#uniqueId, הוא לא הכיל מספיק מידע שמבדיל בין מסכים, מפני שמסכים פיזיים שמזוהה בתור local:0 או local:1, כדי לייצג במסך המובנה ובמסך החיצוני.

שינויים ב-Android 10: DisplayInfo#uniqueId להוסיף מזהה קבוע ולהבחין בין רשת מקומית, רשת במסכים וירטואליים.

סוג הצג פורמט
מקומי
local:<stable-id>
רשת
network:<mac-address>
וירטואלי
virtual:<package-name-and-name>

נוסף לעדכונים על uniqueId, DisplayInfo.address מכיל את DisplayAddress, a מזהה תצוגה יציב בכל הפעלה מחדש. ב-Android 10, DisplayAddress תומך פיזית ותצוגות רשת. DisplayAddress.Physical מכיל יציבה מזהה לתצוגה (כמו ב-uniqueId) וניתן ליצור אותו באמצעות DisplayAddress#fromPhysicalDisplayId().

ב-Android 10 יש גם שיטה נוחה לקבל פרטי יציאה (Physical#getPort()). ניתן להשתמש בשיטה זו ב של המסגרת כדי לזהות תצוגות באופן סטטי. לדוגמה, הוא משמש DisplayWindowSettings). DisplayAddress.Network מכיל את כתובת ה-MAC וניתן ליצור אותו באמצעות DisplayAddress#fromMacAddress().

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

בהינתן מזהה מסך HWC (שיכול להיות אטום ולא תמיד יציב), מחזירה את מספר היציאה (ספציפית לפלטפורמה) של 8 ביט שמזהה מחבר פיזי לפלט של המסך וגם blob של EDID במסך. SurfaceFlinger מחלץ את פרטי היצרן או הדגם מה-EDID אל ליצור את מזהי התצוגה היציבים של 64 ביט שנחשפים ל-framework. אם השיטה הזו אין תמיכה או שגיאות, SurfaceFlinger חוזר למצב MD מדור קודם, כאשר DisplayInfo#address הוא אפס ו- הקוד DisplayInfo#uniqueId הוא בתוך הקוד, כמו שמתואר למעלה.

כדי לוודא שהתכונה הזו נתמכת, מפעילים את הפקודה:

$ dumpsys SurfaceFlinger --display-id
# Example output.
Display 21691504607621632 (HWC display 0): port=0 pnpId=SHP displayName="LQ123P1JX32"
Display 9834494747159041 (HWC display 2): port=1 pnpId=HWP displayName="HP Z24i"
Display 1886279400700944 (HWC display 1): port=2 pnpId=AUS displayName="ASUS MB16AP"

שימוש ביותר משני מסכים

ב-Android 9 (וגרסאות קודמות), SurfaceFlinger ו-DisplayManagerService ההנחה היא קיום של שתי תצוגות פיזיות לכל היותר עם קוד זיהוי 0 בתוך הקוד ו-1.

החל מ-Android 10, פלטפורמת SurfaceFlinger יכולה למנף Hardware Composer (HWC) API ליצירת מזהי תצוגה יציבים, שמאפשרים לו לנהל מספר שרירותי של מסכים פיזיים. מידע נוסף זמין במאמר הבא: מזהי תצוגה סטטיים.

המסגרת יכולה לחפש את האסימון IBinder להציג עד SurfaceControl#getPhysicalDisplayToken לאחר קבלת מזהה התצוגה של 64 סיביות מ-SurfaceControl#getPhysicalDisplayIds או מאירוע Hot בתנאים של DisplayEventReceiver.

ב-Android 10 (וגרסאות קודמות), המסך הפנימי הראשי הוא TYPE_INTERNAL וכל המסכים המשניים מסומנים כ-TYPE_EXTERNAL ללא קשר לסוג החיבור. לכן, מתייחסים למסכים פנימיים נוספים כאל מסכים חיצוניים. כפתרון זמני, קוד ספציפי למכשיר יכול להניח הנחות לגבי DisplayAddress.Physical#getPort אם HWC ידוע והקצאת היציאות היא צפויה.

ההגבלה הזו הוסרה מגרסה 11 של Android (ואילך).

  • ב-Android 11, המסך הראשון שדווח במהלך ההפעלה הוא המסך הראשי. סוג החיבור (פנימי לעומת חיצוני) לא רלוונטי. עם זאת, עדיין לא ניתן לנתק את המסך הראשי ועל פי בפועל, הוא חייב להיות תצוגה פנימית. לתשומת ליבכם: בחלק מהטלפונים המתקפלים יש במסכים פנימיים.
  • מסכים משניים מסווגים כראוי בתור Display.TYPE_INTERNAL או Display.TYPE_EXTERNAL (לשעבר Display.TYPE_BUILT_IN ו-Display.TYPE_HDMI, בהתאמה), בהתאם לסוג החיבור שלהם.

הטמעה

ב-Android 9 ומטה, המסכים מזוהים באמצעות מזהי 32 ביט כאשר 0 הוא המסך הפנימי, 1 הוא המסך החיצוני, [2, INT32_MAX] הם צגים וירטואליים של HWC, ו- -1 מייצג תצוגה לא חוקית או מסך וירטואלי שאינו HWC.

החל מ-Android 10, המסכים מקבלים מודל יציב ומזהים קבועים, שמאפשרים את SurfaceFlinger ואת DisplayManagerService כדי לעקוב אחרי יותר משני מסכים ולזהות תצוגות שנראו בעבר. אם צוות HWC תומך ב-IComposerClient.getDisplayIdentificationData ומספק מסך נתוני זיהוי, SurfaceFlinger מנתח את מבנה EDID ומקצה נתונים יציבים מזהי תצוגה של 64 ביט למסכים פיזיים ולמסכים וירטואליים של HWC. המזהים מבוטאים באמצעות סוג של אפשרות, שבו ערך ה-null מייצג תצוגה לא חוקית או תצוגה וירטואלית לא של HWC מסך. ללא תמיכה של HWC, ב-SurfaceFlinger חוזרים להתנהגות הקודמת עם רוב שני המסכים הפיזיים.

מיקוד לכל תצוגה

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

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

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

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

שימוש בפורמט com.android.internal.R.bool.config_perDisplayFocusEnabled כדי להגדיר מיקוד לכל תצוגה.

תאימות

הבעיה: ב-Android 9 ובגרסאות קודמות, חלון אחד לכל היותר המערכת מתמקדת בשלב מסוים.

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

הטמעה

WindowManagerService#mPerDisplayFocusEnabled שולט/ת הזמינות של התכונה הזו. ב-ActivityManager, ActivityDisplay#getFocusedStack() נמצא עכשיו בשימוש במקום בכל העולם במשתנה. ActivityDisplay#getFocusedStack() קובעת את המיקוד לפי סדר Z במקום לשמור את הערך במטמון. ככה עושים את זה: רק מקור אחד, windowManager, צריך לעקוב אחר סדר ה-Z של הפעילויות.

ActivityStackSupervisor#getTopDisplayFocusedStack() לוקח גישה דומה במקרים שבהם המקבץ עם המיקוד הגבוה ביותר במערכת חייבים להיות מזוהים. מעבר הערימות מתבצע מלמעלה למטה, תוך חיפוש של של המקבץ הראשון כשיר.

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

ראו InputDispatcher::mFocusedWindowHandlesByDisplay ו InputDispatcher::setFocusedDisplay(). גם האפליקציות שבהתמקדות מתעדכנת בנפרד ב-inputManagerService דרך NativeInputManager::setFocusedApplication()

ב-WindowManager, מתבצע גם מעקב נפרד אחרי חלונות במיקוד. ראו DisplayContent#mCurrentFocus ו DisplayContent#mFocusedApp והשימושים התואמים. נושא קשור שיטות המעקב והעדכון הועברו מ WindowManagerService עד DisplayContent.