डिसप्ले से जुड़ी इन खास बातों में किए गए अपडेट के बारे में यहां बताया गया है:
- गतिविधियों और डिसप्ले का साइज़ बदलना
- डिसप्ले के साइज़ और आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात)
- विज्ञापन दिखाने से जुड़ी नीतियां
- डिसप्ले विंडो की सेटिंग
- स्टैटिक डिसप्ले आइडेंटिफ़ायर
- दो से ज़्यादा डिसप्ले का इस्तेमाल करना
- हर डिसप्ले के हिसाब से फ़ोकस
गतिविधियों और डिसप्ले का साइज़ बदलना
अगर किसी ऐप्लिकेशन में मल्टी-विंडो मोड या साइज़ बदलने की सुविधा काम नहीं करती है, तो ऐक्टिविटी resizeableActivity=false
एट्रिब्यूट का इस्तेमाल करती हैं. ऐक्टिविटी का साइज़ बदलने पर, ऐप्लिकेशन को ये सामान्य समस्याएं आ सकती हैं:
- किसी ऐक्टिविटी का कॉन्फ़िगरेशन, ऐप्लिकेशन या किसी अन्य नॉन-विज़ुअल कॉम्पोनेंट से अलग हो सकता है. आम तौर पर, ऐप्लिकेशन के कॉन्टेक्स्ट से डिसप्ले मेट्रिक पढ़ी जाती हैं. यह एक आम गलती है. दिखने वाले क्षेत्र की मेट्रिक के हिसाब से, दिखाई गई गतिविधि की वैल्यू में बदलाव नहीं किया जाएगा.
- ऐसा हो सकता है कि गतिविधि, साइज़ बदलने की सुविधा को मैनेज न कर पाए और क्रैश हो जाए. इसके अलावा, ऐसा भी हो सकता है कि गतिविधि में यूज़र इंटरफ़ेस (यूआई) ठीक से न दिखे या इंस्टेंस की स्थिति को सेव किए बिना फिर से लॉन्च करने की वजह से, गतिविधि की स्थिति सेव न हो.
- कोई ऐप्लिकेशन, विंडो की पोज़िशन के हिसाब से इनपुट कोऑर्डिनेट के बजाय, ऐब्सलूट इनपुट कोऑर्डिनेट का इस्तेमाल करने की कोशिश कर सकता है. इससे मल्टी-विंडो में इनपुट काम नहीं कर सकता.
Android 7 और इसके बाद के वर्शन में, किसी ऐप्लिकेशन को resizeableActivity=false
हमेशा फ़ुल स्क्रीन मोड में चलाने के लिए सेट किया जा सकता है. इस मामले में, प्लैटफ़ॉर्म उन गतिविधियों को स्प्लिट स्क्रीन में जाने से रोकता है जिनका साइज़ नहीं बदला जा सकता. अगर उपयोगकर्ता, स्प्लिट-स्क्रीन मोड में पहले से मौजूद होने के दौरान, लॉन्चर से ऐसी गतिविधि शुरू करने की कोशिश करता है जिसका साइज़ नहीं बदला जा सकता, तो प्लैटफ़ॉर्म स्प्लिट-स्क्रीन मोड से बाहर निकल जाता है. इसके बाद, वह गतिविधि को फ़ुल-स्क्रीन मोड में शुरू करता है.
जिन ऐप्लिकेशन ने मेनिफ़ेस्ट में इस एट्रिब्यूट को false
पर सेट किया है उन्हें मल्टी-विंडो मोड में लॉन्च नहीं किया जाना चाहिए. हालांकि, अगर कंपैटिबिलिटी मोड लागू किया गया है, तो उन्हें लॉन्च किया जा सकता है:
- प्रोसेस पर एक ही कॉन्फ़िगरेशन लागू होता है. इसमें सभी गतिविधियां और गैर-गतिविधि वाले कॉम्पोनेंट शामिल होते हैं.
- लागू किया गया कॉन्फ़िगरेशन, ऐप्लिकेशन के साथ काम करने वाले डिसप्ले के लिए सीडीडी की ज़रूरी शर्तों को पूरा करता हो.
Android 10 में, प्लैटफ़ॉर्म अब भी उन गतिविधियों को स्प्लिट-स्क्रीन मोड में जाने से रोकता है जिनका साइज़ नहीं बदला जा सकता. हालांकि, अगर गतिविधि ने ओरिएंटेशन या आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) तय किया है, तो उन्हें कुछ समय के लिए स्केल किया जा सकता है. ऐसा न होने पर, ऐक्टिविटी का साइज़ बदलकर पूरी स्क्रीन पर दिखने लगता है. यह Android 9 और इससे पहले के वर्शन में होता है.
डिफ़ॉल्ट रूप से लागू की गई नीति यहां दी गई है:
जब android:resizeableActivity
एट्रिब्यूट का इस्तेमाल करके, किसी गतिविधि को मल्टी-विंडो मोड के साथ काम न करने वाली गतिविधि के तौर पर सेट किया जाता है और वह गतिविधि यहां बताई गई किसी एक शर्त को पूरा करती है, तो स्क्रीन कॉन्फ़िगरेशन में बदलाव होने पर, गतिविधि और प्रोसेस को ओरिजनल कॉन्फ़िगरेशन के साथ सेव किया जाता है. साथ ही, उपयोगकर्ता को अपडेट किए गए स्क्रीन कॉन्फ़िगरेशन का इस्तेमाल करने के लिए, ऐप्लिकेशन प्रोसेस को फिर से लॉन्च करने का विकल्प दिया जाता है.
- क्या
android:screenOrientation
का इस्तेमाल करके, ओरिएंटेशन को फ़िक्स किया गया है - ऐप्लिकेशन, एपीआई लेवल को टारगेट करके, डिफ़ॉल्ट तौर पर ज़्यादा से ज़्यादा या कम से कम आसपेक्ट रेशियो सेट करता हो या आसपेक्ट रेशियो के बारे में साफ़ तौर पर बताता हो
इस इमेज में, चौड़ाई-ऊंचाई के तय अनुपात वाली ऐसी गतिविधि दिखाई गई है जिसका साइज़ बदला नहीं जा सकता. डिवाइस को फ़ोल्ड करने पर, विंडो को छोटा करके उस जगह पर फ़िट किया जाता है. साथ ही, लेटरबॉक्सिंग का इस्तेमाल करके आसपेक्ट रेशियो को बनाए रखा जाता है. इसके अलावा, गतिविधि के डिसप्ले एरिया में बदलाव होने पर, उपयोगकर्ता को गतिविधि फिर से शुरू करने का विकल्प दिया जाता है.
डिवाइस को अनफ़ोल्ड करने पर, ऐक्टिविटी के कॉन्फ़िगरेशन, साइज़, और आसपेक्ट रेशियो में कोई बदलाव नहीं होता. हालांकि, ऐक्टिविटी को फिर से शुरू करने का विकल्प दिखता है.
अगर resizeableActivity
को सेट नहीं किया गया है या इसे true
पर सेट किया गया है, तो ऐप्लिकेशन का साइज़ बदलने की सुविधा पूरी तरह से काम करती है.
लागू करना
ऐसी गतिविधि जिसे रीसाइज़ नहीं किया जा सकता और जिसका ओरिएंटेशन या आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) तय होता है उसे कोड में साइज़ कंपैटिबिलिटी मोड (एससीएम) कहा जाता है. शर्त ActivityRecord#shouldUseSizeCompatMode()
में बताई गई है. एससीएम ऐक्टिविटी लॉन्च होने पर, स्क्रीन से जुड़ा कॉन्फ़िगरेशन (जैसे कि साइज़ या डेनसिटी) अनुरोध किए गए ओवरराइड कॉन्फ़िगरेशन में तय हो जाता है. इसलिए, ऐक्टिविटी अब मौजूदा डिसप्ले कॉन्फ़िगरेशन पर निर्भर नहीं रहती.
अगर SCM ऐक्टिविटी पूरी स्क्रीन पर नहीं दिखती है, तो वह सबसे ऊपर अलाइन होती है और
हॉरिजॉन्टल तौर पर बीच में होती है. गतिविधि की सीमाओं का हिसाब AppWindowToken#calculateCompatBoundsTransformation()
लगाता है.
जब कोई एससीएम ऐक्टिविटी, अपने कंटेनर से अलग स्क्रीन कॉन्फ़िगरेशन का इस्तेमाल करती है (उदाहरण के लिए, डिसप्ले का साइज़ बदला जाता है या ऐक्टिविटी को किसी दूसरे डिसप्ले पर ले जाया जाता है), तो ActivityRecord#inSizeCompatMode()
सही होता है. साथ ही, SizeCompatModeActivityController
(सिस्टम यूज़र इंटरफ़ेस में) को प्रोसेस रीस्टार्ट करने का बटन दिखाने के लिए, कॉलबैक मिलता है.
डिसप्ले साइज़ और आसपेक्ट रेशियो (चौड़ाई-ऊंचाई का अनुपात)
Android 10 में, नए आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) के लिए सहायता मिलती है. इसमें लंबी और पतली स्क्रीन के ज़्यादा रेशियो से लेकर 1:1 रेशियो तक शामिल हैं. ऐप्लिकेशन, स्क्रीन के ApplicationInfo#maxAspectRatio
और ApplicationInfo#minAspectRatio
को तय कर सकते हैं.
पहली इमेज. Android 10 में काम करने वाले ऐप्लिकेशन के आसपेक्ट रेशियो के उदाहरण
डिवाइसों में, Android 9 और इससे पहले के वर्शन के लिए ज़रूरी साइज़ और रिज़ॉल्यूशन से छोटे साइज़ और रिज़ॉल्यूशन वाले सेकंडरी डिसप्ले हो सकते हैं.हालांकि, सिर्फ़ वे गतिविधियां वहां रखी जा सकती हैं जिन्होंने इन छोटे डिसप्ले के साथ काम करने की सुविधा के लिए ऑप्ट-इन किया है.smallestScreenWidth
ऐप्लिकेशन, कम से कम उस साइज़ का एलान करके ऑप्ट इन कर सकते हैं जो टारगेट डिसप्ले साइज़ से छोटा या उसके बराबर हो. इसके लिए, AndroidManifest में android:minHeight
और android:minWidth
गतिविधि लेआउट एट्रिब्यूट का इस्तेमाल करें.
डिसप्ले नीतियां
Android 10, कुछ डिसप्ले नीतियों को PhoneWindowManager
में डिफ़ॉल्ट WindowManagerPolicy
से अलग करता है और उन्हें हर डिसप्ले क्लास में ले जाता है. जैसे:
- डिसप्ले की स्थिति और रोटेशन
- कुछ कुंजियों और मोशन इवेंट को ट्रैक करना
- सिस्टम यूज़र इंटरफ़ेस (यूआई) और डेकोरेशन विंडो
Android 9 और इससे पहले के वर्शन में, PhoneWindowManager
क्लास, डिसप्ले की नीतियां, स्थिति और सेटिंग, रोटेशन, डेकोरेशन विंडो फ़्रेम ट्रैकिंग वगैरह को मैनेज करता है. Android 10 में, इनमें से ज़्यादातर को DisplayPolicy
क्लास में ले जाया गया है. हालांकि, रोटेशन ट्रैकिंग को DisplayRotation
में ले जाया गया है.
डिसप्ले विंडो की सेटिंग
Android 10 में, हर डिसप्ले के हिसाब से कॉन्फ़िगर की जा सकने वाली विंडो सेटिंग को इन चीज़ों के लिए भी उपलब्ध कराया गया है:
- डिसप्ले के विंडो मोड का डिफ़ॉल्ट सेटिंग
- ओवस्कैन वैल्यू
- स्क्रीन घुमाने की सुविधा और रोटेशन मोड
- साइज़, डेंसिटी, और स्केलिंग मोड को लागू करना
- कॉन्टेंट हटाने का मोड (जब डिसप्ले हटाया जाता है)
- सिस्टम डेकोरेशन और 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
में बदलाव किए गए हैं, ताकि एक स्टेबल आइडेंटिफ़ायर जोड़ा जा सके. साथ ही, लोकल, नेटवर्क, और वर्चुअल डिसप्ले के बीच अंतर किया जा सके.
डिसप्ले टाइप | Format |
---|---|
लोकल | 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
में किया जा सकता है.
एचडब्ल्यूसी डिसप्ले आईडी (जो अपारदर्शी हो सकता है और हमेशा स्थिर नहीं रहता) दिए जाने पर, यह तरीका (प्लैटफ़ॉर्म के हिसाब से) 8-बिट पोर्ट नंबर दिखाता है. यह डिसप्ले आउटपुट के लिए फ़िज़िकल कनेक्टर की पहचान करता है. साथ ही, डिसप्ले का EDID ब्लोब भी दिखाता है.
SurfaceFlinger, EDID से मैन्युफ़ैक्चरर या मॉडल की जानकारी निकालता है, ताकि फ़्रेमवर्क को दिखाए जाने वाले स्टेबल 64-बिट डिसप्ले आईडी जनरेट किए जा सकें. अगर यह तरीका काम नहीं करता है या इसमें गड़बड़ी होती है, तो SurfaceFlinger, लेगसी एमडी मोड पर वापस आ जाता है. इसमें 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, स्टेबल डिसप्ले आईडी जनरेट करने के लिए, Hardware Composer (HWC) API का इस्तेमाल कर सकता है. इससे, वह किसी भी संख्या में फ़िज़िकल डिसप्ले को मैनेज कर पाता है. ज़्यादा जानने के लिए, स्टैटिक डिसप्ले आइडेंटिफ़ायर देखें.
फ़्रेमवर्क, SurfaceControl#getPhysicalDisplayIds
या DisplayEventReceiver
हॉटप्लग इवेंट से 64-बिट डिसप्ले आईडी पाने के बाद, SurfaceControl#getPhysicalDisplayToken
के ज़रिए किसी फ़िज़िकल डिसप्ले के लिए IBinder
टोकन ढूंढ सकता है.
Android 10 और इससे पहले के वर्शन में, प्राइमरी इंटरनल डिसप्ले को TYPE_INTERNAL
के तौर पर फ़्लैग किया जाता है. साथ ही, सभी सेकंडरी डिसप्ले को TYPE_EXTERNAL
के तौर पर फ़्लैग किया जाता है. भले ही, कनेक्शन का टाइप कुछ भी हो. इसलिए, अतिरिक्त इंटरनल डिसप्ले को बाहरी डिसप्ले माना जाता है.
हालांकि, डिवाइस के हिसाब से कोड, DisplayAddress.Physical#getPort
के बारे में अनुमान लगा सकता है. ऐसा तब होता है, जब एचडब्ल्यूसी के बारे में पता हो और पोर्ट असाइन करने का लॉजिक अनुमान लगाया जा सके.
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]
एचडब्ल्यूसी वर्चुअल डिसप्ले, और -1 अमान्य डिसप्ले या नॉन-एचडब्ल्यूसी वर्चुअल डिसप्ले को दिखाता है.
Android 10 से, डिसप्ले को स्टेबल और परसिस्टेंट आईडी दिए जाते हैं. इससे SurfaceFlinger और DisplayManagerService
को दो से ज़्यादा डिसप्ले ट्रैक करने और पहले से देखे गए डिसप्ले को पहचानने की अनुमति मिलती है. अगर एचडब्ल्यूसी IComposerClient.getDisplayIdentificationData
के साथ काम करता है और डिसप्ले की पहचान से जुड़ा डेटा उपलब्ध कराता है, तो SurfaceFlinger, EDID स्ट्रक्चर को पार्स करता है. साथ ही, फ़िज़िकल और एचडब्ल्यूसी वर्चुअल डिसप्ले के लिए, स्टेबल 64-बिट डिसप्ले आईडी असाइन करता है. आईडी को विकल्प टाइप का इस्तेमाल करके दिखाया जाता है. इसमें शून्य वैल्यू, अमान्य डिसप्ले या नॉन-एचडब्ल्यूसी वर्चुअल डिसप्ले को दिखाती है. एचडब्ल्यूसी की सुविधा के बिना, 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
में ले जाया गया है.