מולטיטסקינג בטלוויזיה

ב-Android 14 (רמת API 34) יש כמה שיפורים ממשקי API של תמונה בתוך תמונה (PiP) שמאפשרים עבודה בכמה משימות בו-זמנית. בזמן 'תמונה בתוך תמונה' קיימת תמיכה ב-Android 8.0 (רמת API 26), היא לא הייתה זמינה באופן נרחב נתמך ב-Android TV ולא נתמך בכלל ב-Google TV לפני Android 13. בריבוי משימות בטלוויזיה נעשה שימוש במצב 'תמונה בתוך תמונה' כדי לאפשר אפליקציות נפרדות לקיום הפעלה אחת על המסך: אחת מהן פועלת באופן מלא והשנייה במצב 'תמונה בתוך תמונה'. יש דרישות שונות לאפליקציות שפועלות בכל אחד מהמצבים האלה.

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

שימו לב שכשמשלבים ריבוי משימות, האפליקציה צריכה להצהיר על סוגי השימוש ב: תאימות להנחיות האיכות לאפליקציות טלוויזיה.

הפעלת האפליקציה במצב 'תמונה בתוך תמונה'

במכשירי טלוויזיה עם Android 14 (רמת API 34) ואילך, צריך להריץ את האפליקציה במצב 'תמונה בתוך תמונה' באמצעות הפעלה של enterPictureInPictureMode(). התקני טלוויזיה שפועלים מוקדם יותר גרסאות של Android לא תומכות במצב 'תמונה בתוך תמונה'.

הנה דוגמה לאופן שבו יש ליישם את הלוגיקה של לחצן כדי להזין מצב 'תמונה בתוך תמונה':

Kotlin

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    pictureInPictureButton.visibility =
        if (requireActivity().packageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
            pictureInPictureButton.setOnClickListener {
                val aspectRatio = Rational(view.width, view.height)
                val params = PictureInPictureParams.Builder()
                    .setAspectRatio(aspectRatio)
                    .build()
                val result = requireActivity().enterPictureInPictureMode(params)
            }
            View.VISIBLE
        } else {
            View.GONE
        }
}

Java

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    if (requireActivity().getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
        pictureInPictureButton.setVisibility(View.VISIBLE);
        pictureInPictureButton.setOnClickListener(v -> {
            Rational aspectRatio = new Rational(view.getWidth(), view.getHeight());
            PictureInPictureParams params = new PictureInPictureParams.Builder()
                    .setAspectRatio(aspectRatio)
                    .setTitle("My Streaming App")
                    .setSubtitle("My On-Demand Content")
                    .build();
            Boolean result = requireActivity().enterPictureInPictureMode(params);
        });
    } else {
        pictureInPictureButton.setVisibility(View.GONE);
    }
}

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

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

קיום משותף עם אפליקציות שפועלות במצב 'תמונה בתוך תמונה'

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

ממשקי API ברורים

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

ביטול הבחירה

כדי לציין שאין ליצור שכבת-על של תצוגה, משתמשים בתו preferKeepClear פריסת XML כמו בדוגמה הבאה:

<TextView
    android:id="@+id/important_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:preferKeepClear="true"
    android:text="@string/app_name"/>

אפשר גם לעשות את זה באופן פרוגרמטי באמצעות setPreferKeepClear():

Kotlin

private lateinit var binding: MyLayoutBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    binding = MyLayoutBinding.inflate(layoutInflater)
    setContentView(binding.root)
    binding.importantText.isPreferKeepClear = true
}

Java

private MyLayoutBinding binding;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    binding = MyLayoutBinding.inflate(getLayoutInflater());
    setContentView(binding.getRoot());
    binding.importantText.setPreferKeepClear(true);
}

יכול להיות שיש מקרים שבהם לא צריך לשמור את כל View בבירור, אבל רק חלק ממנו. ניתן להשתמש בsetPreferKeepClearRects() כדי לציין אזורים של View שאסור להוסיף כשכבת-על. בממשקי משתמש שלא משתמשים יכול להיות שערכות מקורי של View, כמו Flutter, Jetpack Compose ו-WebView, קטעי משנה שחשוב לשמור על שפה ברורה. במקרים כאלה אפשר להשתמש ב-API הזה.

סוגי שימוש

האפליקציה צריכה להצהיר על מאפיין ערך מטא-נתונים של com.google.android.tv.pip.category שתואם לסוג הראשי או לשימוש במצב 'תמונה בתוך תמונה'. כל <activity> שהוגדר android:supportsPictureInPicture="true" צריך להצהיר על המאפיין הזה עם מהטבלה הבאה.

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

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

כמה ערכים מופרדים בקו אנכי (|). מוצרים לדוגמה:

<meta-data android:name="com.google.android.tv.pip.category" android:value="smartHome|health" />