התכונה 'תמונה בתוך תמונה' (PIP) למכשירי Android ניידים מאפשרת למשתמשים לשנות את הגודל של חלון קטן של אפליקציה עם פעילות מתמשכת. התכונה 'תמונה בתוך תמונה' שימושית במיוחד באפליקציות וידאו, כי התוכן ממשיך לפעול בזמן שהמשתמש יכול לבצע פעולות אחרות. המשתמשים יכולים לשנות את המיקום של החלון הזה דרך SystemUI ולבצע אינטראקציה עם האפליקציה שמוצגת כרגע במצב 'תמונה בתוך תמונה' באמצעות (עד שלוש) פעולות שסופקו על ידי האפליקציה.
כדי להשתמש ב-PIP, צריך להביע הסכמה מפורשת באפליקציות שתומכות בו, והוא פועל על בסיס כל פעילות בנפרד. (לאפליקציה אחת יכולות להיות כמה פעילויות, אבל רק אחת מהן יכולה להיות במצב PIP). הבקשה להפעלת תמונה בתוך תמונה מתבצעת על ידי קריאה ל-enterPictureInPictureMode(), והפעילויות מקבלות קריאות חוזרות (callback) בצורה של onPictureInPictureModeChanged().
השיטה setPictureInPictureParams() מאפשרת לפעילויות לשלוט ביחס הגובה-רוחב שלהן כשהן מוצגות בתצוגת PIP, וגם בפעולות מותאמות אישית שמאפשרות למשתמשים ליצור אינטראקציה עם הפעילות בלי להרחיב אותה. ב-PIP, הפעילות מושהית, אבל היא מוצגת, והיא לא מקבלת ישירות קלט מגע או מיקוד חלון.
אפשר להציג רק משימה אחת במצב תמונה בתוך תמונה בכל פעם.
מידע נוסף זמין בתיעוד למפתחים של Android בנושא תמונה בתוך תמונה.
דרישות לגבי מכשירים
כדי לתמוך ב-PIP, צריך להפעיל את תכונת המערכת PackageManager#FEATURE_PICTURE_IN_PICTURE ב-/android/frameworks/base/core/java/android/content/pm/PackageManager.java.
במכשירים שתומכים ב-PIP, רוחב המסך צריך להיות לפחות 220dp. בדומה למסך מפוצל עם כמה חלונות, PIP מאפשר להפעיל כמה פעילויות במסך בו-זמנית. לכן, במכשירים צריכים להיות מעבד (CPU) וזיכרון RAM מספיקים כדי לתמוך בתרחיש השימוש הזה.
הטמעה
רוב הפעולות שקשורות לניהול מחזור החיים של הפעילות מתבצעות במערכת בין ActivityManager לבין WindowManager.
ההטמעה של ממשק המשתמש לדוגמה נמצאת בחבילה SystemUI.
שינויים במערכת לא אמורים להשפיע על ההתנהגות המובנית שלה, כפי שמוגדרת על ידי בדיקות Compatibility Test Suite (CTS). הלוגיקה של המערכת לגבי PIP מתמקדת בעיקר בניהול של משימות ופעילויות בערמה 'מוצמדת'. הנה סקירה כללית מהירה של הכיתה:
-
ActivityRecord: עוקב אחרי מצב התמונה בתוך תמונה של כל פעילות. כדי למנוע ממשתמשים להיכנס למצב תמונה בתוך תמונה בנסיבות מסוימות, כמו ממסך הנעילה או במהלך שימוש במציאות מדומה, מוסיפים מקרים ל-checkEnterPictureInPictureState(). -
ActivityManagerService: הממשק הראשי של הפעילות שדרכו מבקשים להיכנס למצב תמונה בתוך תמונה, והממשק של השיחות מWindowManagerומSystemUIשדרכו משנים את מצב הפעילות של התמונה בתוך התמונה. -
ActivityStackSupervisor: נקרא מתוךActivityManagerServiceכדי להעביר משימות אל הערימה המוצמדת או ממנה, ולעדכן אתWindowManagerלפי הצורך. PinnedStackWindowController: ממשקWindowManagerמ-ActivityManager.-
PinnedStackController: דיווח על שינויים במערכת ל-SystemUI, כמו הצגה או הסתרה של IME, שינוי יחס הגובה-רוחב או שינוי פעולות. -
BoundsAnimationController: מפעיל אנימציה לחלונות הפעילות של PIP באופן שלא גורם לשינוי בהגדרות בזמן שינוי הגודל. -
PipSnapAlgorithm: מחלקה משותפת שמשמשת גם במערכת וגם ב-SystemUI, ושולטת בהתנהגות ההצמדה של חלון ה-PIP ליד קצוות המסך.
ההפניה SystemUI
מספקת הטמעה מלאה של PIP שתומכת בהצגת פעולות מותאמות אישית למשתמשים ובמניפולציה כללית, כמו הרחבה וסגירה.
יצרני מכשירים יכולים להסתמך על השינויים האלה, כל עוד הם לא משפיעים על ההתנהגויות המובנות כפי שהן מוגדרות ב-CDD. הנה סקירה כללית מהירה של השיעור:
-
PipManager: הרכיבSystemUIשמופעל באמצעותSystemUI. -
PipTouchHandler: המטפל במגע, ששולט בתנועות שמשנות את גודל התמונה בתוך התמונה. ההגדרה הזו משמשת רק בזמן שהקלט פעיל ב-PIP (ראוInputConsumerController). אפשר להוסיף כאן תנועות חדשות. -
PipMotionHelper: מחלקה נוחה למעקב אחרי מיקום ה-PIP והאזור המותר במסך. השיחות מועברות אלActivityManagerServiceכדי לעדכן או להנפיש את המיקום והגודל של התמונה בתוך התמונה. -
PipMenuActivityController: מתחיל פעילות שמציגה את הפעולות שזמינות בפעילות שמוצגת כרגע במצב PIP. הפעילות הזו היא פעילות של שכבת-על של משימה, והיא מסירה את צרכן הקלט של שכבת-העל כדי לאפשר אינטראקציה. -
PipMenuActivity: ההטמעה של פעילות התפריט. -
PipMediaController: מאזין שמעדכן אתSystemUIכשסשן המדיה משתנה באופן שעשוי להשפיע על פעולות ברירת המחדל ב-PIP. -
PipNotificationController: בקר שמוודא שההתראה פעילה בזמן שהמשתמש משתמש בתכונת ה-PIP. -
PipDismissViewController: שכבת העל שמוצגת למשתמשים כשהם מתחילים אינטראקציה עם התמונה בתוך תמונה, כדי לציין שאפשר לסגור אותה.
מיקום ברירת המחדל
יש משאבי מערכת שונים ששולטים במיקום ברירת המחדל של התמונה בתוך התמונה:
-
config_defaultPictureInPictureGravity: מספר שלם של gravity, שקובע את הפינה שבה ימוקם ה-PIP, כמוBOTTOM|RIGHT. -
config_defaultPictureInPictureScreenEdgeInsets: ההיסטים מהצדדים של המסך למיקום התמונה בתוך תמונה. -
config_pictureInPictureDefaultSizePercentו-config_pictureInPictureDefaultAspectRatio: השילוב של אחוז הרוחב של המסך ויחס הגובה-רוחב קובע את הגודל של התמונה בתוך התמונה. הגודל המחושב של חלון ה-PIP שמוגדר כברירת מחדל לא יכול להיות קטן מ-@dimen/default_minimal_size_pip_resizable_task, כפי שמוגדר ב-CTS וב-CDD. -
config_pictureInPictureSnapMode: התנהגות ההצמדה כפי שמוגדרת ב-PipSnapAlgorithm.
ההטמעות במכשירים לא צריכות לשנות את יחסי הגובה-רוחב המינימליים והמקסימליים שמוגדרים ב-CDD וב-CTS.
הרשאות
ההגדרה 'פעולת האפליקציה' (OP_PICTURE_IN_PICTURE) לכל חבילה ב-AppOpsManager (main/core/java/android/app/AppOpsManager.java) מאפשרת למשתמשים לשלוט בתכונת התמונה בתוך תמונה ברמת האפליקציה דרך הגדרות המערכת.
ההטמעות של המכשירים צריכות להתייחס לבדיקה הזו כשפעילות מבקשת להיכנס למצב 'תמונה בתוך תמונה'.
בדיקה
כדי לבדוק הטמעות של PIP, מריצים את כל הבדיקות שקשורות לתמונה בתוך תמונה שנמצאות ב/cts/hostsidetests/services/activitymanager, במיוחד בActivityManagerPinnedStackTests.java.