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

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

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

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