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

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

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

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

تشغيل تطبيقك في وضع "نافذة ضمن النافذة"

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

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

التعاون مع التطبيقات التي يتم تشغيلها في وضع "نافذة ضمن النافذة"

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

الاحتفاظ بواجهات برمجة التطبيقات الواضحة

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

Keep-واضح

لتحديد عدم تركيب الملف الشخصي، استخدِم 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" />