डिसप्ले सपोर्ट

डिसप्ले के हिसाब से इन सेक्शन में किए गए अपडेट यहां दिए गए हैं:

गतिविधियों और डिसप्ले का साइज़ बदलना

resizeableActivity=false एट्रिब्यूट का इस्तेमाल करके यह बताया जा सकता है कि हो सकता है कि कोई ऐप्लिकेशन, मल्टी-विंडो मोड या साइज़ बदलने की सुविधा के साथ काम न करे. ऐक्टिविटी का साइज़ बदलने पर, ऐप्लिकेशन को ये सामान्य समस्याएं आ सकती हैं:

  • किसी ऐक्टिविटी का कॉन्फ़िगरेशन, ऐप्लिकेशन या किसी अन्य विज़ुअल कॉम्पोनेंट से अलग हो सकता है. ऐप्लिकेशन के कॉन्टेक्स्ट से डिसप्ले मेट्रिक पढ़ना एक आम गलती है. दिखाई गई वैल्यू, दिखने वाले उस एरिया की मेट्रिक में अडजस्ट नहीं की जाएंगी जिसमें कोई गतिविधि दिखती है.
  • ऐसा हो सकता है कि कोई गतिविधि, साइज़ बदलने की सुविधा को हैंडल न कर पाए और क्रैश हो जाए. इसके अलावा, ऐसा भी हो सकता है कि वह गलत यूज़र इंटरफ़ेस (यूआई) दिखाए या इंस्टेंस की स्थिति को सेव किए बिना उसे फिर से शुरू करने की वजह से, उसकी स्थिति बदल जाए.
  • कोई ऐप्लिकेशन, विंडो की पोज़िशन के हिसाब से इनपुट कोऑर्डिनेट के बजाय, एब्सोलूट इनपुट कोऑर्डिनेट का इस्तेमाल कर सकता है. इससे मल्टी-विंडो में इनपुट काम नहीं कर सकता.

Android 7 (और इसके बाद के वर्शन) में, किसी ऐप्लिकेशन को हमेशा फ़ुल स्क्रीन मोड में चलाने के लिए सेट किया जा सकता है.resizeableActivity=false इस मामले में, प्लैटफ़ॉर्म उन गतिविधियों को स्प्लिट स्क्रीन में जाने से रोकता है जिनका साइज़ नहीं बदला जा सकता. अगर उपयोगकर्ता स्प्लिट-स्क्रीन मोड में होने के बावजूद, लॉन्चर से ऐसी गतिविधि शुरू करने की कोशिश करता है जिसका साइज़ नहीं बदला जा सकता, तो प्लैटफ़ॉर्म स्प्लिट-स्क्रीन मोड से बाहर निकल जाता है और साइज़ न बदलने वाली गतिविधि को फ़ुल-स्क्रीन मोड में लॉन्च करता है.

जिन ऐप्लिकेशन ने मेनिफ़ेस्ट में इस एट्रिब्यूट को साफ़ तौर पर false पर सेट किया है उन्हें मल्टी-विंडो मोड में तब तक लॉन्च नहीं किया जाना चाहिए, जब तक कि साथ काम करने वाला मोड लागू न हो:

  • प्रोसेस पर वही कॉन्फ़िगरेशन लागू होता है जिसमें सभी गतिविधियां और गैर-गतिविधि कॉम्पोनेंट शामिल होते हैं.
  • लागू किया गया कॉन्फ़िगरेशन, ऐप्लिकेशन के साथ काम करने वाले डिसप्ले के लिए सीडीडी की ज़रूरी शर्तों को पूरा करता हो.

Android 10 में, प्लैटफ़ॉर्म अब भी उन गतिविधियों को स्प्लिट-स्क्रीन मोड में जाने से रोकता है जिन्हें स्क्रीन के साइज़ के हिसाब से नहीं बदला जा सकता. हालांकि, अगर गतिविधि के लिए कोई तय ओरिएंटेशन या आसपेक्ट रेशियो तय किया गया है, तो उन्हें कुछ समय के लिए स्केल किया जा सकता है. अगर ऐसा नहीं है, तो ऐक्टिविटी का साइज़ बदलकर पूरी स्क्रीन पर दिखने लगता है. ऐसा Android 9 और उससे पहले के वर्शन में होता है.

डिफ़ॉल्ट रूप से लागू होने वाली नीति के तहत, यह सुविधा इस तरह काम करती है:

जब किसी गतिविधि को android:resizeableActivity एट्रिब्यूट के इस्तेमाल से, मल्टी-विंडो के साथ काम न करने वाला बताया गया हो और वह गतिविधि यहां बताई गई किसी एक शर्त को पूरा करती हो, तो लागू किए गए स्क्रीन कॉन्फ़िगरेशन में बदलाव होने पर, गतिविधि और प्रोसेस को मूल कॉन्फ़िगरेशन के साथ सेव किया जाता है. साथ ही, उपयोगकर्ता को अपडेट किए गए स्क्रीन कॉन्फ़िगरेशन का इस्तेमाल करने के लिए, ऐप्लिकेशन प्रोसेस को फिर से शुरू करने का विकल्प दिया जाता है.

  • क्या android:screenOrientation का इस्तेमाल करके, ओरिएंटेशन तय किया गया है
  • ऐप्लिकेशन में एपीआई लेवल को टारगेट करके, डिफ़ॉल्ट तौर पर ज़्यादा से ज़्यादा या कम से कम आसपेक्ट रेशियो सेट किया गया हो या आसपेक्ट रेशियो साफ़ तौर पर बताया गया हो

इस इमेज में, ऐसेपेक्ट रेशियो के साथ ऐसी गतिविधि दिखाई गई है जिसे बड़ा या छोटा नहीं किया जा सकता. डिवाइस को फ़ोल्ड करने पर, विंडो को आसपेक्ट रेशियो को बनाए रखते हुए, स्क्रीन पर फ़िट करने के लिए छोटा कर दिया जाता है. इसके लिए, लेटरबॉक्सिंग का इस्तेमाल किया जाता है. इसके अलावा, गतिविधि के डिसप्ले एरिया में बदलाव होने पर, उपयोगकर्ता को गतिविधि को फिर से शुरू करने का विकल्प दिया जाता है.

डिवाइस को अनफ़ोल्ड करने पर, ऐक्टिविटी का कॉन्फ़िगरेशन, साइज़, और आसपेक्ट रेशियो नहीं बदलता. हालांकि, ऐक्टिविटी को फिर से शुरू करने का विकल्प दिखता है.

जब resizeableActivity सेट नहीं होता है या इसे true पर सेट किया जाता है, तो ऐप्लिकेशन में साइज़ बदलने की सुविधा पूरी तरह से काम करती है.

लागू करना

कोड में, ऐसे ऐक्टिविटी को साइज़ कम्पैटिबिलिटी मोड (एससीएम) कहा जाता है जिसका ओरिएंटेशन या आसपेक्ट रेशियो तय होता है और जिसे बड़ा या छोटा नहीं किया जा सकता. शर्त के बारे में जानकारी ActivityRecord#shouldUseSizeCompatMode() में दी गई है. जब कोई SCM गतिविधि शुरू की जाती है, तो स्क्रीन से जुड़े कॉन्फ़िगरेशन (जैसे, साइज़ या डेंसिटी) को अनुरोध किए गए बदलाव वाले कॉन्फ़िगरेशन में तय कर दिया जाता है. इसलिए, गतिविधि अब मौजूदा डिसप्ले कॉन्फ़िगरेशन पर निर्भर नहीं रहती.

अगर SCM गतिविधि पूरी स्क्रीन को भर नहीं सकती, तो उसे सबसे ऊपर अलाइन किया जाता है और क्षैतिज रूप से बीच में रखा जाता है. गतिविधि की सीमाओं का हिसाब, AppWindowToken#calculateCompatBoundsTransformation() लगाता है.

जब कोई SCM गतिविधि, अपने कंटेनर से अलग स्क्रीन कॉन्फ़िगरेशन का इस्तेमाल करती है, तो ActivityRecord#inSizeCompatMode() सही होता है और SizeCompatModeActivityController (सिस्टम यूज़र इंटरफ़ेस (यूआई) में) को प्रोसेस को फिर से शुरू करने का बटन दिखाने के लिए कॉलबैक मिलता है. उदाहरण के लिए, डिसप्ले का साइज़ बदला जाता है या गतिविधि को किसी दूसरे डिसप्ले पर ले जाया जाता है.

डिसप्ले साइज़ और आसपेक्ट रेशियो

Android 10 में नए आसपेक्ट रेशियो का इस्तेमाल किया जा सकता है. जैसे, लंबी और पतली स्क्रीन के आसपेक्ट रेशियो से लेकर 1:1 आसपेक्ट रेशियो तक. ऐप्लिकेशन, स्क्रीन के उस ApplicationInfo#maxAspectRatio और ApplicationInfo#minAspectRatio को तय कर सकते हैं जिसे वे मैनेज कर सकते हैं.

Android 10 में ऐप्लिकेशन के अनुपात

पहली इमेज. Android 10 में काम करने वाले ऐप्लिकेशन के अनुपात का उदाहरण

डिवाइस पर लागू किए गए सेकंडरी डिसप्ले, Android 9 और उससे पहले के वर्शन के लिए ज़रूरी साइज़ और रिज़ॉल्यूशन से छोटे हो सकते हैं. जैसे, कम से कम 2.5 इंच चौड़ाई या ऊंचाई, smallestScreenWidth के लिए कम से कम 320 डीपी. हालांकि, इन छोटे डिसप्ले पर काम करने के लिए ऑप्ट-इन करने वाली ही गतिविधियों को वहां रखा जा सकता है.

ऐप्लिकेशन, टारगेट किए गए डिसप्ले साइज़ से कम या उसके बराबर का कम से कम साइज़ तय करके ऑप्ट-इन कर सकते हैं. ऐसा करने के लिए, 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 में बदलाव किया गया है, ताकि एक स्थिर आइडेंटिफ़ायर जोड़ा जा सके और स्थानीय, नेटवर्क, और वर्चुअल डिसप्ले के बीच अंतर किया जा सके.

डिसप्ले टाइप फ़ॉर्मैट
लोकल
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-बिट पोर्ट नंबर दिखाता है. यह नंबर, डिसप्ले आउटपुट के लिए फ़िज़िकल कनेक्टर की पहचान करता है. साथ ही, डिसप्ले के ईडीआईडी ब्लॉब की भी पहचान करता है. फ़्रेमवर्क के लिए दिखाए जाने वाले, स्थिर 64-बिट डिसप्ले आईडी जनरेट करने के लिए, SurfaceFlinger, EDID से मैन्युफ़ैक्चरर या मॉडल की जानकारी निकालता है. अगर यह तरीका काम नहीं करता है या गड़बड़ियां होती हैं, तो 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, स्थिर डिसप्ले आईडी जनरेट करने के लिए, हार्डवेयर कंपोजर (एचडब्ल्यूसी) एपीआई का फ़ायदा ले सकता है. इससे, यह किसी भी संख्या में फ़िज़िकल डिसप्ले मैनेज कर सकता है. ज़्यादा जानने के लिए, स्टैटिक डिसप्ले आइडेंटिफ़ायर देखें.

फ़्रेमवर्क, SurfaceControl#getPhysicalDisplayIds या DisplayEventReceiver hotplug इवेंट से 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, ईडीआईडी स्ट्रक्चर को पार्स करता है और फ़िज़िकल और एचडब्ल्यूसी वर्चुअल डिसप्ले के लिए, स्थिर 64-बिट डिसप्ले आईडी असाइन करता है. आईडी को किसी विकल्प के टाइप का इस्तेमाल करके दिखाया जाता है. यहां शून्य वैल्यू, अमान्य डिसप्ले या नॉन-एचडब्ल्यूसी वर्चुअल डिसप्ले को दिखाती है. HWC की सुविधा के बिना, SurfaceFlinger सबसे ज़्यादा दो फ़िज़िकल डिसप्ले के साथ, लेगसी व्यवहार पर वापस आ जाता है.

हर डिसप्ले के हिसाब से फ़ोकस

एक ही समय पर अलग-अलग डिसप्ले को टारगेट करने वाले कई इनपुट सोर्स के साथ काम करने के लिए, Android 10 को कॉन्फ़िगर किया जा सकता है. इससे, एक डिसप्ले पर ज़्यादा से ज़्यादा एक फ़ोकस वाली विंडो काम कर सकती है. यह सुविधा सिर्फ़ खास तरह के डिवाइसों के लिए है. जब एक ही समय पर एक से ज़्यादा उपयोगकर्ता एक ही डिवाइस से इंटरैक्ट करते हैं और अलग-अलग इनपुट तरीकों या डिवाइसों का इस्तेमाल करते हैं, तब यह सुविधा काम करती है. जैसे, Android Autoमोटिव.

हमारा सुझाव है कि इस सुविधा को सामान्य डिवाइसों के लिए चालू न करें. इनमें कई स्क्रीन वाले डिवाइस या डेस्कटॉप जैसे अनुभव देने वाले डिवाइस भी शामिल हैं. ऐसा मुख्य रूप से सुरक्षा से जुड़ी समस्या की वजह से होता है. इसकी वजह से, उपयोगकर्ताओं को यह पता नहीं चल पाता कि इनपुट फ़ोकस किस विंडो पर है.

मान लें कि कोई उपयोगकर्ता, टेक्स्ट इनपुट फ़ील्ड में सुरक्षित जानकारी डालता है. जैसे, बैंकिंग ऐप्लिकेशन में लॉग इन करना या संवेदनशील जानकारी वाला टेक्स्ट डालना. नुकसान पहुंचाने वाला ऐप्लिकेशन, टेक्स्ट इनपुट फ़ील्ड के साथ-साथ किसी गतिविधि को पूरा करने के लिए, वर्चुअल ऑफ़-स्क्रीन डिसप्ले बना सकता है. मान्य और नुकसान पहुंचाने वाली गतिविधियों पर फ़ोकस होता है. साथ ही, दोनों में एक ऐक्टिव इनपुट इंडिकेटर (पलक मारने वाला कर्सर) दिखता है.

हालांकि, कीबोर्ड (हार्डवेयर या सॉफ़्टवेयर) से मिलने वाला इनपुट सिर्फ़ सबसे ऊपर मौजूद गतिविधि (हाल ही में लॉन्च किया गया ऐप्लिकेशन) में डाला जाता है. इसलिए, छिपे हुए वर्चुअल डिसप्ले बनाकर, नुकसान पहुंचाने वाला ऐप्लिकेशन उपयोगकर्ता का इनपुट हासिल कर सकता है. भले ही, डिवाइस के मुख्य डिसप्ले पर सॉफ़्टवेयर कीबोर्ड का इस्तेमाल किया जा रहा हो.

हर डिसप्ले के लिए फ़ोकस सेट करने के लिए, 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() देखें. फ़ोकस किए गए ऐप्लिकेशन, NativeInputManager::setFocusedApplication() के ज़रिए InputManagerService में भी अलग से अपडेट किए जाते हैं.

WindowManager में, फ़ोकस की गई विंडो को भी अलग से ट्रैक किया जाता है. DisplayContent#mCurrentFocus और DisplayContent#mFocusedApp के साथ-साथ, उनके इस्तेमाल के बारे में जानें. फ़ोकस से जुड़ी ट्रैकिंग और अपडेट करने के तरीकों को WindowManagerService से DisplayContent पर ले जाया गया है.