שימוש בתכונה "תמונה בתוך תמונה" (PiP)

איך עושים את זה ב-Compose
‫Jetpack Compose היא ערכת הכלים המומלצת לפיתוח ממשק משתמש ב-Android. איך תומכים במצב "תמונה בתוך תמונה" ב-Compose.

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

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

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

יש תמיכה ב-PiP גם במכשירים תואמים עם Android TV OS מגרסה 14 (רמת API‏ 34) ואילך. למרות שיש הרבה קווי דמיון, יש שיקולים נוספים כשמשתמשים ב-PiP בטלוויזיה.

איך המשתמשים יכולים לבצע פעולות בחלון ה-PiP

המשתמשים יכולים לגרור את חלון ה-PiP למיקום אחר. החל מ-Android 12, המשתמשים יכולים גם:

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

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

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

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

האפליקציה קובעת מתי הפעילות הנוכחית נכנסת למצב "תמונה בתוך תמונה". הנה כמה דוגמאות:

  • פעילות יכולה להיכנס למצב "תמונה בתוך תמונה" כשהמשתמש לוחץ על כפתור הבית או מחליק למעלה כדי לעבור למסך הבית. כך מפות Google ממשיכות להציג מסלול בזמן שהמשתמש מפעיל פעילות אחרת.

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

  • האפליקציה יכולה להעביר סרטון למצב PiP בזמן שהמשתמש צופה בסוף של פרק תוכן. במסך הראשי מוצג מידע שיווקי או תקציר של הפרק הבא בסדרה.

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

הצהרה על תמיכה ב-PiP

כברירת מחדל, המערכת לא תומכת באופן אוטומטי בתמונה בתוך תמונה באפליקציות. כדי לתמוך ב-PiP באפליקציה, צריך לרשום את פעילות הסרטון במניפסט על ידי הגדרת android:supportsPictureInPicture ל-true. בנוסף, צריך לציין שהפעילות מטפלת בשינויים בפריסה, כדי שהפעילות לא תופעל מחדש כשיש שינויים בפריסה במהלך המעבר למצב "תמונה בתוך תמונה".

<activity android:name="VideoActivity"
    android:supportsPictureInPicture="true"
    android:configChanges=
        "screenSize|smallestScreenSize|screenLayout|orientation"
    ...

הטמעה של תמונה בתוך תמונה באמצעות Jetpack

כדי להטמיע את התכונה 'תמונה בתוך תמונה' (PiP), מומלץ להשתמש בספריית Jetpack Picture-in-Picture. כך אפשר לייעל את ההטמעה ולצמצם בעיות נפוצות באפליקציה. אפשר לעיין באפליקציה לדוגמה של הפלטפורמה כדי לראות דוגמה לשימוש בה. אבל אם אתם מעדיפים להטמיע את התכונה 'תמונה בתוך תמונה' באמצעות ממשקי API של הפלטפורמה, תוכלו לעיין במאמרי העזרה הבאים.

מעבר לפעילות במצב "תמונה בתוך תמונה"

החל מ-Android 12, אפשר להעביר את הפעילות למצב PiP על ידי הגדרת הדגל setAutoEnterEnabled לערך true. בהגדרה הזו, הפעילות עוברת באופן אוטומטי למצב PiP לפי הצורך, בלי שתצטרכו להפעיל באופן מפורש את enterPictureInPictureMode() ב-onUserLeaveHint. יתרון נוסף הוא שהמעברים בין הסרטונים הרבה יותר חלקים. פרטים נוספים זמינים במאמר מעברים חלקים יותר למצב "תמונה בתוך תמונה" מניווט באמצעות תנועות.

אם אתם מטרגטים ל-Android מגרסה 11 ומטה, הפעילות צריכה להפעיל את enterPictureInPictureMode() כדי לעבור למצב PiP. לדוגמה, הקוד הבא מעביר פעילות למצב PiP כשהמשתמש לוחץ על כפתור ייעודי בממשק המשתמש של האפליקציה:

override fun onActionClicked(action: Action) {
    if (action.id.toInt() == R.id.lb_control_picture_in_picture) {
        activity?.enterPictureInPictureMode()
        return
    }
}

יכול להיות שתרצו לכלול לוגיקה שמעבירה פעילות למצב PiP במקום לעבור לרקע. לדוגמה, אפליקציית מפות Google עוברת למצב PiP אם המשתמש לוחץ על כפתור הבית או על כפתור האפליקציות האחרונות בזמן שהאפליקציה מנווטת. כדי לטפל במקרה הזה, אפשר לשנות את onUserLeaveHint():

override fun onUserLeaveHint() {
    if (iWantToBeInPipModeNow()) {
        enterPictureInPictureMode()
    }
}

מומלץ: לספק למשתמשים חוויית מעבר חלקה למצב "תמונה בתוך תמונה"

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

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

השינויים האלה כוללים את הדברים הבאים.

  • מעברים חלקים יותר למצב "תמונה בתוך תמונה" מניווט באמצעות תנועות
  • הגדרת sourceRectHint מתאים לכניסה למצב PiP וליציאה ממנו
  • השבתת שינוי הגודל החלק של תוכן שאינו וידאו

כדי לראות דוגמה לחוויית מעבר חלקה, עיינו בדוגמה ל-PictureInPicture ב-Android Kotlin.

מעברים חלקים יותר למצב "תמונה בתוך תמונה" מניווט באמצעות תנועות

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

כדי לעשות את זה:

  1. משתמשים ב-setAutoEnterEnabled כדי ליצור את PictureInPictureParams.Builder:
setPictureInPictureParams(PictureInPictureParams.Builder()
  .setAspectRatio(aspectRatio)
  .setSourceRectHint(sourceRectHint)
  .setAutoEnterEnabled(true)
  .build())
Note: When `setAutoEnterEnabled` is enabled, you don't need to explicitly
call [`enterPictureInPictureMode`][5] in [`onUserLeaveHint`][6].
  1. צריך להפעיל את setPictureInPictureParams עם PictureInPictureParams העדכני בשלב מוקדם. האפליקציה לא ממתינה לקריאה החוזרת (callback) של onUserLeaveHint (כמו שהיא הייתה עושה ב-Android 11).

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

  2. אפשר להתקשר אל setAutoEnterEnabled(false), אבל רק אם זה הכרחי. לדוגמה, כנראה שלא תרצו להיכנס למצב PiP אם ההפעלה הנוכחית מושהית.

הגדרת sourceRectHint מתאים לכניסה למצב "תמונה בתוך תמונה" וליציאה ממנו

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

ב-Android 12, המערכת משתמשת ב-sourceRectHint כדי להטמיע אנימציה חלקה יותר גם בכניסה למצב PiP וגם ביציאה ממנו.

כדי להגדיר את sourceRectHint בצורה נכונה לכניסה למצב PiP וליציאה ממנו:

  1. יוצרים את PictureInPictureParams באמצעות הגבולות המתאימים בתור sourceRectHint. מומלץ גם לצרף מאזין לשינוי פריסה לנגן הווידאו:
val mOnLayoutChangeListener =
    OnLayoutChangeListener { v: View?, left: Int,
            top: Int, right: Int, bottom: Int, oldLeft: Int, oldTop:
            Int, oldRight: Int, oldBottom: Int ->
        val sourceRectHint = Rect()
        mYourVideoView.getGlobalVisibleRect(sourceRectHint)
        val builder = PictureInPictureParams.Builder()
            .setSourceRectHint(sourceRectHint)
        setPictureInPictureParams(builder.build())
    }

mYourVideoView.addOnLayoutChangeListener(mOnLayoutChangeListener)
  1. אם צריך, מעדכנים את sourceRectHint לפני שהמערכת מתחילה את מעבר היציאה. כשהמערכת עומדת לצאת ממצב PiP, היררכיית התצוגות של הפעילות מוגדרת לפי הגדרות היעד (לדוגמה, מסך מלא). האפליקציה יכולה לצרף מאזין לשינוי פריסה לתצוגת הבסיס או לתצוגת היעד (כמו תצוגת נגן הווידאו) כדי לזהות את האירוע ולעדכן את sourceRectHint לפני שהאנימציה מתחילה.
// Listener is called immediately after the user exits PiP but before animating.
playerView.addOnLayoutChangeListener { _, left, top, right, bottom,
                    oldLeft, oldTop, oldRight, oldBottom ->
    if (left != oldLeft
        || right != oldRight
        || top != oldTop
        || bottom != oldBottom) {
        // The playerView's bounds changed, update the source hint rect to
        // reflect its new bounds.
        val sourceRectHint = Rect()
        playerView.getGlobalVisibleRect(sourceRectHint)
        setPictureInPictureParams(
            PictureInPictureParams.Builder()
                .setSourceRectHint(sourceRectHint)
                .build()
        )
    }
}

השבתת שינוי גודל חלק של תוכן שאינו קטע וידאו

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

כדי להפעיל שינוי גודל חלק של קטע וידאו:

setPictureInPictureParams(PictureInPictureParams.Builder()
    .setSeamlessResizeEnabled(true)
    .build())

ממשק המשתמש של הידית במצב "תמונה בתוך תמונה"

כשהפעילות נכנסת למצב "תמונה בתוך תמונה" (PiP) או יוצאת ממנו, המערכת מפעילה את Activity.onPictureInPictureModeChanged() או את Fragment.onPictureInPictureModeChanged().

ב-Android 15 יש שינויים שמאפשרים מעבר חלק עוד יותר למצב "תמונה בתוך תמונה". האפשרות הזו שימושית לאפליקציות שכוללות רכיבים בממשק המשתמש שמוצגים כשכבת-על מעל ממשק המשתמש הראשי, שעובר למצב "תמונה בתוך תמונה".

מפתחים משתמשים בקריאה החוזרת (callback) onPictureInPictureModeChanged() כדי להגדיר לוגיקה שמשנה את החשיפה של רכיבי ממשק המשתמש שמוצגים בשכבת-על. הקריאה החוזרת הזו מופעלת כשהאנימציה של הכניסה או היציאה ממצב "תמונה בתוך תמונה" מסתיימת. החל מ-Android 15, המחלקה PictureInPictureUiState כוללת מצב חדש.

במצב החדש הזה של ממשק המשתמש, אפליקציות שמטרגטות ל-Android 15 מזהות שהקריאה החוזרת (callback) של Activity#onPictureInPictureUiStateChanged() מופעלת עם isTransitioningToPip() ברגע שהאנימציה של PiP מתחילה. יש הרבה רכיבים בממשק המשתמש שלא רלוונטיים לאפליקציה כשהיא במצב PiP, למשל תצוגות או פריסות שכוללות מידע כמו הצעות, הסרטון הבא, דירוגים ושמות. כשהאפליקציה עוברת למצב PiP, משתמשים בקריאה החוזרת (callback) של onPictureInPictureUiStateChanged() כדי להסתיר את רכיבי ממשק המשתמש האלה. כשהאפליקציה עוברת למצב מסך מלא מחלון PiP, משתמשים בקריאה החוזרת (callback) onPictureInPictureModeChanged() כדי לבטל את ההסתרה של הרכיבים האלה, כמו שמוצג בדוגמאות הבאות:

override fun onPictureInPictureUiStateChanged(pipState: PictureInPictureUiState) {
    if (pipState.isTransitioningToPip()) {
        // Hide UI elements.
    }
}
override fun onPictureInPictureModeChanged(
    isInPictureInPictureMode: Boolean,
    newConfig: Configuration
) {
    super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
    if (!isInPictureInPictureMode) {
        // Unhide UI elements.
    }
}

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

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

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

הוספת פקדים

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

אם לאפליקציה יש סשן מדיה פעיל, יופיעו לחצני ההפעלה, ההשהיה, המעבר לפריט הבא והמעבר לפריט הקודם.

אפשר גם לציין פעולות בהתאמה אישית באופן מפורש על ידי בניית PictureInPictureParams באמצעות PictureInPictureParams.Builder.setActions() לפני הכניסה למצב PiP, ולהעביר את הפרמטרים כשנכנסים למצב PiP באמצעות enterPictureInPictureMode(android.app.PictureInPictureParams) או setPictureInPictureParams(android.app.PictureInPictureParams). חשוב להיזהר. אם תנסו להוסיף יותר מ-getMaxNumPictureInPictureActions(), תקבלו רק את המספר המקסימלי.

המשך הפעלת הסרטון במצב "תמונה בתוך תמונה"

כשהפעילות עוברת למצב PiP, המערכת מעבירה את הפעילות למצב מושהה וקוראת ל-method‏ onPause() של הפעילות. הפעלת הסרטון לא אמורה להשהות, אלא להמשיך אם הפעילות מושהית בזמן המעבר למצב "תמונה בתוך תמונה".

ב-Android 7.0 (רמת API‏ 24) ומעלה, צריך להשהות את הפעלת הסרטון ולהמשיך אותה כשהמערכת קוראת ל-onStop() ול-onStart() של הפעילות. כך לא תצטרכו לבדוק אם האפליקציה נמצאת במצב PiP ב-onPause() ולהמשיך את ההפעלה באופן מפורש.

אם לא הגדרתם את הדגל setAutoEnterEnabled לערך true ואתם צריכים להשהות את ההפעלה בהטמעה של onPause(), בדקו אם מצב PiP מופעל על ידי קריאה ל-isInPictureInPictureMode() וטפלו בהפעלה בהתאם. לדוגמה:

override fun onPause() {
    super.onPause()
    // If called while in PiP mode, don't pause playback.
    if (isInPictureInPictureMode) {
        // Continue playback.
    } else {
        // Use existing playback logic for paused activity behavior.
    }
}

כשהפעילות עוברת ממצב PiP חזרה למצב מסך מלא, המערכת ממשיכה את הפעילות וקוראת ל-method‏ onResume().

שימוש בפעילות הפעלה אחת לתמונה בתוך תמונה

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

כדי לוודא שפעילות אחת משמשת לבקשות להפעלת וידאו ולמעבר למצב PiP או ממנו לפי הצורך, צריך להגדיר את android:launchMode של הפעילות ל-singleTask במניפסט:

<activity android:name="VideoActivity"
    ...
    android:supportsPictureInPicture="true"
    android:launchMode="singleTask"
    ...

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

תמיכה בתמונה בתוך תמונה (PiP) באפליקציות של מצלמות

כדי להפעיל את התכונה "תמונה בתוך תמונה" באפליקציות של מצלמה, צריך לוודא שהמצלמה נשארת פעילה במצב "תמונה בתוך תמונה" ולא נסגרת כשמתבצעת קריאה ל-onPause():

override fun onPause() {
    super.onPause()
    // Don't close the camera if the app is entering PiP mode
    if (!isInPictureInPictureMode) {
        closeCamera()
    }
}

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

חישוב של sourceRectHint למעברים חלקים

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

val previewView = findViewById<View>(R.id.preview_view)
val globalRect = Rect()
// Ensure the view is laid out before calling getGlobalVisibleRect() to get valid screen coordinates.
previewView.getGlobalVisibleRect(globalRect)
val params = PictureInPictureParams.Builder()
    .setSourceRectHint(globalRect)
    .build()
setPictureInPictureParams(params)

שיקולים נוספים

יכול להיות שהתכונה "תמונה בתוך תמונה" מושבתת במכשירים עם זיכרון RAM קטן. לפני שהאפליקציה משתמשת ב-PiP, צריך לוודא שהתכונה זמינה באמצעות קריאה ל-hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE).

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

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

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

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

עוד קוד לדוגמה

כדי להוריד אפליקציה לדוגמה שכתובה ב-Kotlin, עיינו במאמר Android PictureInPicture Sample (Kotlin)‎.