সেটিংস অনুসন্ধান আপনাকে দ্রুত এবং সহজেই অটোমোটিভ সেটিংস অ্যাপে নির্দিষ্ট সেটিংস অনুসন্ধান করতে এবং পরিবর্তন করতে অ্যাপ মেনুতে নেভিগেট না করে এটিকে খুঁজে পেতে সক্ষম করে। অনুসন্ধান একটি নির্দিষ্ট সেটিং খুঁজে পেতে সবচেয়ে কার্যকর উপায়. ডিফল্টরূপে, অনুসন্ধান শুধুমাত্র AOSP সেটিংস খুঁজে পায়। অতিরিক্ত সেটিংস, ইনজেকশন করা হোক বা না হোক, সূচীকরণের জন্য অতিরিক্ত পরিবর্তনের প্রয়োজন।
প্রয়োজনীয়তা
সেটিংস অনুসন্ধানের দ্বারা একটি সেটিং সূচীযোগ্য হওয়ার জন্য, একটি থেকে ডেটা আসতে হবে:
-
CarSettingsভিতরেSearchIndexableফ্র্যাগমেন্ট। - সিস্টেম-স্তরের অ্যাপ।
ডেটা সংজ্ঞায়িত করুন
সাধারণ ক্ষেত্র:
-
Key। ( প্রয়োজনীয় ) ফলাফল সনাক্ত করতে অনন্য মানব পাঠযোগ্য স্ট্রিং কী। -
IconResIdঐচ্ছিক যদি আপনার অ্যাপে ফলাফলের পাশে একটি আইকন দেখা যায়, তাহলে রিসোর্স আইডি যোগ করুন, অন্যথায় উপেক্ষা করুন। -
IntentActionIntentTargetPackageবা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 প্যাকেজগুলি ইতিমধ্যেই সংজ্ঞায়িত ইন্টারফেস এবং বিমূর্ত ক্লাসগুলিকে সূচিত করার জন্য নতুন এন্ট্রি প্রদানের জন্য প্রসারিত করেছে। AOSP সেটিংসে, এই ক্লাসগুলির বাস্তবায়ন ফলাফল সূচী করতে ব্যবহৃত হয়। পূরণ করা প্রাথমিক ইন্টারফেস হল 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; } } }