कार के यूज़र इंटरफ़ेस (यूआई) के प्लगिन

कॉम्पोनेंट को पूरी तरह लागू करने के लिए, कार की यूज़र इंटरफ़ेस (यूआई) लाइब्रेरी के प्लग-इन का इस्तेमाल करें रनटाइम रिसॉर्स ओवरले के इस्तेमाल के बजाय, कार की यूज़र इंटरफ़ेस (यूआई) लाइब्रेरी में कस्टमाइज़ेशन के लिए (आरआरओ). आरआरओ की मदद से, कार की यूज़र इंटरफ़ेस (यूआई) लाइब्रेरी के सिर्फ़ एक्सएमएल संसाधनों को बदला जा सकता है कॉम्पोनेंट, जो आपकी पसंद के मुताबिक बनाने की सीमा तय करते हैं.

प्लग इन बनाएं

कार के यूज़र इंटरफ़ेस (यूआई) की लाइब्रेरी का प्लगिन एक ऐसा APK होता है जिसमें ऐसी क्लास शामिल होती हैं जो प्लग इन एपीआई. प्लग इन एपीआई को प्लग इन को एक स्थिर लाइब्रेरी के रूप में रखता है.

सूंग और ग्रेडल में उदाहरण देखें:

सूंग

सूंग के इस उदाहरण पर ध्यान दें:

android_app {
    name: "my-plugin",

    min_sdk_version: "28",
    target_sdk_version: "30",
    aaptflags: ["--shared-lib"],
    sdk_version: "current",

    manifest: "src/main/AndroidManifest.xml",
    srcs: ["src/main/java/**/*.java"],
    resource_dirs: ["src/main/res"],
    static_libs: [
        "car-ui-lib-oem-apis",
    ],
    // Disable optimization is mandatory to prevent R.java class from being
    // stripped out
    optimize: {
        enabled: false,
    },

    certificate: ":my-plugin-certificate",
}

ग्रेडल

यह build.gradle फ़ाइल देखें:

apply plugin: 'com.android.application'

android {
  compileSdkVersion 30

  defaultConfig {
    minSdkVersion 28
    targetSdkVersion 30
  }

  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }

  signingConfigs {
    debug {
      storeFile file('chassis_upload_key.jks')
      storePassword 'chassis'
      keyAlias 'chassis'
      keyPassword 'chassis'
    }
  }
}

dependencies {
  implementation project(':oem-apis')
  // Or use the following if you'd like to use the maven artifact
  // implementation 'com.android.car.ui:car-ui-lib-plugin-apis:1.0.0'
}

Settings.gradle:

// You can remove the ':oem-apis' if you're using the maven artifact.
include ':oem-apis'
project(':oem-apis').projectDir = new File('./path/to/oem-apis')
include ':my-plugin'
project(':my-plugin').projectDir = new File('./my-plugin')

प्लग इन के मेनिफ़ेस्ट में कॉन्टेंट देने वाले के बारे में जानकारी मौजूद होनी चाहिए ये एट्रिब्यूट दिखते हैं:

  android:authorities="com.android.car.ui.plugin"
  android:enabled="true"
  android:exported="true"

android:authorities="com.android.car.ui.plugin", प्लग इन को खोजे जाने लायक बनाता है कार की यूज़र इंटरफ़ेस (यूआई) लाइब्रेरी में जोड़ा जा सकता है. सेवा देने वाली कंपनी को एक्सपोर्ट करना ज़रूरी है, ताकि उससे इस पर क्वेरी की जा सके रनटाइम. साथ ही, अगर enabled एट्रिब्यूट को false पर सेट किया जाता है, तो डिफ़ॉल्ट तौर पर ऐसा होता है प्लगिन को लागू करने के बजाय, लागू करने की प्रोसेस का इस्तेमाल किया जाएगा. कॉन्टेंट provider क्लास मौजूद नहीं होनी चाहिए. जिस स्थिति में, tools:ignore="MissingClass" को प्रोवाइडर की परिभाषा में जोड़ा गया. सैंपल देखें मेनिफ़ेस्ट एंट्री नीचे दी गई है:

    <application>
        <provider
            android:name="com.android.car.ui.plugin.PluginNameProvider"
            android:authorities="com.android.car.ui.plugin"
            android:enabled="false"
            android:exported="true"
            tools:ignore="MissingClass"/>
    </application>

आखिर में, सुरक्षा उपाय के तौर पर, अपने ऐप्लिकेशन पर हस्ताक्षर करना.

शेयर की गई लाइब्रेरी के रूप में प्लगिन

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

Android की शेयर की गई लाइब्रेरी के तौर पर लागू किए गए प्लगिन की क्लास ऐप्लिकेशन के बीच शेयर किए गए क्लासलोडर में अपने-आप जुड़ जाता है. जब किसी ऐप्लिकेशन को कार की यूज़र इंटरफ़ेस (यूआई) लाइब्रेरी का इस्तेमाल करता है, रनटाइम डिपेंडेंसी प्लगिन की शेयर लाइब्रेरी पर है, इसके classloader, प्लग इन शेयर की गई लाइब्रेरी की क्लास ऐक्सेस कर सकता है. लागू किए गए प्लगिन सामान्य Android ऐप्लिकेशन (शेयर की गई लाइब्रेरी नहीं) की तरह, ऐप्लिकेशन को ठंडा रखने वाला ऐप्लिकेशन शुरू होने का समय.

शेयर की गई लाइब्रेरी लागू करना और बनाना

Android की शेयर की गई लाइब्रेरी की सुविधा को किसी भी सामान्य Android डिवाइस में इस्तेमाल नहीं किया जा सकता कुछ मुख्य अंतरों के साथ दिखाई देते हैं.

  • प्लगिन पैकेज के साथ, application टैग के नीचे मौजूद library टैग का इस्तेमाल करें नाम:
    <application>
        <library android:name="com.chassis.car.ui.plugin" />
        ...
    </application>
  • AAPT के साथ अपने सूंग android_app बिल्ड नियम (Android.bp) को कॉन्फ़िगर करें shared-lib को फ़्लैग करें, जिसका इस्तेमाल शेयर की गई लाइब्रेरी बनाने के लिए किया जाता है:
android_app {
  ...
  aaptflags: ["--shared-lib"],
  ...
}

शेयर की गई लाइब्रेरी पर निर्भरता

कार की यूज़र इंटरफ़ेस (यूआई) लाइब्रेरी का इस्तेमाल करने वाले सिस्टम पर मौजूद हर ऐप्लिकेशन के लिए, uses-library टैग के नीचे, ऐप्लिकेशन मेनिफ़ेस्ट में प्लग इन पैकेज नाम के साथ application टैग:

<manifest>
  <application
      android:name=".MyApp"
      ...>
    <uses-library android:name="com.chassis.car.ui.plugin" android:required="false"/>
    ...
  </application>
</manifest>

प्लग इन इंस्टॉल करना

मॉड्यूल को शामिल करके, सिस्टम पार्टिशन में प्लगिन पहले से इंस्टॉल होने चाहिए PRODUCT_PACKAGES में. पहले से इंस्टॉल किए गए पैकेज को इसी तरह अपडेट किया जा सकता है: इंस्टॉल किए गए ऐप्लिकेशन को नहीं खरीद सकते.

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

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

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

Android Studio का प्लगिन कॉन्फ़िगरेशन अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है पहली इमेज. Android Studio का प्लगिन कॉन्फ़िगरेशन

प्रॉक्सी प्लगिन

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

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

प्रॉक्सी प्लगिन, सिर्फ़ एक उदाहरण है. साथ ही, यह इसका इस्तेमाल करके कस्टमाइज़ेशन करने के लिए, शुरुआती पॉइंट है प्लग इन. आरआरओ के अलावा किसी अन्य प्लगिन को अपनी ज़रूरत के मुताबिक बनाने के लिए, प्लगिन का सबसेट लागू किया जा सकता है कॉम्पोनेंट और बाकी प्लगिन के लिए प्रॉक्सी प्लगिन का इस्तेमाल करें या सभी प्लगिन लागू करें पूरी तरह से शुरुआत से बनाया गया है.

हालांकि, प्रॉक्सी प्लगिन, ऐप्लिकेशन के लिए एक ही जगह पर RRO को पसंद के मुताबिक बनाने की सुविधा देता है, जो ऐप्लिकेशन प्लगिन के इस्तेमाल से ऑप्ट-आउट होते हैं उन्हें अब भी RRO की ज़रूरत होगी ऐप्लिकेशन को टारगेट करता हो.

प्लग इन एपीआई लागू करें

प्लगिन का मुख्य एंट्रीपॉइंट है com.android.car.ui.plugin.PluginVersionProviderImpl क्लास. सभी प्लगिन को यह आवश्यक है इसी नाम और पैकेज नाम वाली क्लास शामिल करें. इस क्लास में डिफ़ॉल्ट कंस्ट्रक्टर है और PluginVersionProviderOEMV1 इंटरफ़ेस को लागू करता है.

CarUi प्लगिन, उन ऐप्लिकेशन के साथ काम करने चाहिए जो प्लगिन से पुराने या नए हैं. यहां की यात्रा पर हूं इसे सुविधा देने के लिए, सभी प्लगिन एपीआई का वर्शन, उनके वर्शन के आखिर में V# क्लास का नाम. अगर कार की यूज़र इंटरफ़ेस (यूआई) लाइब्रेरी का नया वर्शन, नई सुविधाओं के साथ रिलीज़ किया जाता है, तो ये कॉम्पोनेंट के V2 वर्शन का हिस्सा होते हैं. कार की यूज़र इंटरफ़ेस (यूआई) लाइब्रेरी, पुराने प्लग इन कॉम्पोनेंट के दायरे में नई सुविधाएं काम करें. उदाहरण के लिए, टूलबार में एक नए टाइप के बटन को MenuItems में बदलकर.

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

PluginVersionProviderOEMV1 में एक तरीका है:

Object getPluginFactory(int maxVersion, Context context, String packageName);

यह तरीका ऐसा ऑब्जेक्ट दिखाता है जो PluginFactoryOEMV# प्लग इन के साथ काम करता है, लेकिन यह इससे कम है या maxVersion के बराबर है. अगर किसी प्लग इन में PluginFactory पुराना है, तो यह null लौटा सकता है, इस मामले में स्थिर- CarUi कॉम्पोनेंट को लागू करने की प्रोसेस, लिंक किए गए तरीकों का इस्तेमाल किया जाता है.

उन ऐप्लिकेशन के साथ पुराने सिस्टम से काम करने की सुविधा बनाए रखने के लिए जिन्हें कंपाइल किया गया है स्थिर Car Ui लाइब्रेरी के पुराने वर्शन के साथ-साथ, आपके प्लग इन को लागू करने के दौरान, 2, 5, और उसके बाद के maxVersion PluginVersionProvider क्लास. वर्शन 1, 3, और 4 काम नहीं करते. इसके लिए ज़्यादा जानकारी के लिए, देखें PluginVersionProviderImpl.

PluginFactory ऐसा इंटरफ़ेस है जो बाकी सभी CarUi बनाता है कॉम्पोनेंट. इससे यह भी तय होता है कि उनके इंटरफ़ेस के किस वर्शन का इस्तेमाल किया जाना चाहिए. अगर आपने प्लगिन इनमें से किसी भी कॉम्पोनेंट को लागू करने की कोशिश नहीं करता है. यह वापस आ सकता है null उनके निर्माण फ़ंक्शन में (टूलबार को छोड़कर, जिसमें एक अलग customizesBaseLayout() फ़ंक्शन).

pluginFactory तय करता है कि CarUi कॉम्पोनेंट के कौनसे वर्शन इस्तेमाल किए जा सकते हैं हैं बेमिसाल. उदाहरण के लिए, कोई pluginFactory नहीं बना सकता Toolbar का 100 वर्शन और RecyclerView का 1 भी वर्शन है. शायद इस बात की कोई गारंटी नहीं है कि कॉम्पोनेंट की ज़्यादा रेंज एक साथ कैसे काम करते हैं. टूलबार के वर्शन 100 का इस्तेमाल करने के लिए, डेवलपर से उम्मीद की जाती है कि pluginFactory का ऐसा वर्शन उपलब्ध कराएं जो वाला टूलबार वर्शन 100, जो इसके बाद अन्य इन्हें बनाया जा सकता है. अन्य कॉम्पोनेंट के वर्शन बराबर है, उदाहरण के लिए, pluginFactoryOEMV100 से ToolbarControllerOEMV100 और RecyclerViewOEMV70.

टूलबार

बेस लेआउट

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

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

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

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

कॉन्टेंट को टूलबार के नीचे स्क्रोल किया जा रहा है अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है दूसरी इमेज. कॉन्टेंट को टूलबार के नीचे स्क्रोल किया जा रहा है

ऐप्लिकेशन के हिसाब से, जब प्लगिन नए इनसेट भेजेगा, तो उसे InsetsChangedListener को लागू करने वाली किसी भी गतिविधि या फ़्रैगमेंट से उन्हें हटा दें. अगर आपने कोई गतिविधि या फ़्रैगमेंट InsetsChangedListener, कार Ui को लागू नहीं करता है लाइब्रेरी, इनसेट को पैडिंग के रूप में लागू करके डिफ़ॉल्ट रूप से Activity या FragmentActivity जिसमें फ़्रैगमेंट है. लाइब्रेरी इनसेट को डिफ़ॉल्ट रूप से फ़्रैगमेंट पर लागू करें. यहाँ एक इसे लागू करने से, इनसेट को RecyclerView पर पैडिंग (जगह) के तौर पर लागू किया जाता है ऐप्लिकेशन:

public class MainActivity extends Activity implements InsetsChangedListener {
  @Override
  public void onCarUiInsetsChanged(Insets insets) {
    CarUiRecyclerView rv = requireViewById(R.id.recyclerview);
    rv.setPadding(insets.getLeft(), insets.getTop(),
                  insets.getRight(), insets.getBottom());
  }
}

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

क्योंकि installBaseLayoutAround के लिए अपेक्षित है जब शून्य toolbarEnabled, false है, प्लगिन के मुताबिक यह बताने के लिए कि वह ऐसा नहीं करता है आधार लेआउट को कस्टमाइज़ करना चाहते हैं, तो इसे से false वापस करना होगा customizesBaseLayout.

पूरी तरह से बेस लेआउट में, FocusParkingView और FocusArea होनी चाहिए रोटरी कंट्रोल के साथ काम करता है. इन व्यू को उन डिवाइसों पर हटाया जा सकता है जिन पर रोटरी के साथ काम नहीं करता. FocusParkingView/FocusAreas को इसमें लागू किया जाता है: स्टैटिक CarUi लाइब्रेरी. इसलिए, setRotaryFactories का इस्तेमाल इन कामों के लिए फ़ैक्ट्री उपलब्ध कराने के लिए किया जाता है कॉन्टेक्स्ट के हिसाब से व्यू बनाते हैं.

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

टूलबार कंट्रोलर

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

getImeSearchInterface का इस्तेमाल IME (कीबोर्ड) में खोज के नतीजे दिखाने के लिए किया जाता है विंडो. यह खोज परिणामों के साथ-साथ उदाहरण के लिए, अगर कीबोर्ड पूरी स्क्रीन का सिर्फ़ आधा हिस्सा इस्तेमाल करता है. ज़्यादातर यह सुविधा स्थिर CarUi लाइब्रेरी में लागू की जाती है, खोज प्लगिन का इंटरफ़ेस केवल स्थैतिक लाइब्रेरी के लिए ऐसे तरीके प्रदान करता है, TextView और onPrivateIMECommand कॉलबैक. इसका समर्थन करने के लिए, प्लगिन को TextView सब-क्लास का इस्तेमाल करना चाहिए, जो onPrivateIMECommand और पास को बदल देता हो अपने सर्च बार के TextView के तौर पर, दिए गए लिसनर को कॉल किया जा सकता है.

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

ऐपस्टाइल व्यू

AppStyledView, ऐसे व्यू के लिए कंटेनर है जिसे पसंद के मुताबिक नहीं बनाया गया है. यह का उपयोग उस दृश्य के चारों ओर बॉर्डर उपलब्ध कराने के लिए किया जा सकता है जो उसे अलग करता है अन्य ऐप्लिकेशन में साइन इन करना होगा. साथ ही, उपयोगकर्ता को बताना होगा कि यह एक अलग तरह का इंटरफ़ेस पर कॉपी करने की सुविधा मिलती है. AppStyledView के ज़रिए रैप किए गए व्यू को setContent. AppStyledView में 'वापस जाएं' या 'बंद करें' बटन भी दिया जा सकता है: ऐप्लिकेशन ने अनुरोध किया है.

AppStyledView अपने व्यू को व्यू हैरारकी (व्यू और व्यू ग्रुप के लेआउट का क्रम) में तुरंत नहीं डालता जैसे कि installBaseLayoutAround करता है, तो यह इसके बजाय केवल getView के ज़रिए स्टैटिक लाइब्रेरी, जो इसके बाद इंसर्शन करता है. स्थिति और AppStyledView के साइज़ को इसे लागू करके भी कंट्रोल किया जा सकता है getDialogWindowLayoutParam.

संदर्भ

कॉन्टेक्स्ट का इस्तेमाल करते समय प्लगिन को सावधानी बरतनी चाहिए, क्योंकि प्लग इन और "सोर्स" संदर्भ. प्लगिन के कॉन्टेक्स्ट को तर्क के तौर पर getPluginFactory. साथ ही, सिर्फ़ उसी संदर्भ में के संसाधन शामिल करें. इसका मतलब है कि इन कामों के लिए सिर्फ़ इसी संदर्भ का इस्तेमाल किया जा सकता है इनफ़्लेट के साथ प्लग-इन का इस्तेमाल किया जाता है.

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

Context layoutInflationContext = pluginContext.createConfigurationContext(
        sourceContext.getResources().getConfiguration());

मोड में बदलाव

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

Jetpack Compose

प्लगिन, Jetpack Compose का इस्तेमाल करके लागू किए जा सकते हैं. हालांकि, यह ऐल्फ़ा लेवल का है सुविधा होती है और इसे स्थिर नहीं माना जाना चाहिए.

प्लगिन इनका इस्तेमाल कर सकते हैं ComposeView ताकि रेंडर करने के लिए, कंपोज़ की सुविधा वाला प्लैटफ़ॉर्म बनाया जा सके. यह ComposeView होगा कॉम्पोनेंट में getView तरीके से क्या लौटाया जाता है.

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

ComposeViewWithLifecycle:

class ComposeViewWithLifecycle @JvmOverloads constructor(
  context: Context,
  attrs: AttributeSet? = null,
  defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr),
    LifecycleOwner, ViewModelStoreOwner, SavedStateRegistryOwner {

  private val lifeCycle = LifecycleRegistry(this)
  private val modelStore = ViewModelStore()
  private val savedStateRegistryController = SavedStateRegistryController.create(this)
  private var composeView: ComposeView? = null
  private var content = @Composable {}

  init {
    ViewTreeLifecycleOwner.set(this, this)
    ViewTreeViewModelStoreOwner.set(this, this)
    ViewTreeSavedStateRegistryOwner.set(this, this)
    compositionContext = createCompositionContext()
  }

  fun setContent(content: @Composable () -> Unit) {
    this.content = content
    composeView?.setContent(content)
  }

  override fun getLifecycle(): Lifecycle {
    return lifeCycle
  }

  override fun getViewModelStore(): ViewModelStore {
    return modelStore
  }

  override fun getSavedStateRegistry(): SavedStateRegistry {
    return savedStateRegistryController.savedStateRegistry
  }

  override fun onAttachedToWindow() {
    super.onAttachedToWindow()
    savedStateRegistryController.performRestore(Bundle())
    lifeCycle.currentState = Lifecycle.State.RESUMED
    composeView = ComposeView(context)
    composeView?.setContent(content)
    addView(composeView, LayoutParams(
      LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
  }

  override fun onDetachedFromWindow() {
    super.onDetachedFromWindow()
    lifeCycle.currentState = Lifecycle.State.DESTROYED
    modelStore.clear()
    removeAllViews()
    composeView = null
  }

  // Exact copy of View.createCompositionContext() in androidx's WindowRecomposer.android.kt
  private fun createCompositionContext(): CompositionContext {
    val currentThreadContext = AndroidUiDispatcher.CurrentThread
    val pausableClock = currentThreadContext[MonotonicFrameClock]?.let {
      PausableMonotonicFrameClock(it).apply { pause() }
    }
    val contextWithClock = currentThreadContext + (pausableClock ?: EmptyCoroutineContext)
    val recomposer = Recomposer(contextWithClock)
    val runRecomposeScope = CoroutineScope(contextWithClock)
    val viewTreeLifecycleOwner = checkNotNull(ViewTreeLifecycleOwner.get(this)) {
      "ViewTreeLifecycleOwner not found from $this"
    }
    viewTreeLifecycleOwner.lifecycle.addObserver(
      LifecycleEventObserver { _, event ->
        @Suppress("NON_EXHAUSTIVE_WHEN")
        when (event) {
          Lifecycle.Event.ON_CREATE ->
            // Undispatched launch since we've configured this scope
            // to be on the UI thread
            runRecomposeScope.launch(start = CoroutineStart.UNDISPATCHED) {
              recomposer.runRecomposeAndApplyChanges()
            }
          Lifecycle.Event.ON_START -> pausableClock?.resume()
          Lifecycle.Event.ON_STOP -> pausableClock?.pause()
          Lifecycle.Event.ON_DESTROY -> {
            recomposer.cancel()
          }
        }
      }
    )
    return recomposer
  }

//  TODO: ComposeViewWithLifecycle should handle saving state and other lifecycle things
//  override fun onSaveInstanceState(): Parcelable? {
//    val superState = super.onSaveInstanceState()
//    val bundle = Bundle()
//    savedStateRegistryController.performSave(bundle)
//  }
}