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

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

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

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

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

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

דוגמה להטמעת הלוגיקה של לחצן כדי להיכנס למצב PiP:

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 הזה.

יכולת לתפקד לצד אפליקציות שפועלות במצב PiP

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

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

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

ביטול הבחירה

כדי לציין שאין ליצור שכבת-על של תצוגה, משתמשים בתו 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" />