इन्फ़ॉर्मेशन आर्किटेक्चर

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

उदाहरण और सोर्स

सेटिंग के ज़्यादातर पेजों पर, फ़िलहाल नए फ़्रेमवर्क का इस्तेमाल किया जा रहा है. इसका एक अच्छा उदाहरण DisplaySettings है: packages/apps/Settings/src/com/android/settings/DisplaySettings.java

अहम कॉम्पोनेंट के लिए फ़ाइल पाथ यहां दिए गए हैं:

  • CategoryKey: packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
  • DashboardFragmentRegistry: packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
  • DashboardFragment: packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragment.java
  • AbstractPreferenceController: frameworks/base/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
  • BasePreferenceController (Android 9 में पेश किया गया): packages/apps/Settings/src/com/android/settings/core/BasePreferenceController.java

लागू करना

डिवाइस बनाने वाली कंपनियों को सलाह दी जाती है कि वे मौजूदा सेटिंग की जानकारी के आर्किटेक्चर को अपनाएं. साथ ही, पार्टनर से जुड़ी सुविधाओं को शामिल करने के लिए, ज़रूरत के हिसाब से सेटिंग के अतिरिक्त पेज डालें. लेगसी पेज (SettingsPreferencePage के तौर पर लागू किया गया) से नई सेटिंग (DashboardFragment का इस्तेमाल करके लागू किया गया) पर प्राथमिकताएं ट्रांसफ़र करना मुश्किल हो सकता है. ऐसा हो सकता है कि लेगसी पेज पर सेट की गई प्राथमिकता को PreferenceController के साथ लागू न किया गया हो.

इसलिए, किसी लेगसी पेज से नई पेज पर कोई सेटिंग ट्रांसफ़र करते समय, आपको PreferenceController बनाना होगा. साथ ही, कोड को कंट्रोलर में ले जाना होगा. इसके बाद, उसे नए DashboardFragment में इंस्टैंशिएट करना होगा. जिन एपीआई की PreferenceControllerज़रूरत होती है उनके बारे में उनके नाम में बताया गया है. साथ ही, Javadoc में उनके बारे में जानकारी दी गई है.

हमारा सुझाव है कि हर PreferenceController के लिए यूनिट टेस्ट जोड़ें. अगर बदलाव को AOSP में सबमिट किया जाता है, तो यूनिट टेस्ट करना ज़रूरी है. Robolectric पर आधारित टेस्ट लिखने के तरीके के बारे में ज़्यादा जानकारी पाने के लिए, readme फ़ाइल packages/apps/Settings/tests/robotests/README.md देखें.

प्लगिन-स्टाइल वाला इन्फ़ॉर्मेशन आर्किटेक्चर

सेटिंग के हर आइटम को Preference के तौर पर लागू किया जाता है. प्राथमिकता को एक पेज से दूसरे पेज पर आसानी से ले जाया जा सकता है.

Android 8.0 में, प्लगिन-स्टाइल वाला होस्ट फ़्रैगमेंट पेश किया गया था. इसमें सेटिंग के आइटम शामिल होते हैं. इससे कई सेटिंग को एक जगह से दूसरी जगह ले जाना आसान हो जाता है. सेटिंग आइटम को प्लगिन-स्टाइल कंट्रोलर के तौर पर मॉडल किया जाता है. इसलिए, सेटिंग पेज को एक होस्ट फ़्रैगमेंट और कई सेटिंग कंट्रोलर से बनाया जाता है.

DashboardFragment

DashboardFragment, प्लगिन-स्टाइल वाले प्रेफ़रंस कंट्रोलर का होस्ट है. यह फ़्रैगमेंट, PreferenceFragment से इनहेरिट करता है. इसमें स्टैटिक और डाइनैमिक, दोनों तरह की प्राथमिकता वाली सूचियों को बड़ा करने और अपडेट करने के लिए हुक होते हैं.

स्टैटिक प्राथमिकताएं

स्टैटिक प्राथमिकता सूची को एक्सएमएल में <Preference> टैग का इस्तेमाल करके तय किया जाता है. DashboardFragment लागू करने के लिए, getPreferenceScreenResId() तरीके का इस्तेमाल किया जाता है. इससे यह तय किया जाता है कि किस एक्सएमएल फ़ाइल में, दिखाने के लिए प्राथमिकताओं की स्टैटिक सूची मौजूद है.

डाइनैमिक प्राथमिकताएं

डाइनैमिक आइटम, इंटेंट वाली टाइल को दिखाता है. इससे बाहरी या अंदरूनी ऐक्टिविटी पर जाया जा सकता है. आम तौर पर, इंटेंट से सेटिंग के किसी दूसरे पेज पर रीडायरेक्ट किया जाता है. उदाहरण के लिए, सेटिंग के होम पेज पर मौजूद "Google" सेटिंग आइटम, डाइनैमिक आइटम है. डाइनैमिक आइटम, AndroidManifest में तय किए जाते हैं. इनके बारे में यहां बताया गया है. इन्हें FeatureProvider के ज़रिए लोड किया जाता है. इसे DashboardFeatureProvider के तौर पर तय किया जाता है.

डाइनैमिक सेटिंग, स्टैटिक तौर पर कॉन्फ़िगर की गई सेटिंग की तुलना में ज़्यादा मेमोरी लेती हैं. इसलिए, आम तौर पर डेवलपर को सेटिंग को स्टैटिक सेटिंग के तौर पर लागू करना चाहिए. हालांकि, डाइनैमिक सेटिंग तब काम आ सकती है, जब इनमें से कोई भी स्थिति सही हो:

  • सेटिंग को सीधे तौर पर Settings ऐप्लिकेशन में लागू नहीं किया जाता है. जैसे, ओईएम/कैरियर ऐप्लिकेशन की ओर से लागू की गई सेटिंग को इंजेक्ट करना.
  • यह सेटिंग, सेटिंग के होम पेज पर दिखनी चाहिए.
  • आपके पास सेटिंग के लिए पहले से ही कोई गतिविधि है और आपको अतिरिक्त स्टैटिक कॉन्फ़िगरेशन लागू नहीं करना है.

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

  • गतिविधि को डाइनैमिक सेटिंग के तौर पर मार्क करें. इसके लिए, गतिविधि में इंटेंट-फ़िल्टर जोड़ें.
  • सेटिंग ऐप्लिकेशन को बताएं कि यह किस कैटगरी से जुड़ा है. कैटगरी एक कॉन्स्टेंट है, जिसे CategoryKey में तय किया गया है.
  • ज़रूरी नहीं: सेटिंग दिखने पर खास जानकारी वाला टेक्स्ट जोड़ें.

यहां DisplaySettings के लिए, सेटिंग ऐप्लिकेशन से लिया गया एक उदाहरण दिया गया है.

<activity android:name="Settings$DisplaySettingsActivity"
                   android:label="@string/display_settings"
                   android:icon="@drawable/ic_settings_display">
             <!-- Mark the activity as a dynamic setting -->
              <intent-filter>
                     <action android:name="com.android.settings.action.IA_SETTINGS" />
              </intent-filter>
             <!-- Tell Settings app which category it belongs to -->
              <meta-data android:name="com.android.settings.category"
                     android:value="com.android.settings.category.ia.homepage" />
             <!-- Add a summary text when the setting is displayed -->
              <meta-data android:name="com.android.settings.summary"
                     android:resource="@string/display_dashboard_summary"/>
             </activity>

रेंडर करने के समय, फ़्रैगमेंट स्टैटिक एक्सएमएल और AndroidManifest में तय की गई डाइनैमिक सेटिंग, दोनों से प्राथमिकताओं की सूची मांगेगा. PreferenceController, यह तय करता है कि PreferenceController को Java कोड या XML में तय किया गया है या नहीं. साथ ही, यह PreferenceController के ज़रिए हर सेटिंग के हैंडलिंग लॉजिक को मैनेज करता है (इसके बारे में यहां बताया गया है).DashboardFragment इसके बाद, उन्हें यूज़र इंटरफ़ेस (यूआई) में एक मिक्स लिस्ट के तौर पर दिखाया जाता है.

PreferenceController

Android 9 और Android 8.x में PreferenceController लागू करने के तरीके में अंतर है. इसके बारे में इस सेक्शन में बताया गया है.

Android 9 रिलीज़ में PreferenceController

PreferenceController में, प्राथमिकता से इंटरैक्ट करने के लिए सभी लॉजिक शामिल होते हैं. जैसे, प्राथमिकता दिखाना, अपडेट करना, खोज इंडेक्सिंग वगैरह.

PreferenceController का इंटरफ़ेस BasePreferenceController के तौर पर तय किया गया है. उदाहरण के लिए, packages/apps/Settings/src/com/android/settings/core/ BasePreferenceController.java में दिया गया कोड देखें

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

BasePreferenceController में getAvailabilityStatus(), displayPreference(), handlePreferenceTreeClicked(), जैसे एपीआई हैं. हर एपीआई के बारे में ज़्यादा जानकारी देने वाला दस्तावेज़, इंटरफ़ेस क्लास में मौजूद है.

BasePreferenceController (और इसके सबक्लास, जैसे कि TogglePreferenceController) को लागू करने पर यह पाबंदी है कि कंस्ट्रक्टर सिग्नेचर इनमें से किसी एक से मेल खाना चाहिए:

  • public MyController(Context context, String key) {}
  • public MyController(Context context) {}

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

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

Android 8.x वर्शन में PreferenceController

PreferenceController में, प्राथमिकताओं के साथ इंटरैक्ट करने का पूरा लॉजिक शामिल होता है. जैसे, प्राथमिकताएं दिखाना, उन्हें अपडेट करना, और खोज के लिए इंडेक्स करना वगैरह.

पसंद के हिसाब से इंटरैक्शन के लिए, PreferenceController के इंटरफ़ेस में isAvailable(), displayPreference(), handlePreferenceTreeClicked() वगैरह एपीआई होते हैं. हर एपीआई के बारे में ज़्यादा जानकारी देने वाला दस्तावेज़, इंटरफ़ेस क्लास में देखा जा सकता है.

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

DashboardFragment, स्क्रीन पर PreferenceControllers की सूची को सेव करता है. फ़्रैगमेंट के onCreate() पर, सभी कंट्रोलर को isAvailable() तरीके के लिए शुरू किया जाता है. अगर यह सही वैल्यू दिखाता है, तो displayPreference() को डिसप्ले लॉजिक को प्रोसेस करने के लिए शुरू किया जाता है.

DashboardFragment का इस्तेमाल करना

प्राथमिकता को पेज A से B पर ले जाना

अगर प्राथमिकता, ओरिजनल पेज की प्राथमिकता वाली एक्सएमएल फ़ाइल में स्टैटिक तौर पर लिस्ट की गई है, तो Android के वर्शन के हिसाब से, नीचे दिए गए स्टैटिक मूव करने का तरीका अपनाएं. अगर ऐसा नहीं है, तो Android रिलीज़ के लिए, डाइनैमिक तरीके से ऐप्लिकेशन को एक ट्रैक से दूसरे ट्रैक पर ले जाने की प्रक्रिया अपनाएं.

Android 9 में स्टैटिक मूव

  1. मूल पेज और डेस्टिनेशन पेज के लिए, प्राथमिकता वाली एक्सएमएल फ़ाइलें ढूंढें. यह जानकारी, पेज के getPreferenceScreenResId() तरीके से देखी जा सकती है.
  2. ओरिजनल पेज के एक्सएमएल से प्राथमिकता हटाएं.
  3. डेस्टिनेशन पेज के एक्सएमएल में प्राथमिकता जोड़ें.
  4. इस प्राथमिकता के लिए PreferenceController को, ओरिजनल पेज के Java कोड से हटाएं. आम तौर पर, यह createPreferenceControllers() में होता है. कंट्रोलर को सीधे तौर पर एक्सएमएल में भी सेट किया जा सकता है.

    ध्यान दें: ऐसा हो सकता है कि प्राथमिकता में PreferenceController न हो.

  5. डेस्टिनेशन पेज के createPreferenceControllers() में PreferenceController को इंस्टैंशिएट करें. अगर पुराने पेज के एक्सएमएल में PreferenceController को तय किया गया है, तो नए पेज के एक्सएमएल में भी इसे तय करें.

Android 9 में डाइनैमिक मूव

  1. पता लगाएं कि ओरिजनल और डेस्टिनेशन पेज किस कैटगरी में होस्ट किए जाते हैं. यह जानकारी DashboardFragmentRegistry में देखी जा सकती है.
  2. वह AndroidManifest.xml फ़ाइल खोलें जिसमें वह सेटिंग मौजूद है जिसे आपको ट्रांसफ़र करना है. इसके बाद, इस सेटिंग को दिखाने वाली गतिविधि की एंट्री ढूंढें.
  3. com.android.settings.category के लिए गतिविधि के मेटाडेटा की वैल्यू को नए पेज की कैटगरी की कुंजी पर सेट करें.

Android 8.x वर्शन में स्टैटिक मूव

  1. मूल पेज और डेस्टिनेशन पेज के लिए, प्राथमिकता वाली एक्सएमएल फ़ाइलें ढूंढें.
  2. यह जानकारी, पेज के getPreferenceScreenResId() तरीके से देखी जा सकती है.
  3. मूल पेज के एक्सएमएल से प्राथमिकता हटाएं.
  4. डेस्टिनेशन पेज के एक्सएमएल में प्राथमिकता जोड़ें.
  5. मूल पेज के Java कोड में, इस प्राथमिकता के लिए PreferenceController हटाएं. आम तौर पर, यह getPreferenceControllers() में होता है.
  6. ध्यान दें: ऐसा हो सकता है कि प्राथमिकता में कोई PreferenceController न हो.

  7. डेस्टिनेशन पेज के getPreferenceControllers() में PreferenceController को इंस्टैंशिएट करें.

Android 8.x के वर्शन में डाइनैमिक मूव

  1. पता लगाएं कि ओरिजनल और डेस्टिनेशन पेज किस कैटगरी में होस्ट किए जाते हैं. यह जानकारी DashboardFragmentRegistry में देखी जा सकती है.
  2. वह AndroidManifest.xml फ़ाइल खोलें जिसमें वह सेटिंग मौजूद है जिसे आपको ट्रांसफ़र करना है. इसके बाद, इस सेटिंग को दिखाने वाली गतिविधि की एंट्री ढूंढें.
  3. com.android.settings.category के लिए गतिविधि के मेटाडेटा की वैल्यू बदलें. साथ ही, वैल्यू पॉइंट को नए पेज की कैटगरी की कुंजी पर सेट करें.

किसी पेज में नई प्राथमिकता बनाना

अगर प्राथमिकता को ओरिजनल पेज की प्राथमिकता वाली एक्सएमएल फ़ाइल में स्टैटिक तौर पर लिस्ट किया गया है, तो यहां दी गई स्टैटिक प्रक्रिया अपनाएं. इसके अलावा, डाइनैमिक तरीका अपनाएं.

स्टैटिक प्राथमिकता बनाना

  1. पेज के लिए, प्राथमिकता वाली एक्सएमएल फ़ाइलें ढूंढें. आपको यह जानकारी, पेज के getPreferenceScreenResId() तरीके से मिल सकती है.
  2. एक्सएमएल में नया Preference आइटम जोड़ें. पक्का करें कि इसमें यूनीक android:key हो.
  3. पेज के getPreferenceControllers() तरीके में, इस प्राथमिकता के लिए PreferenceController तय करें.
    • Android 8.x और Android 9 में, इस सेटिंग के लिए PreferenceController को पेज के createPreferenceControllers() तरीके में इंस्टैंशिएट करें.

      अगर यह सेटिंग पहले से ही किसी दूसरी जगह पर मौजूद है, तो हो सकता है कि इसके लिए PreferenceController पहले से मौजूद हो. नई PreferenceController बनाने के बजाय, इसका फिर से इस्तेमाल किया जा सकता है.

    • Android 9 से, प्राथमिकता के बगल में मौजूद एक्सएमएल में PreferenceController को शामिल किया जा सकता है. उदाहरण के लिए:
      <Preference
              android:key="reset_dashboard"
              android:title="@string/reset_dashboard_title"
              settings:controller="com.android.settings.system.ResetPreferenceController"/>

डाइनैमिक प्राथमिकता बनाना

  1. पता लगाएं कि ओरिजनल और डेस्टिनेशन पेज किस कैटगरी में होस्ट किए जाते हैं. यह जानकारी DashboardFragmentRegistry में देखी जा सकती है.
  2. AndroidManifest में नई गतिविधि बनाना
  3. सेटिंग तय करने के लिए, नई गतिविधि में ज़रूरी मेटाडेटा जोड़ें. com.android.settings.category के लिए मेटाडेटा वैल्यू को वही वैल्यू सेट करें जो पहले चरण में तय की गई थी.

एक नया पेज बनाएं

  1. DashboardFragment से इनहेरिट करने वाला नया फ़्रैगमेंट बनाएं.
  2. DashboardFragmentRegistry में इसकी कैटगरी तय करें.

    ध्यान दें: यह चरण ज़रूरी नहीं है. अगर आपको इस पेज पर किसी डाइनैमिक सेटिंग की ज़रूरत नहीं है, तो आपको कैटगरी की कुंजी देने की ज़रूरत नहीं है.

  3. इस पेज के लिए ज़रूरी सेटिंग जोड़ने का तरीका अपनाएं. ज़्यादा जानकारी के लिए, लागू करना सेक्शन देखें.

Validation

  • सेटिंग में जाकर, Robolectric टेस्ट चलाएँ. सभी मौजूदा और नए टेस्ट पास होने चाहिए.
  • सेटिंग बनाएं और इंस्टॉल करें. इसके बाद, जिस पेज में बदलाव किया जा रहा है उसे मैन्युअल तरीके से खोलें. पेज तुरंत अपडेट हो जाना चाहिए.