सेटिंग्स खोज आपको ऑटोमोटिव सेटिंग्स ऐप में विशिष्ट सेटिंग्स को खोजने के लिए ऐप मेनू के माध्यम से नेविगेट किए बिना जल्दी और आसानी से खोजने और बदलने में सक्षम बनाती है। किसी विशिष्ट सेटिंग को खोजने के लिए खोज सबसे प्रभावी तरीका है। डिफ़ॉल्ट रूप से, खोज केवल AOSP सेटिंग्स ढूंढती है। अतिरिक्त सेटिंग्स, चाहे इंजेक्ट की गई हों या नहीं, अनुक्रमित होने के लिए अतिरिक्त परिवर्तनों की आवश्यकता होती है।
आवश्यकताएं
सेटिंग खोज द्वारा किसी सेटिंग को अनुक्रमित करने के लिए, डेटा निम्न से आना चाहिए:
-
CarSettings
के अंदरSearchIndexable
टुकड़ा। - सिस्टम-स्तरीय ऐप.
डेटा को परिभाषित करें
सामान्य फ़ील्ड:
-
Key
। ( आवश्यक ) परिणाम की पहचान करने के लिए अद्वितीय मानव पठनीय स्ट्रिंग कुंजी। -
IconResId
. वैकल्पिक यदि आपके ऐप में परिणाम के आगे कोई आइकन दिखाई देता है, तो संसाधन आईडी जोड़ें, अन्यथा अनदेखा करें। -
IntentAction
। यदिIntentTargetPackage
याIntentTargetClass
परिभाषित नहीं है तो आवश्यक है । उस कार्रवाई को परिभाषित करता है जो खोज परिणाम का इरादा है। -
IntentTargetPackage
। यदिIntentAction
परिभाषित नहीं है तो आवश्यक है । उस पैकेज को परिभाषित करता है जिसे खोज परिणाम का उद्देश्य हल करना है। -
IntentTargetClass
. यदिIntentAction
परिभाषित नहीं है तो आवश्यक है । उस वर्ग (गतिविधि) को परिभाषित करता है जिसे खोज परिणाम का उद्देश्य हल करना है।
केवल SearchIndexableResource
:
-
XmlResId
. ( आवश्यक ) अनुक्रमित किए जाने वाले परिणामों वाले पृष्ठ की XML संसाधन आईडी को परिभाषित करता है।
केवल SearchIndexableRaw
:
-
Title
। ( आवश्यक ) खोज परिणाम का शीर्षक. -
SummaryOn
. ( वैकल्पिक ) खोज परिणाम का सारांश। -
Keywords
. ( वैकल्पिक ) खोज परिणाम से जुड़े शब्दों की सूची। क्वेरी को आपके परिणाम से मेल खाता है. -
ScreenTitle
। ( वैकल्पिक ) आपके खोज परिणाम वाले पृष्ठ का शीर्षक।
डेटा छिपाएँ
प्रत्येक खोज परिणाम खोज में दिखाई देता है जब तक कि इसे अन्यथा चिह्नित न किया गया हो। जबकि स्थैतिक खोज परिणाम कैश किए जाते हैं, हर बार खोज खोले जाने पर गैर-अनुक्रमणीय कुंजियों की एक ताज़ा सूची पुनर्प्राप्त की जाती है। परिणाम छिपाने के कारणों में ये शामिल हो सकते हैं:
- डुप्लिकेट. उदाहरण के लिए, एकाधिक पृष्ठों पर दिखाई देता है.
- केवल सशर्त दिखाया गया है। उदाहरण के लिए, केवल सिम कार्ड मौजूद होने पर ही मोबाइल डेटा सेटिंग्स दिखाता है)।
- टेम्पलेट पृष्ठ. उदाहरण के लिए, किसी व्यक्तिगत ऐप के लिए विवरण पृष्ठ।
- सेटिंग को शीर्षक और उपशीर्षक से अधिक संदर्भ की आवश्यकता होती है। उदाहरण के लिए, एक "सेटिंग्स" सेटिंग, जो केवल स्क्रीन शीर्षक के लिए प्रासंगिक है।
किसी सेटिंग को छिपाने के लिए, आपके प्रदाता या SEARCH_INDEX_DATA_PROVIDER
को getNonIndexableKeys
से खोज परिणाम की कुंजी वापस करनी चाहिए। कुंजी को हमेशा वापस किया जा सकता है (डुप्लिकेट, टेम्प्लेटेड पेज केस) या सशर्त रूप से जोड़ा जा सकता है (कोई मोबाइल डेटा केस नहीं)।
स्थैतिक सूचकांक
यदि आपका इंडेक्स डेटा हमेशा समान रहता है तो स्टैटिक इंडेक्स का उपयोग करें। उदाहरण के लिए, XML डेटा का शीर्षक और सारांश या हार्ड कोड कच्चा डेटा। स्थिर डेटा को केवल एक बार अनुक्रमित किया जाता है जब सेटिंग्स खोज पहली बार लॉन्च की जाती है।
सेटिंग्स के अंदर इंडेक्सेबल्स के लिए, getXmlResourcesToIndex
और/या getRawDataToIndex
लागू करें। इंजेक्टेड सेटिंग्स के लिए, queryXmlResources
और/या queryRawData
विधियों को लागू करें।
गतिशील सूचकांक
यदि अनुक्रमणीय डेटा को तदनुसार अद्यतन किया जा सकता है, तो अपने डेटा को अनुक्रमित करने के लिए गतिशील विधि का उपयोग करें। सेटिंग्स खोज इस गतिशील सूची को लॉन्च होने पर अद्यतन करती है।
सेटिंग्स के अंदर इंडेक्सेबल्स के लिए, getDynamicRawDataToIndex
लागू करें। इंजेक्टेड सेटिंग्स के लिए, queryDynamicRawData methods
लागू करें।
कार सेटिंग्स में अनुक्रमणिका
खोज सुविधा में शामिल की जाने वाली विभिन्न सेटिंग्स को अनुक्रमित करने के लिए, सामग्री प्रदाता देखें। SettingsLib
और android.provider
पैकेज में पहले से ही अनुक्रमित की जाने वाली नई प्रविष्टियों को प्रदान करने के लिए विस्तार करने के लिए परिभाषित इंटरफेस और अमूर्त वर्ग हैं। एओएसपी सेटिंग्स में, इन कक्षाओं के कार्यान्वयन का उपयोग परिणामों को अनुक्रमित करने के लिए किया जाता है। पूरा किया जाने वाला प्राथमिक इंटरफ़ेस SearchIndexablesProvider
है, जिसका उपयोग SettingsIntelligence
द्वारा डेटा को अनुक्रमित करने के लिए किया जाता है।
public abstract class SearchIndexablesProvider extends ContentProvider { public abstract Cursor queryXmlResources(String[] projection); public abstract Cursor queryRawData(String[] projection); public abstract Cursor queryNonIndexableKeys(String[] projection); }
सिद्धांत रूप में, प्रत्येक टुकड़े को SearchIndexablesProvider
परिणामों में जोड़ा जा सकता है, जिस स्थिति में SettingsIntelligence
सामग्री होगी। नए टुकड़े जोड़ने के लिए आसानी से बनाए रखने की प्रक्रिया को आसान बनाने के लिए, SearchIndexableResources
की SettingsLib
कोड पीढ़ी का उपयोग करें। कार सेटिंग्स के लिए विशिष्ट, प्रत्येक अनुक्रमित टुकड़े को @SearchIndexable
के साथ एनोटेट किया जाता है और उसके बाद एक स्थिर SearchIndexProvider
फ़ील्ड होता है जो उस टुकड़े के लिए प्रासंगिक डेटा प्रदान करता है। एनोटेशन वाले टुकड़े, लेकिन SearchIndexProvider
गायब होने के परिणामस्वरूप संकलन त्रुटि होती है।
interface SearchIndexProvider { List<SearchIndexableResource> getXmlResourcesToIndex(Context context, boolean enabled); List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled); List<SearchIndexableRaw> getDynamicRawDataToIndex(Context context, boolean enabled); List<String> getNonIndexableKeys(Context context); }
फिर इन सभी टुकड़ों को स्वतः-जनित SearchIndexableResourcesAuto
क्लास में जोड़ दिया जाता है, जो सभी टुकड़ों के लिए SearchIndexProvider
फ़ील्ड की सूची के चारों ओर एक पतला आवरण होता है। किसी एनोटेशन (जैसे ऑटो, टीवी और वेयर) के लिए एक विशिष्ट लक्ष्य निर्दिष्ट करने के लिए समर्थन प्रदान किया जाता है, हालांकि अधिकांश एनोटेशन को डिफ़ॉल्ट ( All
) पर छोड़ दिया जाता है। इस उपयोग के मामले में, ऑटो लक्ष्य निर्दिष्ट करने की कोई विशेष आवश्यकता मौजूद नहीं है, इसलिए यह All
के रूप में बना रहता है। SearchIndexProvider
का मूल कार्यान्वयन अधिकांश अंशों के लिए पर्याप्त होने का इरादा है।
public class CarBaseSearchIndexProvider implements Indexable.SearchIndexProvider { private static final Logger LOG = new Logger(CarBaseSearchIndexProvider.class); private final int mXmlRes; private final String mIntentAction; private final String mIntentClass; public CarBaseSearchIndexProvider(@XmlRes int xmlRes, String intentAction) { mXmlRes = xmlRes; mIntentAction = intentAction; mIntentClass = null; } public CarBaseSearchIndexProvider(@XmlRes int xmlRes, @NonNull Class intentClass) { mXmlRes = xmlRes; mIntentAction = null; mIntentClass = intentClass.getName(); } @Override public List<SearchIndexableResource> getXmlResourcesToIndex(Context context, boolean enabled) { SearchIndexableResource sir = new SearchIndexableResource(context); sir.xmlResId = mXmlRes; sir.intentAction = mIntentAction; sir.intentTargetPackage = context.getPackageName(); sir.intentTargetClass = mIntentClass; return Collections.singletonList(sir); } @Override public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) { return null; } @Override public List<SearchIndexableRaw> getDynamicRawDataToIndex(Context context, boolean enabled) { return null; } @Override public List<String> getNonIndexableKeys(Context context) { if (!isPageSearchEnabled(context)) { try { return PreferenceXmlParser.extractMetadata(context, mXmlRes, FLAG_NEED_KEY) .stream() .map(bundle -> bundle.getString(METADATA_KEY)) .collect(Collectors.toList()); } catch (IOException | XmlPullParserException e) { LOG.w("Error parsing non-indexable XML - " + mXmlRes); } } return null; } /** * Returns true if the page should be considered in search query. If return false, entire page is suppressed during search query. */ protected boolean isPageSearchEnabled(Context context) { return true; } }
एक नया टुकड़ा अनुक्रमित करें
इस डिज़ाइन के साथ, अनुक्रमित करने के लिए एक नया SettingsFragment
जोड़ना अपेक्षाकृत आसान है, आमतौर पर एक दो-पंक्ति वाला अपडेट जो फ़्रैगमेंट और अनुसरण किए जाने वाले इरादे के लिए XML प्रदान करता है। उदाहरण के तौर पर WifiSettingsFragment
के साथ:
@SearchIndexable public class WifiSettingsFragment extends SettingsFragment { [...] public static final CarBaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new CarBaseSearchIndexProvider(R.xml.wifi_list_fragment, Settings.ACTION_WIFI_SETTINGS); }
SearchIndexablesProvider
का AAOS कार्यान्वयन, जो SearchIndexableResources
उपयोग करता है और SearchIndexProviders
से SettingsIntelligence
के लिए डेटाबेस स्कीमा में अनुवाद करता है, लेकिन इस बात से अनजान है कि किन टुकड़ों को अनुक्रमित किया जा रहा है। SettingsIntelligence
किसी भी संख्या में प्रदाताओं का समर्थन करता है, इसलिए विशेष उपयोग के मामलों का समर्थन करने के लिए नए प्रदाता बनाए जा सकते हैं, जिससे प्रत्येक को विशिष्ट बनाया जा सकता है और समान संरचनाओं के साथ परिणामों पर ध्यान केंद्रित किया जा सकता है। खंड के लिए PreferenceScreen
में परिभाषित प्राथमिकताओं में से प्रत्येक को अनुक्रमित करने के लिए एक अद्वितीय कुंजी सौंपी जानी चाहिए। इसके अतिरिक्त, स्क्रीन शीर्षक को अनुक्रमित करने के लिए PreferenceScreen
में एक कुंजी निर्दिष्ट होनी चाहिए।
सूचकांक उदाहरण
कुछ मामलों में, किसी टुकड़े के साथ कोई विशिष्ट आशय वाली कार्रवाई नहीं जुड़ी हो सकती है। ऐसे मामलों में, किसी क्रिया के बजाय किसी घटक का उपयोग करके गतिविधि वर्ग को CarBaseSearchIndexProvider
इरादे में पास करना संभव है। इसके लिए अभी भी गतिविधि को मैनिफ़ेस्ट फ़ाइल में मौजूद होना और उसे निर्यात करना आवश्यक है।
@SearchIndexable public class LanguagesAndInputFragment extends SettingsFragment { [...] public static final CarBaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new CarBaseSearchIndexProvider(R.xml.languages_and_input_fragment, LanguagesAndInputActivity.class); }
कुछ विशेष मामलों में, अनुक्रमित किए जाने वाले वांछित परिणाम प्राप्त करने के लिए CarBaseSearchIndexProvider
की कुछ विधियों को ओवरराइड करने की आवश्यकता हो सकती है। उदाहरण के लिए, NetworkAndInternetFragment
में, मोबाइल नेटवर्क से संबंधित प्राथमिकताओं को बिना मोबाइल नेटवर्क वाले उपकरणों पर अनुक्रमित नहीं किया जाना था। इस मामले में, getNonIndexableKeys
विधि को ओवरराइड करें और जब किसी डिवाइस में मोबाइल नेटवर्क न हो तो उपयुक्त कुंजियों को गैर-अनुक्रमणीय के रूप में चिह्नित करें।
@SearchIndexable public class NetworkAndInternetFragment extends SettingsFragment { [...] public static final CarBaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new CarBaseSearchIndexProvider(R.xml.network_and_internet_fragment, Settings.Panel.ACTION_INTERNET_CONNECTIVITY) { @Override public List<String> getNonIndexableKeys(Context context) { if (!NetworkUtils.hasMobileNetwork( context.getSystemService(ConnectivityManager.class))) { List<String> nonIndexableKeys = new ArrayList<>(); nonIndexableKeys.add(context.getString( R.string.pk_mobile_network_settings_entry)); nonIndexableKeys.add(context.getString( R.string.pk_data_usage_settings_entry)); return nonIndexableKeys; } return null; } }; }
विशेष टुकड़े की जरूरतों के आधार पर, CarBaseSearchIndexProvider
के अन्य तरीकों को अन्य अनुक्रमित डेटा, जैसे स्थिर और गतिशील कच्चे डेटा को शामिल करने के लिए ओवरराइड किया जा सकता है।
@SearchIndexable public class RawIndexDemoFragment extends SettingsFragment { public static final String KEY_CUSTOM_RESULT = "custom_result_key"; [...] public static final CarBaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new CarBaseSearchIndexProvider(R.xml.raw_index_demo_fragment, RawIndexDemoActivity.class) { @Override public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) { List<SearchIndexableRaw> rawData = new ArrayList<>(); SearchIndexableRaw customResult = new SearchIndexableRaw(context); customResult.key = KEY_CUSTOM_RESULT; customResult.title = context.getString(R.string.my_title); customResult.screenTitle = context.getString(R.string.my_screen_title); rawData.add(customResult); return rawData; } @Override public List<SearchIndexableRaw> getDynamicRawDataToIndex(Context context, boolean enabled) { List<SearchIndexableRaw> rawData = new ArrayList<>(); SearchIndexableRaw customResult = new SearchIndexableRaw(context); if (hasIndexData()) { customResult.key = KEY_CUSTOM_RESULT; customResult.title = context.getString(R.string.my_title); customResult.screenTitle = context.getString(R.string.my_screen_title); } rawData.add(customResult); return rawData; } }; }
इंडेक्स इंजेक्टेड सेटिंग्स
अनुक्रमित की जाने वाली सेटिंग को इंजेक्ट करने के लिए:
-
android.provider.SearchIndexablesProvider
वर्ग का विस्तार करके अपने ऐप के लिए एकSearchIndexablesProvider
परिभाषित करें। - चरण 1 में प्रदाता के साथ ऐप के
AndroidManifest.xml
अपडेट करें। प्रारूप है:<provider android:name="PROVIDER_CLASS_NAME" android:authorities="PROVIDER_AUTHORITY" android:multiprocess="false" android:grantUriPermissions="true" android:permission="android.permission.READ_SEARCH_INDEXABLES" android:exported="true"> <intent-filter> <action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER" /> </intent-filter> </provider>
- अपने प्रदाता में अनुक्रमित करने योग्य डेटा जोड़ें। कार्यान्वयन ऐप की ज़रूरतों पर निर्भर करता है। दो अलग-अलग डेटा प्रकारों को अनुक्रमित किया जा सकता है:
SearchIndexableResource
औरSearchIndexableRaw
।
SearchIndexablesProvider उदाहरण
public class SearchDemoProvider extends SearchIndexablesProvider { /** * Key for Auto brightness setting. */ public static final String KEY_AUTO_BRIGHTNESS = "auto_brightness"; /** * Key for my magic preference. */ public static final String KEY_MY_PREFERENCE = "my_preference_key"; /** * Key for my custom search result. */ public static final String KEY_CUSTOM_RESULT = "custom_result_key"; private String mPackageName; @Override public boolean onCreate() { mPackageName = getContext().getPackageName(); return true; } @Override public Cursor queryXmlResources(String[] projection) { MatrixCursor cursor = new MatrixCursor(INDEXABLES_XML_RES_COLUMNS); cursor.addRow(getResourceRow(R.xml.demo_xml)); return cursor; } @Override public Cursor queryRawData(String[] projection) { MatrixCursor cursor = new MatrixCursor(INDEXABLES_RAW_COLUMNS); Context context = getContext(); Object[] raw = new Object[INDEXABLES_RAW_COLUMNS.length]; raw[COLUMN_INDEX_RAW_TITLE] = context.getString(R.string.my_title); raw[COLUMN_INDEX_RAW_SUMMARY_ON] = context.getString(R.string.my_summary); raw[COLUMN_INDEX_RAW_KEYWORDS] = context.getString(R.string.my_keywords); raw[COLUMN_INDEX_RAW_SCREEN_TITLE] = context.getString(R.string.my_screen_title); raw[COLUMN_INDEX_RAW_KEY] = KEY_CUSTOM_RESULT; raw[COLUMN_INDEX_RAW_INTENT_ACTION] = Intent.ACTION_MAIN; raw[COLUMN_INDEX_RAW_INTENT_TARGET_PACKAGE] = mPackageName; raw[COLUMN_INDEX_RAW_INTENT_TARGET_CLASS] = MyDemoFragment.class.getName(); cursor.addRow(raw); return cursor; } @Override public Cursor queryDynamicRawData(String[] projection) { MatrixCursor cursor = new MatrixCursor(INDEXABLES_RAW_COLUMNS); DemoObject object = getDynamicIndexData(); Object[] raw = new Object[INDEXABLES_RAW_COLUMNS.length]; raw[COLUMN_INDEX_RAW_KEY] = object.key; raw[COLUMN_INDEX_RAW_TITLE] = object.title; raw[COLUMN_INDEX_RAW_KEYWORDS] = object.keywords; raw[COLUMN_INDEX_RAW_INTENT_ACTION] = object.intentAction; raw[COLUMN_INDEX_RAW_INTENT_TARGET_PACKAGE] = object.mPackageName; raw[COLUMN_INDEX_RAW_INTENT_TARGET_CLASS] = object.className; cursor.addRow(raw); return cursor; } @Override public Cursor queryNonIndexableKeys(String[] projection) { MatrixCursor cursor = new MatrixCursor(NON_INDEXABLES_KEYS_COLUMNS); cursor.addRow(getNonIndexableRow(KEY_AUTO_BRIGHTNESS)); if (!Utils.isMyPreferenceAvailable) { cursor.addRow(getNonIndexableRow(KEY_MY_PREFERENCE)); } return cursor; } private Object[] getResourceRow(int xmlResId) { Object[] row = new Object[INDEXABLES_XML_RES_COLUMNS.length]; row[COLUMN_INDEX_XML_RES_RESID] = xmlResId; row[COLUMN_INDEX_XML_RES_ICON_RESID] = 0; row[COLUMN_INDEX_XML_RES_INTENT_ACTION] = Intent.ACTION_MAIN; row[COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE] = mPackageName; row[COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS] = SearchResult.class.getName(); return row; } private Object[] getNonIndexableRow(String key) { final Object[] ref = new Object[NON_INDEXABLES_KEYS_COLUMNS.length]; ref[COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE] = key; return ref; } private DemoObject getDynamicIndexData() { if (hasIndexData) { DemoObject object = new DemoObject(); object.key = "demo key"; object.title = "demo title"; object.keywords = "demo, keywords"; object.intentAction = "com.demo.DYNAMIC_INDEX"; object.packageName = "com.demo"; object.className = "DemoClass"; return object; } } }