تعدد المهام على التلفزيون

يقدّم الإصدار 14 من نظام التشغيل Android (المستوى 34 لواجهة برمجة التطبيقات) بعض التحسينات على واجهات برمجة التطبيقات الخاصة بميزة صورة في صورة (PiP) للسماح بتعدد المهام. على الرغم من أنّه تم توفير ميزة "وضع الصورة في الصورة" في الإصدار 8.0 من Android (المستوى 26 من واجهة برمجة التطبيقات)، لم تكن متاحة على نطاق واسع في Android TV، ولم تكن متاحة على الإطلاق في Google TV قبل الإصدار 13 من Android. تستخدم ميزة "تعدد المهام على التلفزيون" وضع "نافذة ضمن النافذة" للسماح لتطبيقَين مختلفَين بالظهور على الشاشة في الوقت نفسه: أحدهما يعمل في وضع ملء الشاشة والآخر في وضع "نافذة ضمن النافذة". هناك متطلبات مختلفة للتطبيقات التي تعمل في أي من هذين الوضعَين.

السلوك التلقائي هو أنّ تطبيق "نافذة ضمن النافذة" يتراكب على التطبيق المعروض في وضع ملء الشاشة. ويشبه ذلك السلوك العادي لميزة "نافذة ضمن النافذة" على Android.

يُرجى العلم أنّه عند دمج ميزة "تعدد المهام"، يجب أن يوضّح تطبيقك أنواع الاستخدام في التوافق مع إرشادات جودة تطبيقات Android TV.

تشغيل تطبيقك في وضع "صورة في صورة"

بالنسبة إلى أجهزة التلفزيون التي تعمل بالإصدار 14 من نظام التشغيل Android (المستوى 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. بالإضافة إلى ذلك، عند بدء الإجراء، يتم ضبط نسبتَي العرض إلى الارتفاع في وضع "نافذة ضمن النافذة" لتتطابق مع نسبة العرض إلى الارتفاع في الفيديو الذي يتم تشغيله.

احرص على إضافة عنوان وعنوان فرعي لتزويد المستخدم بمعلومات حول الغرض من استخدام وضع "صورة في صورة" هذا بشكل عام.

التوافق مع التطبيقات التي تعمل في وضع "صورة في صورة"

عندما يكون تطبيقك قيد التشغيل على الشاشة الكاملة، قد يحتاج إلى التكيف مع التطبيقات الأخرى التي تعمل في وضع "نافذة داخل النافذة".

واجهات برمجة التطبيقات لميزة "إبقاء المسار خاليًا"

في بعض الحالات، قد يتراكب تطبيق وضع الصورة في الصورة على مكونات واجهة مستخدِم مهمة في التطبيق المعروض على الشاشة الكاملة. للحدّ من حدوث ذلك، تتوفّر واجهات برمجة تطبيقات للحفاظ على الوضوح يمكن للتطبيقات استخدامها لتحديد مكونات واجهة مستخدِم مهمة يجب عدم تداخلها. يحاول النظام تنفيذ الطلبات لتجنّب حجب هذه المكوّنات من خلال إعادة وضع نافذة وضع الصورة في الصورة.

Keep-Clear

لتحديد أنّه لا يجب تراكب عرض معيّن، استخدِم 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، على أقسام فرعية تحتاج إلى إبقاء المناطق خالية. يمكن استخدام واجهة برمجة التطبيقات هذه في هذه الحالات.

أنواع الاستخدام

يجب أن يُعلن تطبيقك عن سمة قيمة البيانات الوصفية 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" />