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