डिसप्ले से जुड़ी इन खास बातों में किए गए अपडेट के बारे में यहां बताया गया है:
- गतिविधियों और डिसप्ले का साइज़ बदलना
- डिसप्ले के साइज़ और आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात)
- विज्ञापन दिखाने से जुड़ी नीतियां
- डिसप्ले विंडो की सेटिंग
- स्टैटिक डिसप्ले आइडेंटिफ़ायर
- दो से ज़्यादा डिसप्ले का इस्तेमाल करना
- हर डिसप्ले के हिसाब से फ़ोकस करना
गतिविधियों और डिसप्ले का साइज़ बदलना
अगर किसी ऐप्लिकेशन में मल्टी-विंडो मोड या साइज़ बदलने की सुविधा काम नहीं करती है, तो ऐक्टिविटी resizeableActivity=false एट्रिब्यूट का इस्तेमाल करती हैं. ऐक्टिविटी का साइज़ बदलने पर, ऐप्लिकेशन को आम तौर पर ये समस्याएं आती हैं:
- किसी गतिविधि का कॉन्फ़िगरेशन, ऐप्लिकेशन या किसी अन्य नॉन-विज़ुअल कॉम्पोनेंट से अलग हो सकता है. आम तौर पर, ऐप्लिकेशन के कॉन्टेक्स्ट से डिसप्ले मेट्रिक पढ़ी जाती हैं. यह एक आम गलती है. दिखाई गई वैल्यू को, दिखने वाले एरिया की उन मेट्रिक के हिसाब से नहीं बदला जाएगा जिनमें गतिविधि दिखाई जाती है.
- ऐसा हो सकता है कि गतिविधि, साइज़ बदलने की सुविधा को मैनेज न कर पाए और क्रैश हो जाए. इसके अलावा, ऐसा भी हो सकता है कि गतिविधि का यूज़र इंटरफ़ेस (यूआई) खराब दिखे या इंस्टेंस की स्थिति को सेव किए बिना फिर से लॉन्च करने की वजह से, गतिविधि की स्थिति बदल जाए.
- कोई ऐप्लिकेशन, विंडो की पोज़िशन के हिसाब से इनपुट कोऑर्डिनेट के बजाय, ऐब्सलूट इनपुट कोऑर्डिनेट का इस्तेमाल करने की कोशिश कर सकता है. इससे मल्टी-विंडो में इनपुट काम नहीं कर सकता.
Android 7 और इसके बाद के वर्शन में, किसी ऐप्लिकेशन को resizeableActivity=false हमेशा फ़ुल स्क्रीन मोड में चलाने के लिए सेट किया जा सकता है. इस मामले में, प्लैटफ़ॉर्म ऐसी गतिविधियों को स्प्लिट स्क्रीन मोड में जाने से रोकता है जिनका साइज़ नहीं बदला जा सकता. अगर उपयोगकर्ता, स्प्लिट-स्क्रीन मोड में पहले से मौजूद है और लॉन्चर से ऐसी गतिविधि शुरू करने की कोशिश करता है जिसका साइज़ नहीं बदला जा सकता, तो प्लैटफ़ॉर्म स्प्लिट-स्क्रीन मोड से बाहर निकल जाता है. इसके बाद, वह गतिविधि को फ़ुल-स्क्रीन मोड में शुरू करता है.
जिन ऐप्लिकेशन ने मेनिफ़ेस्ट में इस एट्रिब्यूट को false पर सेट किया है उन्हें मल्टी-विंडो मोड में लॉन्च नहीं किया जाना चाहिए. हालांकि, अगर कंपैटिबिलिटी मोड लागू किया गया है, तो उन्हें लॉन्च किया जा सकता है:
- प्रोसेस पर एक ही कॉन्फ़िगरेशन लागू होता है. इसमें सभी गतिविधियां और गैर-गतिविधि वाले कॉम्पोनेंट शामिल होते हैं.
- लागू किया गया कॉन्फ़िगरेशन, ऐप्लिकेशन के साथ काम करने वाले डिसप्ले के लिए सीडीडी की ज़रूरी शर्तों को पूरा करता हो.
Android 10 में, प्लैटफ़ॉर्म अब भी उन गतिविधियों को स्प्लिट-स्क्रीन मोड में जाने से रोकता है जिनका साइज़ नहीं बदला जा सकता. हालांकि, अगर गतिविधि ने ओरिएंटेशन या आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) तय किया है, तो उन्हें कुछ समय के लिए स्केल किया जा सकता है. अगर ऐसा नहीं होता है, तो गतिविधि का साइज़ बदलकर पूरी स्क्रीन पर दिखने लगता है. यह Android 9 और इससे पहले के वर्शन में होता है.
डिफ़ॉल्ट तौर पर लागू की गई नीति यहां दी गई है:
जब android:resizeableActivity एट्रिब्यूट का इस्तेमाल करके, किसी गतिविधि को मल्टी-विंडो मोड के साथ काम न करने वाली गतिविधि के तौर पर सेट किया जाता है और वह गतिविधि यहां बताई गई किसी एक शर्त को पूरा करती है, तो स्क्रीन कॉन्फ़िगरेशन में बदलाव होने पर, गतिविधि और प्रोसेस को ओरिजनल कॉन्फ़िगरेशन के साथ सेव किया जाता है. साथ ही, उपयोगकर्ता को अपडेट किए गए स्क्रीन कॉन्फ़िगरेशन का इस्तेमाल करने के लिए, ऐप्लिकेशन प्रोसेस को फिर से लॉन्च करने का विकल्प दिया जाता है.
- क्या
android:screenOrientationका इस्तेमाल करके ओरिएंटेशन को लॉक किया गया है - ऐप्लिकेशन, एपीआई लेवल को टारगेट करके, डिफ़ॉल्ट तौर पर ज़्यादा से ज़्यादा या कम से कम आसपेक्ट रेशियो सेट करता हो या आसपेक्ट रेशियो साफ़ तौर पर बताता हो
इस इमेज में, चौड़ाई-ऊंचाई के तय अनुपात वाली ऐसी गतिविधि दिखाई गई है जिसका साइज़ नहीं बदला जा सकता. डिवाइस को फ़ोल्ड करने पर, विंडो को छोटा करके स्क्रीन पर फ़िट किया जाता है. साथ ही, लेटरबॉक्सिंग का इस्तेमाल करके आसपेक्ट रेशियो को बनाए रखा जाता है. इसके अलावा, गतिविधि के डिसप्ले एरिया में बदलाव होने पर, उपयोगकर्ता को गतिविधि फिर से शुरू करने का विकल्प दिया जाता है.
डिवाइस को अनफ़ोल्ड करने पर, ऐक्टिविटी के कॉन्फ़िगरेशन, साइज़, और आसपेक्ट रेशियो में कोई बदलाव नहीं होता. हालांकि, ऐक्टिविटी को फिर से शुरू करने का विकल्प दिखता है.
अगर resizeableActivity को सेट नहीं किया जाता है या इसे true पर सेट किया जाता है, तो ऐप्लिकेशन का साइज़ बदलने की सुविधा पूरी तरह से काम करती है.
लागू करना
जिस गतिविधि का साइज़ नहीं बदला जा सकता और जिसका ओरिएंटेशन या आसपेक्ट रेशियो तय होता है उसे कोड में साइज़ कंपैटिबिलिटी मोड (एससीएम) कहा जाता है. शर्त ActivityRecord#shouldUseSizeCompatMode() में बताई गई है. एससीएम ऐक्टिविटी लॉन्च होने पर, स्क्रीन से जुड़ा कॉन्फ़िगरेशन (जैसे, साइज़ या सघनता) अनुरोध किए गए ओवरराइड कॉन्फ़िगरेशन में निश्चित हो जाता है. इसलिए, ऐक्टिविटी अब मौजूदा डिसप्ले कॉन्फ़िगरेशन पर डिपेंडेंसी नहीं रहती.
अगर एससीएम ऐक्टिविटी पूरी स्क्रीन पर नहीं दिखती है, तो उसे सबसे ऊपर अलाइन किया जाता है और हॉरिज़ॉन्टल तौर पर बीच में रखा जाता है. गतिविधि की सीमाओं का हिसाब AppWindowToken#calculateCompatBoundsTransformation() लगाता है.
जब कोई एससीएम ऐक्टिविटी, अपने कंटेनर से अलग स्क्रीन कॉन्फ़िगरेशन का इस्तेमाल करती है (उदाहरण के लिए, डिसप्ले का साइज़ बदला जाता है या ऐक्टिविटी को किसी दूसरे डिसप्ले पर ले जाया जाता है), तो ActivityRecord#inSizeCompatMode() सही होता है. साथ ही, SizeCompatModeActivityController (सिस्टम यूज़र इंटरफ़ेस में) को प्रोसेस रीस्टार्ट करने का बटन दिखाने के लिए, कॉलबैक मिलता है.
डिसप्ले साइज़ और आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात)
Android 10 में, नए आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) के लिए सहायता मिलती है. इसमें लंबी और पतली स्क्रीन के ज़्यादा रेशियो से लेकर 1:1 रेशियो तक शामिल हैं. ऐप्लिकेशन, स्क्रीन के ApplicationInfo#maxAspectRatio और ApplicationInfo#minAspectRatio को तय कर सकते हैं.

पहली इमेज. Android 10 में काम करने वाले ऐप्लिकेशन के रेशियो का उदाहरण
डिवाइसों में, Android 9 और इससे पहले के वर्शन के लिए ज़रूरी साइज़ और रिज़ॉल्यूशन से छोटे साइज़ और रिज़ॉल्यूशन वाले सेकंडरी डिसप्ले हो सकते हैं. इनका साइज़ कम से कम 2.5 इंच चौड़ा या लंबा और smallestScreenWidth के लिए कम से कम 320 डीपी होना चाहिए. हालांकि, सिर्फ़ वे गतिविधियां इन छोटे डिसप्ले पर रखी जा सकती हैं जिन्होंने इन छोटे डिसप्ले के साथ काम करने की सुविधा के लिए ऑप्ट-इन किया है.
ऐप्लिकेशन, कम से कम साइज़ का एलान करके ऑप्ट इन कर सकते हैं. यह साइज़, टारगेट डिसप्ले साइज़ से कम या उसके बराबर होना चाहिए. इसके लिए, AndroidManifest में android:minHeight और android:minWidth गतिविधि लेआउट एट्रिब्यूट का इस्तेमाल करें.
डिसप्ले नीतियां
Android 10, कुछ डिसप्ले नीतियों को डिफ़ॉल्ट WindowManagerPolicy से अलग करता है और उन्हें PhoneWindowManager में हर डिसप्ले क्लास में ले जाता है. जैसे:
- डिसप्ले की स्थिति और रोटेशन
- कुछ कुंजियों और मोशन इवेंट की ट्रैकिंग
- सिस्टम यूज़र इंटरफ़ेस (यूआई) और डेकोरेशन विंडो
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 में बदलाव किए गए हैं, ताकि एक स्टेबल आइडेंटिफ़ायर जोड़ा जा सके. साथ ही, लोकल, नेटवर्क, और वर्चुअल डिसप्ले के बीच अंतर किया जा सके.
| डिसप्ले का टाइप | फ़ॉर्मैट |
|---|---|
| स्थानीय | 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 में ले जाया गया है.