برنامههایی برای دستگاههای تاشو و چندصفحهای
بهطورکلی، برنامهها نباید به شناسههای ایستا یا منطقی که به برخی شناسههای نمایشگر وابسته است، متکی باشند. در بیشتر موارد، برنامهها باید تغییر اندازه دهند و روی نمایشگرهای مختلف کار کنند و سیستم باید کنترل کند که برنامهها کجا قرار گیرند. بهعنوانمثال، برای ایجاد یک تجربه جدید و منحصربهفرد برای دستگاههای تاشو و راهاندازی یک برنامه ویژه روی صفحه نمایش خارجی هنگام تا شدن دستگاه.
در این حالت، SystemUI (یا یکی دیگر از اجزای سیستم) باید fold را تشخیص دهد، تعیین کند که آیا انجام یک عمل مناسب است یا خیر، و سپس activity هدف را اجرا کند و یک شناسه نمایش خارجی را به عنوان هدف اجرا مشخص کند. برنامهها نباید این عمل را تشخیص دهند یا در پاسخ به آن عملی انجام دهند و سپس اجرا را روی یک صفحه نمایش خاص انجام دهند. به عبارت دیگر، فرض نکنید که آنچه در یک دستگاه کار میکند، روی دستگاههای دیگر نیز کار خواهد کرد. به طور خلاصه، کد مختص دستگاه، پراکندگی را افزایش میدهد.
محدود کردن دسترسی به نمایشگرها
اگر پیکربندی دستگاه مستلزم محدود کردن دسترسی به یک یا چند نمایشگر باشد، توصیه میشود از پرچم Display#FLAG_PRIVATE برای تعیین خصوصی بودن چنین نمایشگرهایی استفاده شود. انجام این کار، همه را به جز مالک، از افزودن محتوا به نمایشگر محدود میکند. هرگونه تلاش برای راهاندازی یک فعالیت یا افزودن پنجره توسط هر کسی به جز مالک، منجر به یک SecurityException میشود. اگر سیستم مالک نمایشگر باشد، سیستم میتواند پنجرهها را اضافه کرده و فعالیتها را راهاندازی کند.
علاوه بر این، موجودیتهای قرار گرفته روی یک نمایشگر همیشه میتوانند به آن نمایشگر دسترسی داشته باشند. اگر مالک یک فعالیت را روی یک نمایشگر راهاندازی کند، آن فعالیت میتواند فعالیتهای دیگری را روی این نمایشگر راهاندازی کند. در نتیجه، مالک مسئول محدود کردن دسترسی و اجازه دادن به برنامههای مورد اعتماد است.
علاوه بر این، محدودیتهای بیشتری به نمایشگرهای مجازی اضافه میشود زیرا هر برنامهای میتواند یکی از آنها را بدون قابل مشاهده بودن برای کاربر ایجاد کند. اگر نمایشگر مجازی متعلق به سیستم نباشد، فقط فعالیتهایی با allowEmbedded مجاز هستند و فراخوانیکننده باید مجوز ACTIVITY_EMBEDDING را داشته باشد.
برای اطلاعات بیشتر، مراجعه کنید به:
-
ActivityStackSupervisor#isCallerAllowedToLaunchOnDisplay() -
ActivityDisplay#isUidPresent() -
DisplayManagerService#isUidPresentOnDisplay()
برای کنترل شرطی راهاندازی فعالیتها، LaunchParamsController استفاده کنید که تمام راهاندازیهای فعالیت را متوقف میکند و به یک جزء سیستم اجازه میدهد پارامترهای مورد استفاده برای راهاندازی را تغییر دهد. این در system_server موجود است.
پیکربندی تنظیمات پنجرههای نمایش و تزئینات سیستم
تزئینات سیستم را میتوان برای هر نمایشگر در DisplayWindowSettings پیکربندی کرد. پیادهسازی دستگاه میتواند پیکربندی پیشفرض را در /data/system/display_settings.xml ارائه دهد.
این مقدار تعیین میکند که آیا تزئینات سیستم (لانچر، تصویر زمینه، نوار ناوبری و سایر پنجرههای تزئینی) و IME روی صفحه نمایش ظاهر شوند یا خیر. برای جزئیات بیشتر، به DisplayWindowSettings#shouldShowSystemDecorsLocked() و DisplayWindowSettings#shouldShowImeLocked() مراجعه کنید.
برای شناسایی نمایشگر، از یک شناسه منحصر به فرد (این پیشفرض از DisplayInfo#uniqueId استفاده میکند) یا یک شناسه پورت فیزیکی برای نمایشگرهای سختافزاری استفاده کنید (به DisplayInfo#address مراجعه کنید).
برای مثال، مثال پیکربندی نمایش زیر، تزئینات سیستم و IME را در یک نمایش شبیهسازی شده فعال میکند:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?> <display-settings> <config identifier="0" /> <display name="overlay:1" shouldShowSystemDecors="true" shouldShowIme="true" /> </display-settings>
در مثال بالا، uniqueId برای شناسایی نمایش در ویژگی name استفاده شده است که برای یک نمایش شبیهسازی شده، overlay:1 است. برای یک نمایش داخلی، مقدار نمونه میتواند "local:45354385242535243453" باشد. گزینه دیگر استفاده از اطلاعات پورت سختافزاری و تنظیم identifier="1" برای مطابقت با DisplayWindowSettings#IDENTIFIER_PORT و سپس بهروزرسانی نام برای استفاده از قالب "port:<port_id>" است:
<?xmlversion='1.0' encoding='utf-8' standalone='yes' ?> <display-settings> <config identifier="1" /> <display name="port:12345" shouldShowSystemDecors="true" shouldShowIme="true" /> </display-settings>
برای جزئیات بیشتر، به شناسههای نمایشی استاتیک مراجعه کنید.
برای اطلاعات بیشتر، مراجعه کنید به:
نمایشگرها را بین وظایف آینهسازی و میزبانی تغییر دهید
در اندروید ۱۷ و بالاتر، DisplayManager از پرچم FLAG_ALLOWS_CONTENT_MODE_SWITCH برای کنترل اینکه آیا یک نمایشگر در زمان اجرا بین وظایف آینهسازی و میزبانی جابجا میشود یا خیر، استفاده میکند. به طور پیشفرض، این پرچم برای نمایشگرهای خارجی فعال و برای سایر نمایشگرها غیرفعال است.
وقتی FLAG_ALLOWS_CONTENT_MODE_SWITCH وجود داشته باشد، DisplayManager تنظیمات امن android.provider.Settings.Secure.MIRROR_BUILT_IN_DISPLAY را رصد میکند تا تعیین کند که آیا وظایف را منعکس کند یا میزبانی کند. اگرچه این منطق پیشفرض است، تولیدکنندگان اصلی تجهیزات (OEM) میتوانند این رفتار را سفارشی کنند.
توپولوژی نمایش و حرکت اشارهگر
در اندروید ۱۷ و بالاتر، توپولوژی نمایشگر، موقعیتهای نسبی نمایشگرها را تعریف میکند و حرکت اشارهگر ماوس را به مجموعه خاصی از نمایشگرها در توپولوژی محدود میکند.
WindowManager تصمیم میگیرد که یک نمایشگر را در توپولوژی قرار دهد و DisplayManagerInternal.onDisplayBelongToTopologyChanged را فراخوانی میکند. DisplayManager قبل از افزودن نمایشگر، DisplayTopologyCoordinator.isDisplayAllowedInTopology را بررسی میکند. به طور پیشفرض، اگر نمایشگرهای محلی بتوانند وظایف را میزبانی کنند، سیستم آنها را اضافه میکند.
اگر چندین نمایشگر عمومی وجود داشته باشد که بتوانند وظایف را میزبانی کنند، تصمیم برای گنجاندن نمایشگر پیشفرض توسط ارائهدهندهی بولی shouldIncludeDefaultDisplayInTopology که به DisplayTopologyCoordinator ارسال میشود، انجام میشود. اگر نمایشگر پیشفرض تنها نمایشگر عمومی باشد که میتواند وظایف را میزبانی کند، همیشه در توپولوژی قرار دارد. در AOSP، ارائهدهندهی بولی فقط در صورتی true را برمیگرداند که نمایشگر پیشفرض از پنجرهبندی دسکتاپ پشتیبانی کند یا تنظیم امن Settings.Secure.INCLUDE_DEFAULT_DISPLAY_IN_TOPOLOGY true باشد.
برنامهها با استفاده از DisplayManager.getDisplayTopology توپولوژی فعلی را جستجو میکنند و با ثبت یک شنونده با DisplayManager.registerTopologyListener به تغییرات توپولوژی واکنش نشان میدهند.