עדכונים שבוצעו לאזורים הספציפיים האלה לתצוגה מסופקים להלן:
- שינוי גודל פעילויות ותצוגות
- גדלי תצוגה ויחסי גובה-רוחב
- מדיניות תצוגה
- הגדרות חלון תצוגה
- מזהי תצוגה סטטיים
- שימוש ביותר משני צגים
- מיקוד לכל תצוגה
שנה את גודל הפעילויות והתצוגות
כדי לציין שייתכן שאפליקציה לא תומכת במצב ריבוי חלונות או שינוי גודל, פעילויות משתמשות בתכונה resizeableActivity=false
. בעיות נפוצות בהן נתקלים אפליקציות כאשר גודל הפעילויות משתנים כוללות:
- לפעילות יכולה להיות תצורה שונה מהאפליקציה או מרכיב אחר שאינו ויזואלי. טעות נפוצה היא לקרוא מדדי תצוגה מהקשר האפליקציה. הערכים המוחזרים לא יותאמו למדדי האזור הגלויים שבהם מוצגת פעילות.
- פעילות עשויה שלא לטפל בשינוי גודל ולקרס, להציג ממשק משתמש מעוות או לאבד מצב עקב הפעלה מחדש מבלי לשמור את מצב המופע.
- אפליקציה עשויה לנסות להשתמש בקואורדינטות קלט מוחלטות (במקום אלה ביחס למיקום החלון), מה שעלול לשבור את הקלט בריבוי חלונות.
באנדרואיד 7 (ומעלה), ניתן להגדיר אפליקציה resizeableActivity=false
כך שתפעל תמיד במצב מסך מלא. במקרה זה, הפלטפורמה מונעת מפעילויות שאינן ניתנות לשינוי גודל להיכנס למסך מפוצל. אם המשתמש מנסה להפעיל פעילות שאינה ניתנת לשינוי גודל מהמשגר בעודו נמצא במצב מסך מפוצל, הפלטפורמה יוצאת ממצב מסך מפוצל ומשיקה את הפעילות שאינה ניתנת לשינוי גודל במצב מסך מלא.
אין להפעיל אפליקציות שמגדירות את התכונה הזו ל- false
במניפסט במצב ריבוי חלונות, אלא אם מוחל מצב התאימות:
- אותה תצורה מוחלת על התהליך, המכיל את כל הפעילויות והרכיבים שאינם פעילות.
- התצורה המיושמת עומדת בדרישות ה-CDD עבור צגים תואמים לאפליקציה.
באנדרואיד 10, הפלטפורמה עדיין מונעת מפעילויות שאינן ניתנות לשינוי גודל לעבור למצב מסך מפוצל, אך ניתן להתאים אותן באופן זמני אם הפעילות הכריזה על כיוון קבוע או יחס רוחב-גובה. אם לא, הפעילות משתנה כדי למלא את כל המסך כמו באנדרואיד 9 ומטה.
יישום ברירת המחדל מחיל את המדיניות הבאה:
כאשר פעילות שהוכרזה כלא תואמת לריבוי חלונות באמצעות התכונה android:resizeableActivity
וכאשר פעילות זו עומדת באחד מהתנאים המתוארים להלן, אז כאשר תצורת המסך החלה חייבת להשתנות, הפעילות והתהליך נשמרים עם התצורה המקורית ולמשתמש ניתנת הזדמנות להפעיל מחדש את תהליך האפליקציה כדי להשתמש בתצורת המסך המעודכנת.
- האם אוריינטציה קבועה באמצעות היישום של
android:screenOrientation
- לאפליקציה יש ברירת מחדל של יחס רוחב-גובה מקסימלי או מינימלי על ידי מיקוד לרמת API או מצהירה במפורש על יחס רוחב-גובה
איור זה מציג פעילות שאינה ניתנת לשינוי גודל עם יחס רוחב-גובה מוצהר. בעת קיפול המכשיר, החלון מצטמצם כך שיתאים לאזור תוך שמירה על יחס הגובה-רוחב באמצעות ה-letterboxing המתאים. בנוסף, ניתנת למשתמש אפשרות הפעלה מחדש בכל פעם שאזור התצוגה של הפעילות משתנה.
בעת פתיחת המכשיר, התצורה, הגודל ויחס הגובה-רוחב של הפעילות אינם משתנים, אך מוצגת האפשרות להפעיל מחדש את הפעילות.
כאשר resizeableActivity
לא מוגדר (או שהוא מוגדר כ- true
), האפליקציה תומכת באופן מלא בשינוי גודל.
יישום
פעילות שאינה ניתנת לשינוי גודל עם כיוון קבוע או יחס רוחב-גובה נקרא בקוד מצב תאימות גודל (SCM). התנאי מוגדר ב- ActivityRecord#shouldUseSizeCompatMode()
. כאשר פעילות SCM מופעלת, התצורה הקשורה למסך (כגון גודל או צפיפות) קבועה בתצורת העקיפה המבוקשת, כך שהפעילות אינה תלויה עוד בתצורת התצוגה הנוכחית.
אם פעילות SCM לא יכולה למלא את כל המסך, היא מיושרת למעלה וממרכזת אופקית. גבולות הפעילות מחושבים על ידי AppWindowToken#calculateCompatBoundsTransformation()
.
כאשר פעילות SCM משתמשת בתצורת מסך שונה מהמכיל שלה (לדוגמה, גודל התצוגה שונה, או פעילות הועברה לתצוגה אחרת), ActivityRecord#inSizeCompatMode()
היא אמת ו- SizeCompatModeActivityController
(בממשק המשתמש של המערכת) מקבל את ההתקשרות חזרה כדי להציג את התהליך לחצן הפעלה מחדש.
גדלי תצוגה ויחסי גובה-רוחב
אנדרואיד 10 מספקת תמיכה ביחסי רוחב-גובה חדשים מיחסים גבוהים של מסכים ארוכים ודקים ועד ליחסים של 1:1. אפליקציות יכולות להגדיר את ApplicationInfo#maxAspectRatio
ואת ApplicationInfo#minAspectRatio
של המסך שהם מסוגלים לטפל בהם.
איור 1. יחסי אפליקציות לדוגמה נתמכים ב-Android 10
למימושים של מכשירים יכולים להיות צגים משניים עם גדלים ורזולוציות קטנות מאלה הנדרשות על-ידי אנדרואיד 9, ומטה (מינימום של 2.5 אינץ' רוחב או גובה, מינימום של 320 DP עבור smallestScreenWidth
), אך ניתן לבצע רק פעילויות שמצטרפות לתמוך בצגים קטנים אלה. מוצב שם.
אפליקציות יכולות להצטרף על ידי הצהרה על גודל מינימלי נתמך הקטן מ-oe שווה לגודל התצוגה היעד. השתמש בתכונות פריסת הפעילות android:minHeight
ו- android:minWidth
ב-AndroidManifest כדי לעשות זאת.
מדיניות תצוגה
אנדרואיד 10 מפרידה ומעבירה מדיניות תצוגה מסוימת מיישום ברירת המחדל WindowManagerPolicy
ב- PhoneWindowManager
למחלקות לכל תצוגה, כגון:
- מצב תצוגה וסיבוב
- כמה מקשים ומעקב אחר אירועי תנועה
- ממשק משתמש וחלונות דקורציה של המערכת
באנדרואיד 9 (ומטה), מחלקת PhoneWindowManager
טיפלה במדיניות תצוגה, מצב והגדרות, סיבוב, מעקב אחר מסגרות חלונות קישוט ועוד. אנדרואיד 10 מעביר את רוב זה למחלקה DisplayPolicy
, למעט מעקב אחר סיבוב, שהועבר ל- DisplayRotation
.
הגדרות חלון תצוגה
באנדרואיד 10, הגדרת החלונות הניתנת להגדרה לכל תצוגה הורחבה כך שתכלול:
- מצב חלונות תצוגה ברירת מחדל
- סריקת יתר של ערכים
- מצב סיבוב וסיבוב משתמש
- מצב גודל, צפיפות וקנה מידה מאולץ
- מצב הסרת תוכן (כאשר התצוגה מוסרת)
- תמיכה בקישוטי מערכת וב-IME
המחלקה DisplayWindowSettings
מכילה הגדרות עבור אפשרויות אלה. הם מועברים לתקליטור במחיצת /data
ב- display_settings.xml
בכל פעם ששינוי הגדרה. לפרטים, ראה DisplayWindowSettings.AtomicFileStorage
ו- DisplayWindowSettings#writeSettings()
. יצרני התקנים יכולים לספק ערכי ברירת מחדל ב- display_settings.xml
עבור תצורת המכשיר שלהם. עם זאת, מכיוון שהקובץ מאוחסן ב- /data
, ייתכן שיהיה צורך בהיגיון נוסף כדי לשחזר את הקובץ אם נמחק על ידי מחיקה.
כברירת מחדל, אנדרואיד 10 משתמש DisplayInfo#uniqueId
כמזהה עבור תצוגה בעת שמירה על ההגדרות. יש לאכלס uniqueId
עבור כל התצוגות. בנוסף, הוא יציב עבור תצוגות פיזיות ורשתות. אפשר גם להשתמש ביציאה של תצוגה פיזית כמזהה, שניתן להגדיר ב- DisplayWindowSettings#mIdentifier
. בכל כתיבה, כל ההגדרות נכתבות כך שבטוח לעדכן את המפתח המשמש לכניסה לתצוגה באחסון. לפרטים, ראה מזהי תצוגה סטטיים .
ההגדרות נשארות בספריית /data
מסיבות היסטוריות. במקור, הם שימשו לשמירה על הגדרות מוגדרות על ידי המשתמש, כגון סיבוב תצוגה.
מזהי תצוגה סטטיים
אנדרואיד 9 (ומטה) לא סיפק מזהים יציבים לתצוגות במסגרת. כאשר נוספה תצוגה למערכת, Display#mDisplayId
או DisplayInfo#displayId
נוצר עבור אותה תצוגה על ידי הגדלה של מונה סטטי. אם המערכת הוסיפה והסירה את אותה תצוגה, נוצר מזהה שונה.
אם למכשיר היו מספר צגים זמינים מהאתחול, ניתן היה להקצות לצגים מזהים שונים, בהתאם לתזמון. בעוד ש-Android 9 (וקודמתה יותר) כללה DisplayInfo#uniqueId
, היא לא הכילה מספיק מידע כדי להבדיל בין צגים מכיוון שצגים פיזיים זוהו כ- local:0
או local:1
, כדי לייצג את התצוגה המובנית והחיצונית.
אנדרואיד 10 משנה את DisplayInfo#uniqueId
כדי להוסיף מזהה יציב וכדי להבדיל בין תצוגות מקומיות, רשתות ווירטואליות.
סוג תצוגה | פוּרמָט |
---|---|
מְקוֹמִי | local:<stable-id> |
רֶשֶׁת | network:<mac-address> |
וירטואלי | virtual:<package-name-and-name> |
בנוסף לעדכונים של uniqueId
, DisplayInfo.address
מכיל DisplayAddress
, מזהה תצוגה שיציב לאורך אתחולים מחדש. באנדרואיד 10, DisplayAddress
תומכת בתצוגות פיזיות וברשתות. DisplayAddress.Physical
מכיל מזהה תצוגה יציב (זהה לזה של uniqueId
) וניתן ליצור אותו עם DisplayAddress#fromPhysicalDisplayId()
.
אנדרואיד 10 מספקת גם שיטה נוחה לקבל מידע על יציאות ( Physical#getPort()
). ניתן להשתמש בשיטה זו במסגרת לזיהוי סטטי של תצוגות. לדוגמה, הוא משמש ב- DisplayWindowSettings
). DisplayAddress.Network
מכיל את כתובת ה-MAC וניתן ליצור באמצעות DisplayAddress#fromMacAddress()
.
תוספות אלו מאפשרות ליצרני התקנים לזהות תצוגות בהגדרות מרובות תצוגה סטטיות ולהגדיר הגדרות ותכונות מערכת שונות באמצעות מזהי תצוגה סטטיים, כגון יציאות לצגים פיזיים. שיטות אלו מוסתרות והן מיועדות לשימוש רק בתוך system_server
.
בהינתן מזהה תצוגה של HWC (שיכול להיות אטום ולא תמיד יציב), שיטה זו מחזירה את מספר יציאת 8 סיביות (הספציפית לפלטפורמה) המזהה מחבר פיזי לפלט תצוגה, כמו גם את ה-EDID של התצוגה. SurfaceFlinger מחלץ מידע יצרן או דגם מה-EDID כדי ליצור את מזהי התצוגה היציבים של 64 סיביות שנחשפו למסגרת. אם שיטה זו אינה נתמכת או שגיאה יוצאת דופן, SurfaceFlinger חוזר למצב MD מדור קודם, שבו DisplayInfo#address
הוא null ו- 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"
השתמש ביותר משני צגים
באנדרואיד 9 (ומטה), SurfaceFlinger ו- DisplayManagerService
הניחו את קיומם של שני צגים פיזיים לכל היותר עם מזהים מקודדים קשיחים 0 ו-1.
החל מ-Android 10, SurfaceFlinger יכול למנף ממשק API של Hardware Composer (HWC) כדי ליצור מזהי תצוגה יציבים, המאפשרים לו לנהל מספר שרירותי של תצוגות פיזיות. למידע נוסף, ראה מזהי תצוגה סטטיים .
המסגרת יכולה לחפש את אסימון IBinder
עבור תצוגה פיזית דרך SurfaceControl#getPhysicalDisplayToken
לאחר השגת מזהה התצוגה של 64 סיביות מ- SurfaceControl#getPhysicalDisplayIds
או מאירוע Hotplug של DisplayEventReceiver
.
באנדרואיד 10 (ומטה), התצוגה הפנימית הראשית היא TYPE_INTERNAL
וכל הצגים המשניים מסומנים כ- TYPE_EXTERNAL
ללא קשר לסוג החיבור. לכן, תצוגות פנימיות נוספות מטופלות כאל חיצוניות. כפתרון עוקף, קוד ספציפי למכשיר יכול ליצור הנחות לגבי DisplayAddress.Physical#getPort
אם ה-HWC ידוע והלוגיקה של הקצאת היציאה ניתנת לחיזוי.
מגבלה זו מוסרת באנדרואיד 11 (ומעלה).
- באנדרואיד 11, התצוגה הראשונה שדווחה במהלך האתחול היא התצוגה הראשית. סוג החיבור (פנימי מול חיצוני) אינו רלוונטי. עם זאת, זה נשאר נכון שלא ניתן לנתק את התצוגה הראשית ומכאן שהיא חייבת להיות תצוגה פנימית בפועל. שימו לב שלחלק מהטלפונים המתקפלים יש מספר צגים פנימיים.
- תצוגות משניות מסווגות כהלכה כ-
Display.TYPE_INTERNAL
אוDisplay.TYPE_EXTERNAL
(שנודעו בעבר כ-Display.TYPE_BUILT_IN
ו-Display.TYPE_HDMI
, בהתאמה) בהתאם לסוג החיבור שלהם.
יישום
באנדרואיד 9 ומטה, התצוגות מזוהות על ידי מזהי 32 סיביות, כאשר 0 הוא התצוגה הפנימית, 1 הוא התצוגה החיצונית, [2, INT32_MAX]
הם צגים וירטואליים של HWC, ו-1 מייצג תצוגה לא חוקית או תצוגה שאינה של HWC תצוגה וירטואלית.
החל מאנדרואיד 10, לצגים מקבלים מזהים יציבים ומתמשכים, מה שמאפשר ל-SurfaceFlinger ול- DisplayManagerService
לעקוב אחר יותר משתי תצוגות ולזהות תצוגות שנראו בעבר. אם ה-HWC תומך IComposerClient.getDisplayIdentificationData
ומספק נתוני זיהוי תצוגה, SurfaceFlinger מנתח את מבנה ה-EDID ומקצה מזהי תצוגה יציבים של 64 סיביות עבור תצוגות וירטואליות פיזיות ו-HWC. המזהים באים לידי ביטוי באמצעות סוג אופציה, כאשר הערך null מייצג תצוגה לא חוקית או תצוגה וירטואלית שאינה של HWC. ללא תמיכת HWC, SurfaceFlinger חוזרת להתנהגות מדור קודם עם שני צגים פיזיים לכל היותר.
מיקוד לכל תצוגה
כדי לתמוך במספר מקורות קלט המכוונים לצגים בודדים בו-זמנית, ניתן להגדיר את אנדרואיד 10 לתמיכה במספר חלונות ממוקדים, לכל היותר אחד לכל תצוגה. זה מיועד רק לסוגים מיוחדים של מכשירים כאשר משתמשים מרובים מקיימים אינטראקציה עם אותו מכשיר בו-זמנית ומשתמשים בשיטות קלט או מכשירים שונים, כגון Android Automotive.
מומלץ מאוד שתכונה זו לא תהיה מופעלת עבור מכשירים רגילים, כולל מכשירים מרובי מסכים או כאלה המשמשים לחוויות דמויות שולחן עבודה. זה נובע בעיקר מחשש אבטחה שעלול לגרום למשתמשים לתהות באיזה חלון יש מיקוד קלט.
דמיינו את המשתמש שמזין מידע מאובטח לשדה קלט טקסט, אולי נכנס לאפליקציית בנק או מזין טקסט שמכיל מידע רגיש. אפליקציה זדונית עלולה ליצור תצוגה וירטואלית מחוץ למסך שבאמצעותה ניתן לבצע פעילות, גם עם שדה קלט טקסט. לפעילויות לגיטימיות וזדוניות יש מיקוד ושתיהן מציגות מחוון קלט פעיל (סמן מהבהב).
עם זאת, מכיוון שקלט ממקלדת (חומרה או תוכנה) מוזן לפעילות העליונה בלבד (אותה אפליקציה שהושקה לאחרונה), על ידי יצירת תצוגה וירטואלית נסתרת, אפליקציה זדונית עלולה לתפוס קלט משתמש, גם בעת שימוש במקלדת תוכנה בתצוגת המכשיר הראשי.
השתמש com.android.internal.R.bool.config_perDisplayFocusEnabled
כדי להגדיר מיקוד לכל תצוגה.
תְאִימוּת
בעיה: באנדרואיד 9 ומטה, לכל היותר לחלון אחד במערכת יש פוקוס בכל פעם.
פתרון: במקרה הנדיר שבו יתמקדו שני חלונות מאותו תהליך, המערכת מספקת מיקוד רק לחלון הגבוה יותר בסדר ה-Z. הגבלה זו מוסרת עבור אפליקציות המכוונות לאנדרואיד 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
.