প্রদর্শন সমর্থন

এই প্রদর্শন-নির্দিষ্ট ক্ষেত্রগুলিতে করা আপডেটগুলি নীচে দেওয়া হল:

কার্যকলাপ এবং ডিসপ্লেগুলির আকার পরিবর্তন করুন

কোনো অ্যাপ মাল্টি-উইন্ডো মোড বা রিসাইজিং সমর্থন করে না, তা বোঝাতে অ্যাক্টিভিটিগুলোতে resizeableActivity=false অ্যাট্রিবিউট ব্যবহার করা হয়। অ্যাক্টিভিটি রিসাইজ করার সময় অ্যাপগুলোতে যে সাধারণ সমস্যাগুলো দেখা দেয়, তার মধ্যে রয়েছে:

  • একটি অ্যাক্টিভিটির কনফিগারেশন অ্যাপ বা অন্য কোনো অদৃশ্য উপাদান থেকে ভিন্ন হতে পারে। একটি সাধারণ ভুল হলো অ্যাপ কনটেক্সট থেকে ডিসপ্লে মেট্রিক্স পড়া। এর ফলে প্রাপ্ত মানগুলো, অ্যাক্টিভিটিটি যে দৃশ্যমান এলাকায় প্রদর্শিত হয়, তার মেট্রিক্স অনুযায়ী সমন্বয় করা হয় না।
  • কোনো অ্যাক্টিভিটি রিসাইজিং সামলাতে না পেরে ক্র্যাশ করতে পারে, বিকৃত UI প্রদর্শন করতে পারে, অথবা ইনস্ট্যান্স স্টেট সেভ না করে রিলঞ্চ করার কারণে তার স্টেট হারিয়ে ফেলতে পারে।
  • কোনো অ্যাপ উইন্ডোর অবস্থানের সাপেক্ষে স্থানাঙ্কের পরিবর্তে পরম ইনপুট স্থানাঙ্ক ব্যবহার করার চেষ্টা করতে পারে, যা একাধিক উইন্ডোতে ইনপুটকে অকার্যকর করে দিতে পারে।

অ্যান্ড্রয়েড ৭ (এবং এর পরবর্তী সংস্করণ)-এ, কোনো অ্যাপকে সবসময় ফুল স্ক্রিন মোডে চালানোর জন্য resizeableActivity=false সেট করা যায়। এক্ষেত্রে, প্ল্যাটফর্মটি নন-রিসাইজেবল অ্যাক্টিভিটিগুলোকে স্প্লিট স্ক্রিনে যেতে বাধা দেয়। যদি ব্যবহারকারী ইতোমধ্যে স্প্লিট-স্ক্রিন মোডে থাকা অবস্থায় লঞ্চার থেকে কোনো নন-রিসাইজেবল অ্যাক্টিভিটি চালু করার চেষ্টা করেন, তাহলে প্ল্যাটফর্মটি স্প্লিট-স্ক্রিন মোড থেকে বেরিয়ে আসে এবং নন-রিসাইজেবল অ্যাক্টিভিটিটিকে ফুল-স্ক্রিন মোডে চালু করে।

যেসব অ্যাপের ম্যানিফেস্টে এই অ্যাট্রিবিউটটি স্পষ্টভাবে false সেট করা থাকে, সেগুলোকে মাল্টি-উইন্ডো মোডে চালু করা যাবে না, যদি না কম্প্যাটিবিলিটি মোড প্রয়োগ করা হয়:

  • প্রক্রিয়াটিতে একই কনফিগারেশন প্রয়োগ করা হয়, যেটিতে সমস্ত কার্যকলাপ এবং অ-কার্যকলাপ উপাদান অন্তর্ভুক্ত থাকে।
  • প্রয়োগকৃত কনফিগারেশনটি অ্যাপ-সামঞ্জস্যপূর্ণ ডিসপ্লেগুলির জন্য CDD-এর প্রয়োজনীয়তা পূরণ করে।

অ্যান্ড্রয়েড ১০-এ, প্ল্যাটফর্মটি এখনও আকার পরিবর্তনযোগ্য নয় এমন অ্যাক্টিভিটিগুলোকে স্প্লিট-স্ক্রিন মোডে যেতে বাধা দেয়, কিন্তু অ্যাক্টিভিটিটি যদি একটি নির্দিষ্ট ওরিয়েন্টেশন বা অ্যাসপেক্ট রেশিও ঘোষণা করে থাকে, তবে সেটিকে সাময়িকভাবে স্কেল করা যেতে পারে। অন্যথায়, অ্যান্ড্রয়েড ৯ এবং তার পূর্ববর্তী সংস্করণগুলোর মতোই অ্যাক্টিভিটিটি পুরো স্ক্রিন জুড়ে আকার পরিবর্তন করে।

ডিফল্ট বাস্তবায়ন নিম্নলিখিত নীতি প্রয়োগ করে:

যখন android:resizeableActivity অ্যাট্রিবিউট ব্যবহারের মাধ্যমে কোনো অ্যাক্টিভিটিকে মাল্টি-উইন্ডোর সাথে বেমানান বলে ঘোষণা করা হয় এবং যখন সেই অ্যাক্টিভিটি নিচে বর্ণিত শর্তগুলোর মধ্যে একটি পূরণ করে, তখন প্রয়োগকৃত স্ক্রিন কনফিগারেশন পরিবর্তন করার প্রয়োজন হলে, অ্যাক্টিভিটি এবং প্রসেসটি মূল কনফিগারেশনসহ সংরক্ষণ করা হয় এবং ব্যবহারকারীকে আপডেট করা স্ক্রিন কনফিগারেশন ব্যবহার করার জন্য অ্যাপ প্রসেসটি পুনরায় চালু করার একটি সুযোগ দেওয়া হয়।

  • android:screenOrientation প্রয়োগের মাধ্যমে ওরিয়েন্টেশন স্থির করা হয়।
  • অ্যাপটি এপিআই লেভেল টার্গেট করার মাধ্যমে ডিফল্ট সর্বোচ্চ বা সর্বনিম্ন অ্যাস্পেক্ট রেশিও নির্ধারণ করে, অথবা স্পষ্টভাবে অ্যাস্পেক্ট রেশিও ঘোষণা করে।

এই চিত্রে একটি ঘোষিত অ্যাস্পেক্ট রেশিও সহ একটি আকার পরিবর্তন-অযোগ্য অ্যাক্টিভিটি দেখানো হয়েছে। ডিভাইসটি ভাঁজ করার সময়, উপযুক্ত লেটারবক্সিং ব্যবহার করে অ্যাস্পেক্ট রেশিও বজায় রেখে উইন্ডোটি জায়গার সাথে মানানসই করে ছোট করা হয়। এছাড়াও, প্রতিবার অ্যাক্টিভিটির ডিসপ্লে এলাকা পরিবর্তন করা হলে ব্যবহারকারীকে একটি ‘অ্যাক্টিভিটি পুনরায় চালু করুন’ (restart activity) বিকল্প প্রদান করা হয়।

ডিভাইসটি আনফোল্ড করার সময় অ্যাক্টিভিটির কনফিগারেশন, আকার এবং অ্যাসপেক্ট রেশিও অপরিবর্তিত থাকে, কিন্তু অ্যাক্টিভিটিটি রিস্টার্ট করার অপশনটি প্রদর্শিত হয়।

যখন resizeableActivity সেট করা থাকে না (অথবা এটি true সেট করা থাকে), তখন অ্যাপটি রিসাইজিংকে সম্পূর্ণরূপে সমর্থন করে।

বাস্তবায়ন

কোডে, একটি নির্দিষ্ট ওরিয়েন্টেশন বা অ্যাসপেক্ট রেশিও সহ আকার পরিবর্তন-অযোগ্য অ্যাক্টিভিটিকে সাইজ কম্প্যাটিবিলিটি মোড (SCM) বলা হয়। এই অবস্থাটি ActivityRecord#shouldUseSizeCompatMode() -এ সংজ্ঞায়িত করা হয়। যখন একটি SCM অ্যাক্টিভিটি চালু করা হয়, তখন স্ক্রিন-সম্পর্কিত কনফিগারেশন (যেমন আকার বা ঘনত্ব) অনুরোধ করা ওভাররাইড কনফিগারেশনে স্থির করে দেওয়া হয়, ফলে অ্যাক্টিভিটিটি আর বর্তমান ডিসপ্লে কনফিগারেশনের উপর নির্ভরশীল থাকে না।

যদি SCM অ্যাক্টিভিটি পুরো স্ক্রিনটি পূরণ করতে না পারে, তবে এটি উপরে সারিবদ্ধ এবং অনুভূমিকভাবে কেন্দ্রে থাকে। অ্যাক্টিভিটির সীমানা AppWindowToken#calculateCompatBoundsTransformation() দ্বারা গণনা করা হয়।

যখন কোনো SCM অ্যাক্টিভিটি তার কন্টেইনারের চেয়ে ভিন্ন স্ক্রিন কনফিগারেশন ব্যবহার করে (উদাহরণস্বরূপ, ডিসপ্লের আকার পরিবর্তন করা হলে, বা অ্যাক্টিভিটি অন্য ডিসপ্লেতে সরানো হলে), তখন ActivityRecord#inSizeCompatMode() ট্রু হয় এবং SizeCompatModeActivityController (সিস্টেম UI-তে) প্রসেস রিস্টার্ট বাটনটি দেখানোর জন্য কলব্যাক গ্রহণ করে।

ডিসপ্লে আকার এবং আকৃতির অনুপাত

অ্যান্ড্রয়েড ১০ লম্বা ও সরু স্ক্রিনের উচ্চ অনুপাত থেকে শুরু করে ১:১ অনুপাত পর্যন্ত নতুন অ্যাস্পেক্ট রেশিও সমর্থন করে। অ্যাপগুলো তাদের পরিচালনা করতে সক্ষম স্ক্রিনের জন্য ApplicationInfo#maxAspectRatio এবং ApplicationInfo#minAspectRatio নির্ধারণ করতে পারে।

অ্যান্ড্রয়েড ১০-এ অ্যাপের অনুপাত

চিত্র ১. অ্যান্ড্রয়েড ১০-এ সমর্থিত অ্যাপ অনুপাতের উদাহরণ।

ডিভাইস ইমপ্লিমেন্টেশনগুলিতে অ্যান্ড্রয়েড ৯-এর জন্য প্রয়োজনীয় আকার ও রেজোলিউশনের চেয়ে ছোট এবং তার চেয়েও কম আকারের সেকেন্ডারি ডিসপ্লে থাকতে পারে (সর্বনিম্ন ২.৫ ইঞ্চি প্রস্থ বা উচ্চতা, smallestScreenWidth এর জন্য সর্বনিম্ন ৩২০ ডিপি), কিন্তু শুধুমাত্র সেইসব অ্যাক্টিভিটিই সেখানে রাখা যাবে যেগুলো এই ছোট ডিসপ্লেগুলিকে সাপোর্ট করার জন্য অপ্ট-ইন করেছে।

অ্যাপগুলো টার্গেট ডিসপ্লে সাইজের চেয়ে ছোট বা সমান একটি সর্বনিম্ন সমর্থিত সাইজ ঘোষণা করে এটি বেছে নিতে পারে। এর জন্য AndroidManifest-এ android:minHeight এবং android:minWidth অ্যাক্টিভিটি লেআউট অ্যাট্রিবিউটগুলো ব্যবহার করুন।

নীতিমালা প্রদর্শন করুন

অ্যান্ড্রয়েড ১০, PhoneWindowManager এর ডিফল্ট WindowManagerPolicy ইমপ্লিমেন্টেশন থেকে নির্দিষ্ট কিছু ডিসপ্লে পলিসিকে আলাদা করে প্রতি-ডিসপ্লে ক্লাসে স্থানান্তর করে, যেমন:

  • অবস্থা এবং ঘূর্ণন প্রদর্শন করুন
  • কিছু কী এবং মোশন ইভেন্ট ট্র্যাকিং
  • সিস্টেম UI এবং সজ্জা উইন্ডো

অ্যান্ড্রয়েড ৯ (এবং এর পূর্ববর্তী সংস্করণগুলোতে), PhoneWindowManager ক্লাসটি ডিসপ্লে পলিসি, স্টেট ও সেটিংস, রোটেশন, ডেকোরেশন, উইন্ডো ফ্রেম ট্র্যাকিং এবং আরও অনেক কিছু পরিচালনা করত। অ্যান্ড্রয়েড ১০-এ এর বেশিরভাগই DisplayPolicy ক্লাসে স্থানান্তরিত করা হয়েছে, তবে রোটেশন ট্র্যাকিং এর ব্যতিক্রম, যা DisplayRotation ক্লাসে সরানো হয়েছে।

ডিসপ্লে উইন্ডো সেটিংস

অ্যান্ড্রয়েড ১০-এ, কনফিগারযোগ্য প্রতি-ডিসপ্লে উইন্ডোয়িং সেটিংটি সম্প্রসারিত করে নিম্নলিখিত বিষয়গুলো অন্তর্ভুক্ত করা হয়েছে:

  • ডিফল্ট ডিসপ্লে উইন্ডোইং মোড
  • ওভারস্ক্যান মান
  • ব্যবহারকারীর ঘূর্ণন এবং ঘূর্ণন মোড
  • জোরপূর্বক আকার, ঘনত্ব এবং স্কেলিং মোড
  • বিষয়বস্তু অপসারণ মোড (যখন ডিসপ্লে সরানো হয়)
  • সিস্টেম ডেকোরেশন এবং আইএমই-এর জন্য সমর্থন

DisplayWindowSettings ক্লাসে এই অপশনগুলোর জন্য সেটিংস থাকে। প্রতিবার কোনো সেটিং পরিবর্তন করা হলে, সেগুলো display_settings.xml ফাইলের মাধ্যমে ডিস্কের /data পার্টিশনে সংরক্ষিত হয়। বিস্তারিত জানতে, DisplayWindowSettings.AtomicFileStorage এবং DisplayWindowSettings#writeSettings() দেখুন। ডিভাইস নির্মাতারা তাদের ডিভাইস কনফিগারেশনের জন্য display_settings.xml এ ডিফল্ট মান প্রদান করতে পারেন। তবে, যেহেতু ফাইলটি /data তে সংরক্ষিত থাকে, তাই ওয়াইপ করার ফলে ফাইলটি মুছে গেলে তা পুনরুদ্ধার করার জন্য অতিরিক্ত লজিকের প্রয়োজন হতে পারে।

ডিফল্টরূপে, অ্যান্ড্রয়েড ১০ সেটিংস সংরক্ষণ করার সময় একটি ডিসপ্লের শনাক্তকারী হিসেবে DisplayInfo#uniqueId ব্যবহার করে। সমস্ত ডিসপ্লের জন্য uniqueId পূরণ করা উচিত। এছাড়াও, এটি ফিজিক্যাল এবং নেটওয়ার্ক ডিসপ্লের জন্য স্থিতিশীল। শনাক্তকারী হিসেবে একটি ফিজিক্যাল ডিসপ্লের পোর্ট ব্যবহার করাও সম্ভব, যা DisplayWindowSettings#mIdentifier এ সেট করা যেতে পারে। প্রতিবার লেখার সময় সমস্ত সেটিংস লেখা হয়, তাই স্টোরেজে একটি ডিসপ্লে এন্ট্রির জন্য ব্যবহৃত কী-টি আপডেট করা নিরাপদ। বিস্তারিত জানতে, স্ট্যাটিক ডিসপ্লে আইডেন্টিফায়ারস দেখুন।

ঐতিহাসিক কারণে সেটিংস /data ডিরেক্টরিতে সংরক্ষণ করা হয়। মূলত, এগুলো ব্যবহারকারী-নির্ধারিত সেটিংস, যেমন ডিসপ্লে রোটেশন, সংরক্ষণের জন্য ব্যবহৃত হতো।

স্থির প্রদর্শন শনাক্তকারী

অ্যান্ড্রয়েড ৯ (এবং এর পূর্ববর্তী সংস্করণ) ফ্রেমওয়ার্কে ডিসপ্লেগুলোর জন্য কোনো স্থিতিশীল আইডেন্টিফায়ার প্রদান করত না। যখন সিস্টেমে কোনো ডিসপ্লে যুক্ত করা হতো, তখন একটি স্ট্যাটিক কাউন্টার বাড়িয়ে সেই ডিসপ্লেটির জন্য Display#mDisplayId অথবা DisplayInfo#displayId তৈরি করা হতো। যদি সিস্টেম একই ডিসপ্লে যুক্ত করে আবার সরিয়ে দিত, তাহলে একটি ভিন্ন আইডি তৈরি হতো।

যদি কোনো ডিভাইসে বুট করার সময় একাধিক ডিসপ্লে উপলব্ধ থাকতো, তবে সময়ের ওপর নির্ভর করে ডিসপ্লেগুলোকে ভিন্ন ভিন্ন আইডেন্টিফায়ার দেওয়া যেত। যদিও অ্যান্ড্রয়েড ৯ (এবং এর আগের সংস্করণগুলোতে) DisplayInfo#uniqueId অন্তর্ভুক্ত ছিল, কিন্তু ডিসপ্লেগুলোর মধ্যে পার্থক্য করার জন্য এতে যথেষ্ট তথ্য ছিল না, কারণ ফিজিক্যাল ডিসপ্লেগুলোকে বিল্ট-ইন এবং এক্সটার্নাল ডিসপ্লে বোঝানোর জন্য local:0 বা local:1 হিসেবে চিহ্নিত করা হতো।

অ্যান্ড্রয়েড ১০ একটি স্থিতিশীল শনাক্তকারী যোগ করতে এবং লোকাল, নেটওয়ার্ক ও ভার্চুয়াল ডিসপ্লের মধ্যে পার্থক্য করার জন্য 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() দিয়ে তৈরি করা যায়।

অ্যান্ড্রয়েড ১০ পোর্ট সম্পর্কিত তথ্য পাওয়ার জন্য একটি সুবিধাজনক পদ্ধতিও প্রদান করে ( Physical#getPort() )। এই পদ্ধতিটি ফ্রেমওয়ার্কে ডিসপ্লেগুলোকে স্থিরভাবে শনাক্ত করতে ব্যবহার করা যেতে পারে। উদাহরণস্বরূপ, এটি DisplayWindowSettings এ ব্যবহৃত হয়। DisplayAddress.Network MAC অ্যাড্রেস থাকে এবং DisplayAddress#fromMacAddress() দিয়ে তৈরি করা যায়।

এই সংযোজনগুলি ডিভাইস প্রস্তুতকারকদের স্ট্যাটিক মাল্টি-ডিসপ্লে সেট-আপে ডিসপ্লে শনাক্ত করতে এবং স্ট্যাটিক ডিসপ্লে আইডেন্টিফায়ার, যেমন ফিজিক্যাল ডিসপ্লের পোর্ট, ব্যবহার করে বিভিন্ন সিস্টেম সেটিংস ও ফিচার কনফিগার করতে সাহায্য করে। এই মেথডগুলি লুকানো থাকে এবং শুধুমাত্র system_server মধ্যেই ব্যবহারের জন্য উদ্দিষ্ট।

একটি HWC ডিসপ্লে আইডি (যা অস্বচ্ছ এবং সবসময় স্থিতিশীল নাও হতে পারে) দেওয়া হলে, এই মেথডটি ডিসপ্লে আউটপুটের জন্য একটি ফিজিক্যাল কানেক্টর শনাক্তকারী (প্ল্যাটফর্ম-নির্দিষ্ট) ৮-বিট পোর্ট নম্বর এবং ডিসপ্লেটির EDID ব্লব রিটার্ন করে। SurfaceFlinger ফ্রেমওয়ার্কের কাছে প্রকাশ করা স্থিতিশীল ৬৪-বিট ডিসপ্লে আইডিগুলো তৈরি করার জন্য EDID থেকে প্রস্তুতকারক বা মডেলের তথ্য সংগ্রহ করে। যদি এই মেথডটি সমর্থিত না হয় বা কোনো ত্রুটি দেখায়, তাহলে 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"

দুইটির বেশি ডিসপ্লে ব্যবহার করুন

অ্যান্ড্রয়েড ৯ (এবং এর পূর্ববর্তী সংস্করণগুলোতে), SurfaceFlinger এবং DisplayManagerService ধরে নিত যে সর্বোচ্চ দুটি ফিজিক্যাল ডিসপ্লে রয়েছে, যেগুলোর আইডি ০ এবং ১ হার্ড-কোড করা থাকত।

অ্যান্ড্রয়েড ১০ থেকে শুরু করে, সারফেসফ্লিঙ্গার একটি হার্ডওয়্যার কম্পোজার (HWC) এপিআই ব্যবহার করে স্থিতিশীল ডিসপ্লে আইডি তৈরি করতে পারে, যা এটিকে যেকোনো সংখ্যক ফিজিক্যাল ডিসপ্লে পরিচালনা করতে সক্ষম করে। আরও জানতে, স্ট্যাটিক ডিসপ্লে আইডেন্টিফায়ারস দেখুন।

ফ্রেমওয়ার্কটি SurfaceControl#getPhysicalDisplayIds থেকে অথবা একটি DisplayEventReceiver হটপ্লাগ ইভেন্ট থেকে ৬৪-বিট ডিসপ্লে আইডি পাওয়ার পর, SurfaceControl#getPhysicalDisplayToken এর মাধ্যমে একটি ফিজিক্যাল ডিসপ্লের জন্য IBinder টোকেনটি খুঁজে বের করতে পারে।

অ্যান্ড্রয়েড ১০ (এবং এর পূর্ববর্তী সংস্করণ)-এ, প্রাথমিক অভ্যন্তরীণ ডিসপ্লেটি TYPE_INTERNAL এবং সংযোগের ধরন নির্বিশেষে সমস্ত সেকেন্ডারি ডিসপ্লে TYPE_EXTERNAL হিসেবে চিহ্নিত করা হয়। তাই, অতিরিক্ত অভ্যন্তরীণ ডিসপ্লেগুলোকে এক্সটার্নাল হিসেবে গণ্য করা হয়। এর একটি বিকল্প সমাধান হিসেবে, যদি হার্ডওয়্যার কোড (HWC) জানা থাকে এবং পোর্ট বরাদ্দের লজিক অনুমানযোগ্য হয়, তবে ডিভাইস-নির্দিষ্ট কোড DisplayAddress.Physical#getPort সম্পর্কে কিছু ধারণা নিতে পারে।

অ্যান্ড্রয়েড ১১ (এবং এর পরবর্তী সংস্করণগুলোতে) এই সীমাবদ্ধতাটি দূর করা হয়েছে।

  • অ্যান্ড্রয়েড ১১-এ, বুট করার সময় প্রথমে যে ডিসপ্লেটি দেখা যায়, সেটিই হলো প্রাইমারি ডিসপ্লে। কানেকশনের ধরন (অভ্যন্তরীণ বনাম বাহ্যিক) এক্ষেত্রে অপ্রাসঙ্গিক। তবে, এটা সত্যি যে প্রাইমারি ডিসপ্লে সংযোগ বিচ্ছিন্ন করা যায় না এবং ফলস্বরূপ, বাস্তবে এটি অবশ্যই একটি অভ্যন্তরীণ ডিসপ্লে হতে হবে। উল্লেখ্য যে, কিছু ফোল্ডেবল ফোনে একাধিক অভ্যন্তরীণ ডিসপ্লে থাকে।
  • সেকেন্ডারি ডিসপ্লেগুলোকে তাদের সংযোগের ধরনের ওপর নির্ভর করে Display.TYPE_INTERNAL অথবা Display.TYPE_EXTERNAL (যা পূর্বে যথাক্রমে Display.TYPE_BUILT_IN এবং Display.TYPE_HDMI নামে পরিচিত ছিল) হিসেবে সঠিকভাবে শ্রেণিবদ্ধ করা হয়।

বাস্তবায়ন

অ্যান্ড্রয়েড ৯ এবং এর পূর্ববর্তী সংস্করণগুলিতে, ডিসপ্লেগুলিকে ৩২-বিট আইডি দ্বারা চিহ্নিত করা হয়, যেখানে ০ হলো অভ্যন্তরীণ ডিসপ্লে, ১ হলো বাহ্যিক ডিসপ্লে, [2, INT32_MAX] হলো HWC ভার্চুয়াল ডিসপ্লে, এবং -১ একটি অবৈধ ডিসপ্লে বা একটি নন-HWC ভার্চুয়াল ডিসপ্লেকে বোঝায়।

অ্যান্ড্রয়েড ১০ থেকে, ডিসপ্লেগুলোকে স্থিতিশীল এবং স্থায়ী আইডি দেওয়া হয়, যা সারফেসফ্লিঙ্গার এবং DisplayManagerService দুইটির বেশি ডিসপ্লে ট্র্যাক করতে এবং পূর্বে দেখা ডিসপ্লে শনাক্ত করতে সক্ষম করে। যদি HWC, IComposerClient.getDisplayIdentificationData সমর্থন করে এবং ডিসপ্লে শনাক্তকরণ ডেটা সরবরাহ করে, তবে সারফেসফ্লিঙ্গার EDID কাঠামোটি পার্স করে এবং ফিজিক্যাল ও HWC ভার্চুয়াল ডিসপ্লেগুলোর জন্য স্থিতিশীল ৬৪-বিট ডিসপ্লে আইডি বরাদ্দ করে। এই আইডিগুলো একটি অপশন টাইপ ব্যবহার করে প্রকাশ করা হয়, যেখানে নাল (null) মানটি একটি অবৈধ ডিসপ্লে বা নন-HWC ভার্চুয়াল ডিসপ্লেকে বোঝায়। HWC সমর্থন ছাড়া, সারফেসফ্লিঙ্গার সর্বাধিক দুটি ফিজিক্যাল ডিসপ্লে সহ তার পুরোনো আচরণে ফিরে যায়।

প্রতি-ডিসপ্লে ফোকাস

একই সময়ে একাধিক ডিসপ্লেতে ইনপুট দেওয়ার জন্য, অ্যান্ড্রয়েড ১০-কে এমনভাবে কনফিগার করা যায় যাতে এটি প্রতি ডিসপ্লেতে সর্বোচ্চ একটি ফোকাসড উইন্ডো সমর্থন করতে পারে। এটি শুধুমাত্র বিশেষ ধরনের ডিভাইসের জন্য প্রযোজ্য, যখন একাধিক ব্যবহারকারী একই সময়ে একই ডিভাইস ব্যবহার করেন এবং বিভিন্ন ইনপুট পদ্ধতি বা ডিভাইস ব্যবহার করেন, যেমন অ্যান্ড্রয়েড অটোমোটিভ।

সাধারণ ডিভাইস, যার মধ্যে মাল্টি-স্ক্রিন ডিভাইস বা ডেস্কটপের মতো অভিজ্ঞতার জন্য ব্যবহৃত ডিভাইসও অন্তর্ভুক্ত, সেগুলোর জন্য এই ফিচারটি চালু না করার জন্য দৃঢ়ভাবে সুপারিশ করা হচ্ছে। এর প্রধান কারণ হলো একটি নিরাপত্তাজনিত উদ্বেগ, যার ফলে ব্যবহারকারীরা বিভ্রান্ত হতে পারেন যে কোন উইন্ডোটিতে ইনপুট ফোকাস রয়েছে।

এমন একজন ব্যবহারকারীর কথা ভাবুন যিনি একটি টেক্সট ইনপুট ফিল্ডে সুরক্ষিত তথ্য প্রবেশ করান, যেমন—হয়তো কোনো ব্যাংকিং অ্যাপে লগ ইন করার জন্য বা সংবেদনশীল তথ্য সম্বলিত কোনো টেক্সট লেখার জন্য। একটি ক্ষতিকারক অ্যাপ একটি ভার্চুয়াল অফ-স্ক্রিন ডিসপ্লে তৈরি করতে পারে, যার মাধ্যমে কোনো একটি কার্যকলাপ সম্পাদন করা যায় এবং সেখানেও একটি টেক্সট ইনপুট ফিল্ড থাকে। বৈধ এবং ক্ষতিকারক উভয় কার্যকলাপেরই ফোকাস থাকে এবং উভয়ই একটি সক্রিয় ইনপুট নির্দেশক (ঝিকমিক করা কার্সার) প্রদর্শন করে।

তবে, যেহেতু কিবোর্ড (হার্ডওয়্যার বা সফটওয়্যার) থেকে ইনপুট শুধুমাত্র সর্বোচ্চ অ্যাক্টিভিটিতে (অর্থাৎ সর্বশেষ চালু করা অ্যাপে) প্রবেশ করে, তাই একটি লুকানো ভার্চুয়াল ডিসপ্লে তৈরি করে একটি ক্ষতিকারক অ্যাপ ব্যবহারকারীর ইনপুট হাতিয়ে নিতে পারে, এমনকি ডিভাইসের প্রধান ডিসপ্লেতে সফটওয়্যার কিবোর্ড ব্যবহার করার সময়েও।

প্রতি-ডিসপ্লে ফোকাস সেট করতে com.android.internal.R.bool.config_perDisplayFocusEnabled ব্যবহার করুন।

সামঞ্জস্যতা

সমস্যা: অ্যান্ড্রয়েড ৯ এবং এর পূর্ববর্তী সংস্করণগুলোতে, সিস্টেমের সর্বাধিক একটি উইন্ডো একবারে ফোকাসে থাকে।

সমাধান: এমন বিরল ক্ষেত্রে যখন একই প্রসেসের দুটি উইন্ডো ফোকাসড হয়, তখন সিস্টেম শুধুমাত্র Z-অর্ডারে উপরের উইন্ডোটিকে ফোকাস দেয়। অ্যান্ড্রয়েড ১০ টার্গেট করা অ্যাপগুলোর জন্য এই সীমাবদ্ধতাটি তুলে দেওয়া হয়েছে, এবং তখন থেকে আশা করা হয় যে তারা একই সাথে একাধিক উইন্ডোতে ফোকাস করা সমর্থন করতে পারবে।

বাস্তবায়ন

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 এ স্থানান্তর করা হয়েছে।