התכונה 'תמונה בתוך תמונה' (PIP) למכשירי Android ניידים מאפשרת למשתמשים לשנות את הגודל של אפליקציה עם פעילות מתמשכת לחלון קטן. התכונה 'תמונה בתוך תמונה' שימושית במיוחד באפליקציות וידאו, כי התוכן ממשיך לפעול בזמן שהמשתמש יכול לבצע פעולות אחרות. המשתמשים יכולים לשנות את המיקום של החלון הזה דרך SystemUI וליצור אינטראקציה עם האפליקציה שמוצגת כרגע במצב 'תמונה בתוך תמונה' באמצעות (עד שלוש) פעולות שסופקו על ידי האפליקציה.
כדי להשתמש ב-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: הממשק הראשי שדרכו מבקשים להפעיל את התמונה בתוך התמונה (PIP) מהפעילות, והממשק שדרכו מתקשרים מ-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: מתחיל פעילות שמציגה את הפעולות שזמינות כרגע בפעילות במצב תמונה בתוך תמונה. הפעילות הזו היא פעילות של שכבת-על של משימה, והיא מסירה את צרכן הקלט של שכבת-העל כדי לאפשר אינטראקציה. -
PipMenuActivity: ההטמעה של פעילות התפריט. -
PipMediaController: מאזין שמעדכן אתSystemUIכשסשן המדיה משתנה באופן שעשוי להשפיע על פעולות ברירת המחדל ב-PIP. -
PipNotificationController: בקר שמבטיח שההתראה תהיה פעילה בזמן שהמשתמש משתמש בתכונת ה-PIP. -
PipDismissViewController: שכבת העל שמוצגת למשתמשים כשהם מתחילים ליצור אינטראקציה עם חלון ה-PIP, כדי לציין שאפשר לסגור אותו.
מיקום ברירת מחדל
יש משאבי מערכת שונים ששולטים במיקום ברירת המחדל של התמונה בתוך התמונה:
-
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 בצד המארח בקטע /cts/hostsidetests/services/activitymanager, במיוחד ב-ActivityManagerPinnedStackTests.java.