دعم العرض

تنظيم صفحاتك في مجموعات يمكنك حفظ المحتوى وتصنيفه حسب إعداداتك المفضّلة.

يتم توفير التحديثات التي تم إجراؤها على هذه المناطق الخاصة بالعرض أدناه:

تغيير حجم الأنشطة والعروض

للإشارة إلى أن التطبيق قد لا يدعم وضع النوافذ المتعددة أو تغيير الحجم ، تستخدم الأنشطة resizeableActivity=false . تتضمن المشكلات الشائعة التي تواجهها التطبيقات عند تغيير حجم الأنشطة ما يلي:

  • يمكن أن يكون للنشاط تكوين مختلف عن التطبيق أو مكون آخر غير مرئي. من الأخطاء الشائعة قراءة مقاييس العرض من سياق التطبيق. لن يتم تعديل القيم التي تم إرجاعها إلى مقاييس المنطقة المرئية التي يتم فيها عرض النشاط.
  • قد لا يعالج النشاط تغيير الحجم والتعطل ، أو يعرض واجهة مستخدم مشوهة ، أو يفقد الحالة بسبب إعادة التشغيل دون حفظ حالة المثيل.
  • قد يحاول التطبيق استخدام إحداثيات الإدخال المطلقة (بدلاً من تلك المتعلقة بموضع النافذة) ، مما قد يؤدي إلى كسر الإدخال في النوافذ المتعددة.

في نظام Android 7 (والإصدارات الأحدث) ، يمكن تعيين تطبيق يمكن resizeableActivity=false للتشغيل دائمًا في وضع ملء الشاشة. في هذه الحالة ، يمنع النظام الأساسي الأنشطة التي لا يمكن تغيير حجمها من الانتقال إلى شاشة مقسمة. إذا حاول المستخدم استدعاء نشاط غير قابل لتغيير الحجم من المشغل أثناء وجوده بالفعل في وضع تقسيم الشاشة ، فإن النظام الأساسي يخرج من وضع تقسيم الشاشة ويبدأ النشاط غير القابل لتغيير الحجم في وضع ملء الشاشة.

يجب عدم تشغيل التطبيقات التي تعيّن هذه السمة صراحةً على " false " في البيان في وضع النوافذ المتعددة ، ما لم يتم تطبيق وضع التوافق:

  • يتم تطبيق نفس التكوين على العملية ، والتي تحتوي على كافة الأنشطة والمكونات غير المتعلقة بالنشاط.
  • يفي التكوين المطبق بمتطلبات CDD لشاشات العرض المتوافقة مع التطبيق.

في Android 10 ، لا يزال النظام الأساسي يمنع الأنشطة غير القابلة لتغيير الحجم من الدخول في وضع تقسيم الشاشة ، ولكن يمكن تغيير حجمها مؤقتًا إذا أعلن النشاط عن اتجاه ثابت أو نسبة عرض إلى ارتفاع. إذا لم يكن الأمر كذلك ، فسيتم تغيير حجم النشاط لملء الشاشة بالكامل كما هو الحال في Android 9 والإصدارات الأقدم.

يطبق التطبيق الافتراضي السياسة التالية:

عندما يُعلن أن نشاطًا ما غير متوافق مع النوافذ المتعددة من خلال استخدام سمة android:resizeableActivity وعندما يفي هذا النشاط بأحد الشروط الموضحة أدناه ، فعندما يجب تغيير تكوين الشاشة المطبق ، يتم حفظ النشاط والعملية بالتكوين الأصلي ويتم تزويد المستخدم بميزة إعادة تشغيل عملية التطبيق لاستخدام تكوين الشاشة المحدث.

  • هو اتجاه ثابت عبر تطبيق android:screenOrientation
  • يحتوي التطبيق على حد أقصى أو أدنى افتراضي لنسبة العرض إلى الارتفاع من خلال استهداف مستوى واجهة برمجة التطبيقات أو الإعلان عن نسبة العرض إلى الارتفاع صراحة

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

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

عندما لا يتم تعيين resizeableActivity (أو تم تعيينه على true ) ، فإن التطبيق يدعم تغيير الحجم بشكل كامل.

تطبيق

يسمى النشاط غير القابل لتغيير الحجم ذي الاتجاه الثابت أو نسبة العرض إلى الارتفاع بوضع توافق الحجم (SCM) في التعليمات البرمجية. تم تعريف الشرط في ActivityRecord#shouldUseSizeCompatMode() . عند بدء نشاط SCM ، يتم إصلاح التكوين المرتبط بالشاشة (مثل الحجم أو الكثافة) في تكوين التجاوز المطلوب ، وبالتالي لم يعد النشاط يعتمد على تكوين العرض الحالي.

إذا لم يتمكن نشاط SCM من ملء الشاشة بالكامل ، فسيتم محاذاته لأعلى وتوسيطه أفقيًا. يتم حساب حدود النشاط بواسطة AppWindowToken#calculateCompatBoundsTransformation() .

عندما يستخدم نشاط SCM تكوين شاشة مختلفًا عن حاويته (على سبيل المثال ، يتم تغيير حجم العرض أو نقل النشاط إلى شاشة أخرى) ، ActivityRecord#inSizeCompatMode() صحيحًا ويتلقى SizeCompatModeActivityController (في System UI) رد الاتصال لإظهار العملية زر إعادة التشغيل.

أحجام العرض ونسب العرض إلى الارتفاع

يوفر Android 10 دعمًا لنسب عرض إلى ارتفاع جديدة من النسب العالية للشاشات الطويلة والرقيقة إلى نسب 1: 1. يمكن للتطبيقات تحديد ApplicationInfo#maxAspectRatio و ApplicationInfo#minAspectRatio للشاشة التي يمكنهم التعامل معها.

نسب التطبيق في Android 10

الشكل 1. مثال على نسب التطبيق المدعومة في Android 10

يمكن أن تحتوي تطبيقات الجهاز على شاشات ثانوية بأحجام ودرجات دقة أصغر من تلك المطلوبة بواسطة Android 9 ، وأقل (عرض أو ارتفاع 2.5 بوصة كحد أدنى ، 320 نقطة لكل بوصة smallestScreenWidth عرض للشاشة الصغيرة) ، ولكن يمكن فقط للأنشطة التي تم تمكينها لدعم هذه الشاشات الصغيرة وضعت هناك.

يمكن للتطبيقات الاشتراك من خلال الإعلان عن حد أدنى للحجم المدعوم أصغر من oe يساوي حجم العرض المستهدف. استخدم android:minHeight و android:minWidth في AndroidManifest للقيام بذلك.

عرض السياسات

يفصل Android 10 وينقل سياسات عرض معينة من تنفيذ WindowManagerPolicy الافتراضي في PhoneWindowManager إلى فئات لكل شاشة ، مثل:

  • عرض الحالة والتناوب
  • بعض المفاتيح وتتبع أحداث الحركة
  • نظام واجهة المستخدم ونوافذ الزخرفة

في Android 9 (والإصدارات الأقدم) ، تعاملت فئة PhoneWindowManager مع سياسات العرض والحالة والإعدادات والدوران وتتبع إطار نافذة الزخرفة والمزيد. ينقل Android 10 معظم هذا إلى فئة DisplayPolicy ، باستثناء تتبع التدوير ، الذي تم نقله إلى DisplayRotation .

عرض إعدادات النافذة

في Android 10 ، تم توسيع إعداد النوافذ القابل للتكوين لكل شاشة ليشمل:

  • الوضع الافتراضي لعرض النوافذ
  • قيم overcan
  • تناوب المستخدم ووضع التناوب
  • الحجم والكثافة والقياس القسري
  • وضع إزالة المحتوى (عند إزالة العرض)
  • دعم زخارف النظام ومحرر أسلوب الإدخال (IME)

تحتوي فئة DisplayWindowSettings على إعدادات هذه الخيارات. يتم إصرارها على القرص في قسم /data في display_settings.xml في كل مرة يتم فيها تغيير أحد الإعدادات. للحصول على تفاصيل ، راجع DisplayWindowSettings.AtomicFileStorage و DisplayWindowSettings#writeSettings() . يمكن للشركات المصنعة للأجهزة توفير القيم الافتراضية في display_settings.xml لتهيئة أجهزتهم. ومع ذلك ، نظرًا لأنه يتم تخزين الملف في /data ، فقد تكون هناك حاجة إلى منطق إضافي لاستعادة الملف إذا تم مسحه بواسطة المسح.

بشكل افتراضي ، يستخدم Android 10 DisplayInfo#uniqueId للعرض عند استمرار الإعدادات. يجب ملء uniqueId لجميع شاشات العرض. بالإضافة إلى ذلك ، فهو مستقر للشاشات المادية والشبكات. من الممكن أيضًا استخدام منفذ العرض المادي كمعرف ، والذي يمكن تعيينه في DisplayWindowSettings#mIdentifier . عند كل عملية كتابة ، تتم كتابة جميع الإعدادات بحيث يكون من الآمن تحديث المفتاح المستخدم لإدخال العرض في التخزين. للحصول على التفاصيل ، راجع معرّفات العرض الثابتة .

استمرت الإعدادات في دليل /data لأسباب تاريخية. في الأصل ، تم استخدامها للاحتفاظ بالإعدادات التي يحددها المستخدم ، مثل تدوير العرض.

معرّفات العرض الثابتة

لم يوفر Android 9 (والإصدارات الأقدم) معرّفات ثابتة لشاشات العرض في إطار العمل. عند إضافة عرض إلى النظام ، تم إنشاء Display#mDisplayId أو DisplayInfo#displayId لهذا العرض عن طريق زيادة عداد ثابت. إذا أضاف النظام نفس الشاشة وأزالها ، ينتج عن ذلك معرف مختلف.

إذا كان الجهاز يحتوي على شاشات متعددة متاحة من التمهيد ، فيمكن تعيين معرفات مختلفة للشاشات ، اعتمادًا على التوقيت. بينما تضمن Android 9 (والإصدارات الأقدم) DisplayInfo#uniqueId ، إلا أنه لم يحتوي على معلومات كافية للتمييز بين شاشات العرض لأن الشاشات المادية تم تحديدها على أنها إما local:0 أو local:1 ، لتمثيل الشاشة المدمجة والخارجية.

يغير Android 10 DisplayInfo#uniqueId لإضافة معرف ثابت ولتمييز بين شاشات العرض المحلية والشبكة والظاهرية.

نوع العرض شكل
محلي
local:<stable-id>
شبكة الاتصال
network:<mac-address>
افتراضية
virtual:<package-name-and-name>

بالإضافة إلى التحديثات الخاصة بـ uniqueId ، يحتوي DisplayInfo.address على DisplayAddress ، وهو معرف عرض يكون مستقرًا عبر عمليات إعادة التشغيل. في Android 10 ، يدعم DisplayAddress العروض المادية والشبكات. يحتوي DisplayAddress.Physical على معرّف عرض ثابت (مثل معرف uniqueId ) ويمكن إنشاؤه باستخدام DisplayAddress#fromPhysicalDisplayId() .

يوفر Android 10 أيضًا طريقة مناسبة للحصول على معلومات المنفذ ( Physical#getPort() ). يمكن استخدام هذه الطريقة في إطار العمل لتحديد العروض بشكل ثابت. على سبيل المثال ، يتم استخدامه في DisplayWindowSettings ). يحتوي DisplayAddress.Network على عنوان MAC ويمكن إنشاؤه باستخدام DisplayAddress#fromMacAddress() .

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

بالنظر إلى معرّف عرض HWC (الذي يمكن أن يكون معتمًا وليس ثابتًا دائمًا) ، تُرجع هذه الطريقة رقم المنفذ 8 بت (الخاص بالمنصة) الذي يحدد موصلًا ماديًا لإخراج العرض ، بالإضافة إلى EDID blob الخاص بالشاشة. يستخرج SurfaceFlinger معلومات الشركة المصنعة أو النموذج من EDID لإنشاء معرّفات عرض 64 بت مستقرة معرّضة لإطار العمل. إذا لم تكن هذه الطريقة مدعومة أو تم حل الأخطاء ، فإن SurfaceFlinger يعود إلى وضع MD القديم ، حيث DisplayInfo#address فارغًا ويكون DisplayInfo#uniqueId بشكل ثابت ، كما هو موضح أعلاه.

للتحقق من دعم هذه الميزة ، قم بتشغيل:

$ dumpsys SurfaceFlinger --display-id
# Example output.
Display 21691504607621632 (HWC display 0): port=0 pnpId=SHP displayName="LQ123P1JX32"
Display 9834494747159041 (HWC display 2): port=1 pnpId=HWP displayName="HP Z24i"
Display 1886279400700944 (HWC display 1): port=2 pnpId=AUS displayName="ASUS MB16AP"

باستخدام أكثر من شاشتين

في Android 9 (والإصدارات الأقدم) ، افترض SurfaceFlinger و DisplayManagerService وجود شاشتين فعليتين على الأكثر مع معرفات مشفرة 0 و 1.

بدءًا من Android 10 ، يمكن لـ SurfaceFlinger الاستفادة من واجهة برمجة تطبيقات مؤلف الأجهزة (HWC) لإنشاء معرّفات عرض ثابتة ، مما يمكّنه من إدارة عدد تعسفي من العروض المادية. لمعرفة المزيد ، راجع معرّفات العرض الثابتة .

يمكن لإطار العمل البحث عن رمز IBinder للعرض المادي من خلال SurfaceControl#getPhysicalDisplayToken بعد الحصول على معرف العرض 64 بت من SurfaceControl#getPhysicalDisplayIds أو من حدث DisplayEventReceiver hotplug.

في Android 10 (والإصدارات الأقدم) ، تكون الشاشة الداخلية الأساسية TYPE_INTERNAL ويتم تمييز جميع شاشات العرض الثانوية على أنها TYPE_EXTERNAL بغض النظر عن نوع الاتصال. لذلك ، يتم التعامل مع شاشات العرض الداخلية الإضافية على أنها خارجية. كحل بديل ، يمكن أن تضع التعليمات البرمجية الخاصة بالجهاز افتراضات حول DisplayAddress.Physical#getPort إذا كان HWC معروفًا وكان منطق تخصيص المنفذ متوقعًا.

تمت إزالة هذا القيد في Android 11 (والإصدارات الأحدث).

  • في Android 11 ، تكون الشاشة الأولى التي تم الإبلاغ عنها أثناء التمهيد هي الشاشة الأساسية. نوع الاتصال (داخلي مقابل خارجي) غير ذي صلة. ومع ذلك ، يظل صحيحًا أنه لا يمكن فصل الشاشة الأساسية ويترتب على ذلك أنه يجب أن يكون عرضًا داخليًا في الممارسة العملية. لاحظ أن بعض الهواتف القابلة للطي بها شاشات عرض داخلية متعددة.
  • يتم تصنيف شاشات العرض الثانوية بشكل صحيح على أنها Display.TYPE_INTERNAL أو Display.TYPE_EXTERNAL (المعروفة سابقًا باسم Display.TYPE_BUILT_IN و Display.TYPE_HDMI ، على التوالي) اعتمادًا على نوع الاتصال الخاص بها.

تطبيق

في نظام التشغيل Android 9 والإصدارات الأقدم ، يتم تحديد الشاشات بمعرفات 32 بت ، حيث يمثل 0 شاشة العرض الداخلية ، و 1 هو شاشة العرض الخارجية ، [2, INT32_MAX] هي شاشات عرض افتراضية HWC ، ويمثل -1 شاشة عرض غير صالحة أو غير HWC شاشة افتراضية.

بدءًا من Android 10 ، يتم منح الشاشات معرفات ثابتة ودائمة ، مما يسمح لـ SurfaceFlinger و DisplayManagerService بتتبع أكثر من شاشتين والتعرف على شاشات العرض التي سبق رؤيتها. إذا كان HWC يدعم IComposerClient.getDisplayIdentificationData ويوفر بيانات تعريف العرض ، يوزع SurfaceFlinger بنية EDID ويخصص معرّفات عرض 64 بت ثابتة لشاشات العرض الافتراضية الفعلية و HWC. يتم التعبير عن المعرفات باستخدام نوع الخيار ، حيث تمثل القيمة الخالية عرضًا غير صالح أو عرض افتراضي غير HWC. بدون دعم HWC ، يعود SurfaceFlinger إلى السلوك القديم مع شاشتين ماديتين على الأكثر.

التركيز لكل شاشة

لدعم العديد من مصادر الإدخال التي تستهدف شاشات العرض الفردية في نفس الوقت ، يمكن تكوين Android 10 لدعم العديد من النوافذ المركزة ، واحدة على الأكثر لكل شاشة. هذا مخصص فقط لأنواع خاصة من الأجهزة عندما يتفاعل عدة مستخدمين مع نفس الجهاز في نفس الوقت ويستخدمون أساليب أو أجهزة إدخال مختلفة ، مثل Android Automotive.

يوصى بشدة بعدم تمكين هذه الميزة للأجهزة العادية ، بما في ذلك الأجهزة متعددة الشاشات أو تلك المستخدمة في التجارب الشبيهة بسطح المكتب. هذا يرجع في المقام الأول إلى مخاوف أمنية قد تجعل المستخدمين يتساءلون عن النافذة التي تركز على الإدخال.

تخيل المستخدم الذي يقوم بإدخال معلومات آمنة في حقل إدخال النص ، وربما يقوم بتسجيل الدخول إلى تطبيق مصرفي أو إدخال نص يحتوي على معلومات حساسة. يمكن أن ينشئ تطبيق ضار عرضًا افتراضيًا خارج الشاشة يمكن من خلاله تنفيذ نشاط ما ، وأيضًا باستخدام حقل إدخال نص. يتم التركيز على الأنشطة المشروعة والخبيثة ويعرض كلاهما مؤشر إدخال نشط (مؤشر وامض).

ومع ذلك ، نظرًا لإدخال الإدخال من لوحة المفاتيح (الأجهزة أو البرامج) في النشاط الأعلى فقط (هذا التطبيق الذي تم إطلاقه مؤخرًا) ، من خلال إنشاء شاشة افتراضية مخفية ، يمكن لتطبيق ضار الحصول على مدخلات المستخدم ، حتى عند استخدام لوحة مفاتيح برمجية على شاشة الجهاز الأساسي.

استخدم com.android.internal.R.bool.config_perDisplayFocusEnabled لتعيين التركيز لكل شاشة.

التوافق

المشكلة: في نظام Android 9 والإصدارات الأقدم ، يتم التركيز على نافذة واحدة على الأكثر في كل مرة.

الحل: في الحالة النادرة التي يتم فيها التركيز على نافذتين من نفس العملية ، يوفر النظام التركيز فقط على النافذة الأعلى في الترتيب Z. تمت إزالة هذا التقييد للتطبيقات التي تستهدف Android 10 ، وعند هذه النقطة من المتوقع أن تتمكن من دعم العديد من النوافذ التي يتم التركيز عليها في وقت واحد.

تطبيق

WindowManagerService#mPerDisplayFocusEnabled يتحكم في توفر هذه الميزة. في ActivityManager ، يتم الآن استخدام ActivityDisplay#getFocusedStack() بدلاً من التتبع العام في متغير. ActivityDisplay#getFocusedStack() التركيز بناءً على ترتيب Z بدلاً من تخزين القيمة مؤقتًا. هذا بحيث يحتاج مصدر واحد فقط ، هو WindowManager ، إلى تتبع ترتيب Z للأنشطة.

ActivityStackSupervisor#getTopDisplayFocusedStack() يتبع نهجًا مشابهًا لتلك الحالات التي يجب فيها تحديد المكدس الأعلى تركيزًا في النظام. يتم عبور الكدسات من أعلى إلى أسفل ، بحثًا عن أول مكدس مؤهل.

يمكن أن InputDispatcher الآن على عدة نوافذ مركزة (واحدة لكل شاشة). إذا كان حدث الإدخال خاصًا بالعرض ، فسيتم إرساله إلى النافذة المركزة في الشاشة المقابلة. بخلاف ذلك ، يتم إرساله إلى النافذة المركزة في الشاشة المركزة ، وهي الشاشة التي تفاعل معها المستخدم مؤخرًا.

راجع InputDispatcher::mFocusedWindowHandlesByDisplay و InputDispatcher::setFocusedDisplay() . يتم أيضًا تحديث التطبيقات المركزة بشكل منفصل في InputManagerService من خلال NativeInputManager::setFocusedApplication() .

في WindowManager ، يتم أيضًا تتبع النوافذ المركزة بشكل منفصل. راجع DisplayContent#mCurrentFocus و DisplayContent#mFocusedApp والاستخدامات ذات الصلة. تم نقل أساليب تتبع التركيز والتحديث ذات الصلة من WindowManagerService إلى DisplayContent .