پشتیبانی از نمایش

به روز رسانی های انجام شده در این مناطق ویژه نمایشگر در زیر ارائه شده است:

تغییر اندازه فعالیت ها و نمایشگرها

برای نشان دادن اینکه یک برنامه ممکن است حالت چند پنجره ای یا تغییر اندازه را پشتیبانی نکند، فعالیت ها از ویژگی resizeableActivity=false استفاده می کنند. مشکلات رایجی که برنامه‌ها هنگام تغییر اندازه فعالیت‌ها با آن مواجه می‌شوند عبارتند از:

  • یک فعالیت می‌تواند پیکربندی متفاوتی از برنامه یا مؤلفه غیربصری دیگر داشته باشد. یک اشتباه رایج این است که معیارهای نمایش را از متن برنامه بخوانید. مقادیر برگشتی با معیارهای منطقه قابل مشاهده که در آن یک فعالیت نمایش داده می شود، تنظیم نمی شود.
  • ممکن است یک اکتیویتی با تغییر اندازه و خرابی، نمایش رابط کاربری تحریف شده یا از دست دادن حالت به دلیل راه‌اندازی مجدد بدون ذخیره حالت نمونه، کار نکند.
  • یک برنامه ممکن است سعی کند از مختصات ورودی مطلق استفاده کند (به جای مختصات مربوط به موقعیت پنجره)، که ممکن است ورودی را در چند پنجره شکست دهد.

در اندروید 7 (و بالاتر)، یک برنامه را می توان resizeableActivity=false تنظیم کرد تا همیشه در حالت تمام صفحه اجرا شود. در این حالت، پلتفرم از ورود فعالیت های غیرقابل تغییر اندازه به صفحه نمایش تقسیم شده جلوگیری می کند. اگر کاربر سعی کند یک فعالیت غیرقابل تغییر اندازه را از راه‌انداز در حالی که قبلاً در حالت تقسیم صفحه است فراخوانی کند، پلتفرم از حالت تقسیم صفحه خارج شده و فعالیت غیرقابل تغییر اندازه را در حالت تمام صفحه راه‌اندازی می‌کند.

برنامه‌هایی که صراحتاً این ویژگی را در مانیفست روی false تنظیم می‌کنند، نباید در حالت چند پنجره‌ای راه‌اندازی شوند، مگر اینکه حالت سازگاری اعمال شود:

  • پیکربندی مشابهی برای فرآیند اعمال می‌شود که شامل تمام فعالیت‌ها و اجزای غیرفعالیتی است.
  • پیکربندی کاربردی الزامات CDD را برای نمایشگرهای سازگار با برنامه برآورده می کند.

در اندروید 10، این پلتفرم همچنان از رفتن به حالت تقسیم صفحه نمایش فعالیت‌های غیرقابل تغییر اندازه جلوگیری می‌کند، اما اگر فعالیت دارای جهت یا نسبت تصویر ثابتی باشد، می‌توان آن‌ها را به‌طور موقت مقیاس‌بندی کرد. در غیر این صورت، اندازه فعالیت تغییر می کند تا کل صفحه مانند اندروید 9 و پایین تر را پر کند.

اجرای پیش فرض سیاست زیر را اعمال می کند:

هنگامی که فعالیتی با استفاده از ویژگی android:resizeableActivity با چند پنجره ناسازگار اعلام می شود و زمانی که آن فعالیت یکی از شرایط شرح داده شده در زیر را برآورده می کند، هنگامی که پیکربندی صفحه اعمال شده باید تغییر کند، فعالیت و فرآیند با پیکربندی اصلی ذخیره می شوند. و به کاربر امکان راه اندازی مجدد فرآیند برنامه برای استفاده از پیکربندی صفحه به روز شده داده می شود.

  • جهت گیری از طریق برنامه android:screenOrientation ثابت شده است
  • با هدف قرار دادن سطح API یا اعلام صریح نسبت ابعاد، برنامه دارای حداکثر یا حداقل نسبت ابعاد پیش‌فرض است.

این شکل یک فعالیت غیرقابل تغییر اندازه را با نسبت ابعادی اعلام شده نشان می دهد. هنگام تا کردن دستگاه، پنجره کوچک می‌شود تا متناسب با ناحیه باشد و در عین حال نسبت تصویر را با استفاده از جعبه نامه مناسب حفظ می‌کند. علاوه بر این، هر بار که ناحیه نمایش فعالیت تغییر می‌کند، یک گزینه شروع مجدد فعالیت در اختیار کاربر قرار می‌گیرد.

هنگام باز کردن دستگاه، پیکربندی، اندازه و نسبت ابعاد فعالیت تغییر نمی‌کند، اما گزینه راه‌اندازی مجدد فعالیت نمایش داده می‌شود.

وقتی resizeableActivity تنظیم نشده باشد (یا روی true تنظیم شده باشد)، برنامه به طور کامل از تغییر اندازه پشتیبانی می کند.

پیاده سازی

یک فعالیت غیرقابل تغییر اندازه با جهت یا نسبت ابعاد ثابت در کد حالت سازگاری اندازه (SCM) نامیده می شود. این شرط در ActivityRecord#shouldUseSizeCompatMode() تعریف شده است. هنگامی که یک فعالیت SCM راه اندازی می شود، پیکربندی مربوط به صفحه (مانند اندازه یا تراکم) در پیکربندی لغو درخواستی ثابت می شود، بنابراین فعالیت دیگر به پیکربندی نمایش فعلی وابسته نیست.

اگر فعالیت SCM نتواند کل صفحه را پر کند، در بالا تراز و در مرکز افقی قرار می گیرد. محدوده فعالیت توسط AppWindowToken#calculateCompatBoundsTransformation() محاسبه می شود.

هنگامی که یک فعالیت SCM از پیکربندی صفحه متفاوتی نسبت به محفظه خود استفاده می کند (به عنوان مثال، اندازه نمایشگر تغییر می کند یا فعالیت به نمایشگر دیگری منتقل می شود)، ActivityRecord#inSizeCompatMode() true است و SizeCompatModeActivityController (در System UI) برای نشان دادن فرآیند، پاسخ تماس را دریافت می کند. دکمه راه اندازی مجدد

اندازه و نسبت ابعاد نمایشگر

اندروید 10 از نسبت ابعاد جدید از نسبت بالای صفحه نمایش بلند و نازک تا نسبت 1:1 پشتیبانی می کند. برنامه‌ها می‌توانند ApplicationInfo#maxAspectRatio و ApplicationInfo#minAspectRatio صفحه‌نمایش را که قادر به مدیریت آن هستند، تعریف کنند.

نسبت برنامه ها در اندروید 10

شکل 1. نمونه نسبت برنامه های پشتیبانی شده در اندروید 10

پیاده‌سازی‌های دستگاه می‌توانند نمایشگرهای ثانویه با اندازه‌ها و رزولوشن‌های کوچک‌تر از آنچه در Android 9 مورد نیاز است، و کمتر (حداقل عرض یا ارتفاع 2.5 اینچ، حداقل 320 DP برای smallestScreenWidth ) داشته باشند، اما فقط فعالیت‌هایی که از این نمایشگرهای کوچک پشتیبانی می‌کنند، می‌توانند باشند. در آنجا قرار داده شده است.

برنامه‌ها می‌توانند با اعلام حداقل اندازه پشتیبانی شده که کوچک‌تر از oe برابر با اندازه نمایش هدف است، شرکت کنند. برای این کار از ویژگی‌های طرح‌بندی فعالیت android:minHeight و android:minWidth در AndroidManifest استفاده کنید.

سیاست های نمایش

Android 10 برخی از سیاست‌های نمایشگر را از اجرای پیش‌فرض WindowManagerPolicy در PhoneWindowManager به کلاس‌های هر نمایشگر جدا کرده و منتقل می‌کند، مانند:

  • نمایش وضعیت و چرخش
  • برخی از کلیدها و ردیابی رویداد حرکت
  • رابط کاربری سیستم و پنجره های دکوراسیون

در اندروید 9 (و پایین تر)، کلاس PhoneWindowManager سیاست های نمایش، وضعیت و تنظیمات، چرخش، ردیابی قاب پنجره دکوراسیون و موارد دیگر را مدیریت می کند. اندروید 10 بیشتر این موارد را به کلاس DisplayPolicy منتقل می کند، به جز ردیابی چرخش، که به DisplayRotation منتقل شده است.

نمایش تنظیمات پنجره

در اندروید 10، تنظیمات پنجره قابل تنظیم برای هر نمایشگر گسترش یافته است تا شامل موارد زیر باشد:

  • حالت پنجره نمایش پیش فرض
  • مقادیر Overscan
  • چرخش کاربر و حالت چرخش
  • اندازه اجباری، چگالی، و حالت پوسته پوسته شدن
  • حالت حذف محتوا (زمانی که نمایشگر حذف می شود)
  • پشتیبانی از تزئینات سیستم و IME

کلاس DisplayWindowSettings شامل تنظیماتی برای این گزینه ها است. هر بار که یک تنظیم تغییر می کند، آنها در پارتیشن /data در display_settings.xml دیسک می شوند. برای جزئیات، به DisplayWindowSettings.AtomicFileStorage و DisplayWindowSettings#writeSettings() مراجعه کنید. سازندگان دستگاه می توانند مقادیر پیش فرض را در display_settings.xml برای پیکربندی دستگاه خود ارائه دهند. با این حال، از آنجایی که فایل در /data ذخیره می شود، ممکن است منطق اضافی برای بازیابی فایل در صورت پاک شدن با پاک کردن نیاز باشد.

به‌طور پیش‌فرض، Android 10 از DisplayInfo#uniqueId به‌عنوان شناسه نمایشگر هنگام ادامه تنظیمات استفاده می‌کند. uniqueId باید برای همه نمایشگرها پر شود. علاوه بر این، برای نمایشگرهای فیزیکی و شبکه پایدار است. همچنین می توان از پورت یک نمایشگر فیزیکی به عنوان شناسه استفاده کرد که می تواند در DisplayWindowSettings#mIdentifier تنظیم شود. پس از هر نوشتن، همه تنظیمات نوشته می‌شوند، بنابراین می‌توان کلیدی را که برای ورودی نمایشگر در فضای ذخیره‌سازی استفاده می‌شود، به‌روزرسانی کرد. برای جزئیات، به شناسه های نمایشگر استاتیک مراجعه کنید.

تنظیمات به دلایل تاریخی در فهرست /data باقی می مانند. در اصل، از آنها برای تداوم تنظیمات تنظیم شده توسط کاربر، مانند چرخش نمایشگر استفاده می شد.

شناسه های صفحه نمایش استاتیک

اندروید 9 (و پایین تر) شناسه های پایداری برای نمایشگرها در چارچوب ارائه نمی کند. هنگامی که یک نمایشگر به سیستم اضافه شد، Display#mDisplayId یا DisplayInfo#displayId با افزایش یک شمارنده استاتیک برای آن نمایشگر تولید شد. اگر سیستم همان نمایشگر را اضافه و حذف کند، شناسه متفاوتی حاصل می‌شود.

اگر دستگاهی دارای چندین نمایشگر از راه‌اندازی بود، بسته به زمان، می‌توان به نمایشگرها شناسه‌های مختلفی اختصاص داد. در حالی که اندروید 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 است، یک شناسه نمایشگر که در هنگام راه‌اندازی مجدد پایدار است. در اندروید 10، DisplayAddress از نمایشگرهای فیزیکی و شبکه پشتیبانی می کند. DisplayAddress.Physical حاوی یک شناسه نمایش پایدار (همانند در uniqueId ) است و می تواند با DisplayAddress#fromPhysicalDisplayId() ایجاد شود.

اندروید 10 همچنین روشی مناسب برای دریافت اطلاعات پورت ( Physical#getPort() ) ارائه می‌کند. این روش را می توان در چارچوب برای شناسایی ایستا نمایشگرها استفاده کرد. به عنوان مثال، در DisplayWindowSettings استفاده می شود. DisplayAddress.Network حاوی آدرس MAC است و می تواند با DisplayAddress#fromMacAddress() ایجاد شود.

این افزودنی‌ها به سازندگان دستگاه اجازه می‌دهد نمایشگرها را در تنظیمات چند صفحه‌نمایش ثابت شناسایی کنند و تنظیمات و ویژگی‌های مختلف سیستم را با استفاده از شناسه‌های نمایشگر ثابت، مانند پورت‌های نمایشگرهای فیزیکی، پیکربندی کنند. این روش‌ها پنهان هستند و فقط برای استفاده در system_server در نظر گرفته شده‌اند.

با توجه به شناسه نمایشگر HWC (که می تواند مات باشد و همیشه پایدار نیست)، این روش شماره پورت 8 بیتی (ویژه پلتفرم) را برمی گرداند که یک رابط فیزیکی برای خروجی نمایشگر و همچنین لکه EDID نمایشگر را مشخص می کند. 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"

از بیش از دو نمایشگر استفاده کنید

در اندروید 9 (و پایین‌تر)، SurfaceFlinger و DisplayManagerService حداکثر دو نمایشگر فیزیکی با شناسه‌های کد سخت 0 و 1 را فرض کردند.

با شروع اندروید 10، SurfaceFlinger می‌تواند از API سخت‌افزار Composer (HWC) برای تولید شناسه‌های نمایشگر پایدار استفاده کند که به آن امکان می‌دهد تعداد دلخواه نمایش‌های فیزیکی را مدیریت کند. برای کسب اطلاعات بیشتر، به شناسه های نمایشگر استاتیک مراجعه کنید.

این فریم ورک می‌تواند رمز IBinder را برای نمایش فیزیکی از طریق SurfaceControl#getPhysicalDisplayToken پس از دریافت شناسه نمایشگر 64 بیتی از SurfaceControl#getPhysicalDisplayIds یا از یک رویداد hotplug DisplayEventReceiver جستجو کند.

در Android 10 (و پایین تر)، صفحه نمایش داخلی اصلی TYPE_INTERNAL است و همه نمایشگرهای ثانویه بدون در نظر گرفتن نوع اتصال به عنوان TYPE_EXTERNAL علامت گذاری می شوند. بنابراین، نمایشگرهای داخلی اضافی به عنوان خارجی در نظر گرفته می شوند. به عنوان یک راه حل، اگر HWC شناخته شده باشد و منطق تخصیص پورت قابل پیش بینی باشد، کد مخصوص دستگاه می تواند در مورد DisplayAddress.Physical#getPort مفروضاتی ایجاد کند.

این محدودیت در اندروید 11 (و بالاتر) حذف شده است.

  • در اندروید 11، اولین نمایشگر گزارش شده در هنگام بوت، نمایشگر اصلی است. نوع اتصال (داخلی در مقابل خارجی) بی ربط است. با این حال، درست است که صفحه نمایش اصلی را نمی توان قطع کرد و به این ترتیب که در عمل باید نمایشگر داخلی باشد. توجه داشته باشید که برخی از گوشی های تاشو دارای چندین نمایشگر داخلی هستند.
  • نمایشگرهای ثانویه بسته به نوع اتصالشان به درستی به‌عنوان Display.TYPE_INTERNAL یا Display.TYPE_EXTERNAL (که قبلاً به ترتیب Display.TYPE_BUILT_IN و Display.TYPE_HDMI شناخته می‌شد) دسته‌بندی می‌شوند.

پیاده سازی

در اندروید 9 و پایین‌تر، نمایشگرها با شناسه‌های 32 بیتی شناسایی می‌شوند که 0 نمایشگر داخلی، 1 نمایشگر خارجی، [2, INT32_MAX] نمایشگرهای مجازی HWC، و -1 نمایشگر نامعتبر یا غیر HWC است. نمایش مجازی

با شروع اندروید 10، به نمایشگرها شناسه‌های پایدار و پایدار داده می‌شود که به SurfaceFlinger و DisplayManagerService اجازه می‌دهد بیش از دو نمایشگر را ردیابی کنند و نمایشگرهایی که قبلاً دیده‌شده را تشخیص دهند. اگر HWC از IComposerClient.getDisplayIdentificationData پشتیبانی می‌کند و داده‌های شناسایی نمایشگر را ارائه می‌کند، SurfaceFlinger ساختار EDID را تجزیه می‌کند و شناسه‌های نمایشگر ۶۴ بیتی پایدار را برای نمایشگرهای فیزیکی و مجازی HWC اختصاص می‌دهد. شناسه ها با استفاده از یک نوع گزینه بیان می شوند، جایی که مقدار تهی نشان دهنده یک نمایشگر نامعتبر یا نمایش مجازی غیر HWC است. بدون پشتیبانی HWC، SurfaceFlinger به رفتار قدیمی با حداکثر دو نمایشگر فیزیکی بازمی گردد.

فوکوس هر صفحه نمایش

برای پشتیبانی از چندین منبع ورودی که نمایشگرهای فردی را به طور همزمان هدف قرار می دهند، اندروید 10 را می توان طوری پیکربندی کرد که از چندین پنجره متمرکز، حداکثر یک در هر نمایشگر پشتیبانی کند. این فقط برای انواع خاصی از دستگاه‌ها در نظر گرفته شده است، زمانی که چندین کاربر به طور همزمان با یک دستگاه تعامل دارند و از روش‌ها یا دستگاه‌های ورودی متفاوتی مانند Android Automotive استفاده می‌کنند.

اکیداً توصیه می‌شود که این ویژگی برای دستگاه‌های معمولی، از جمله دستگاه‌های چند صفحه‌نما یا دستگاه‌هایی که برای تجربه‌هایی شبیه به دسکتاپ استفاده می‌شوند، فعال نشود . این در درجه اول به دلیل یک نگرانی امنیتی است که ممکن است باعث شود کاربران تعجب کنند که کدام پنجره دارای فوکوس ورودی است.

کاربری را تصور کنید که اطلاعات ایمن را در یک قسمت ورودی متن وارد می کند، شاید وارد یک برنامه بانکی شده یا متنی را وارد می کند که حاوی اطلاعات حساس است. یک برنامه مخرب می تواند یک صفحه نمایش مجازی خارج از صفحه ایجاد کند که با آن یک فعالیت را انجام دهد، همچنین با یک فیلد ورودی متن. فعالیت های مشروع و مخرب دارای فوکوس هستند و هر دو یک نشانگر ورودی فعال (مکان نما چشمک زن) را نمایش می دهند.

با این حال، از آنجایی که ورودی صفحه کلید (سخت‌افزار یا نرم‌افزار) فقط در بالاترین فعالیت (برنامه‌ای که اخیراً راه‌اندازی شده است) وارد می‌شود، با ایجاد یک نمایشگر مجازی مخفی، یک برنامه مخرب می‌تواند ورودی کاربر را حتی زمانی که از صفحه‌کلید نرم‌افزاری استفاده می‌کند، بگیرد. در صفحه نمایش دستگاه اصلی

برای تنظیم فوکوس هر نمایشگر از com.android.internal.R.bool.config_perDisplayFocusEnabled استفاده کنید.

سازگاری

مشکل: در اندروید 9 و پایین تر، حداکثر یک پنجره در سیستم هر بار فوکوس دارد.

راه‌حل: در موارد نادری که دو پنجره از یک فرآیند فوکوس می‌شوند، سیستم تنها به پنجره‌ای که در مرتبه Z بالاتر است فوکوس می‌دهد. این محدودیت برای برنامه‌هایی که اندروید 10 را هدف قرار می‌دهند برداشته می‌شود، در این مرحله انتظار می‌رود که آنها بتوانند چندین پنجره را که به طور همزمان بر روی آنها متمرکز شده‌اند پشتیبانی کنند.

پیاده سازی

WindowManagerService#mPerDisplayFocusEnabled در دسترس بودن این ویژگی را کنترل می کند. در ActivityManager ، ActivityDisplay#getFocusedStack() اکنون به جای ردیابی سراسری در یک متغیر استفاده می شود. ActivityDisplay#getFocusedStack() فوکوس را بر اساس Z-order به جای کش کردن مقدار تعیین می کند. این به این دلیل است که تنها یک منبع، WindowManager، نیاز به ردیابی ترتیب Z فعالیت‌ها دارد.

ActivityStackSupervisor#getTopDisplayFocusedStack() رویکرد مشابهی را برای مواردی که بالاترین پشته متمرکز در سیستم باید شناسایی شود، اتخاذ می کند. پشته ها از بالا به پایین طی می شوند و اولین پشته واجد شرایط را جستجو می کنند.

InputDispatcher اکنون می تواند چندین پنجره متمرکز داشته باشد (یکی در هر نمایشگر). اگر یک رویداد ورودی مختص صفحه نمایش باشد، به پنجره متمرکز در نمایشگر مربوطه ارسال می شود. در غیر این صورت، به پنجره متمرکز در صفحه نمایش متمرکز ارسال می شود، که نمایشگری است که کاربر اخیراً با آن تعامل داشته است.

InputDispatcher::mFocusedWindowHandlesByDisplay و InputDispatcher::setFocusedDisplay() را ببینید. برنامه های متمرکز نیز به طور جداگانه در InputManagerService از طریق NativeInputManager::setFocusedApplication() به روز می شوند.

در WindowManager ، پنجره های متمرکز نیز به طور جداگانه ردیابی می شوند. DisplayContent#mCurrentFocus و DisplayContent#mFocusedApp و کاربردهای مربوطه را ببینید. روش‌های ردیابی و به‌روزرسانی فوکوس مرتبط از WindowManagerService به DisplayContent منتقل شده‌اند.