Ayarlar arama, Otomotiv Ayarları uygulamasındaki belirli ayarları bulmak için uygulama menülerinde gezinmeye gerek kalmadan hızlı ve kolay bir şekilde aramanıza ve değiştirmenize olanak tanır. Arama, belirli bir ayarı bulmanın en etkili yoludur. Varsayılan olarak arama yalnızca AOSP ayarlarını bulur. Ek ayarların, enjekte edilmiş olsun ya da olmasın, indekslenmesi için ek değişiklikler yapılması gerekir.
Gereksinimler
Bir ayarın Ayarlar aramasıyla dizine eklenebilir olması için verilerin aşağıdakilerden gelmesi gerekir:
-
CarSettings
içindekiSearchIndexable
parçası. - Sistem düzeyinde uygulama.
Verileri tanımlayın
Ortak alanlar:
-
Key
. ( Gerekli ) Sonucu tanımlamak için insanlar tarafından okunabilen benzersiz Dize anahtarı. -
IconResId
. İsteğe Bağlı Uygulamanızda sonucun yanında bir simge görünürse kaynak kimliğini ekleyin, aksi halde dikkate almayın. -
IntentAction
.IntentTargetPackage
veyaIntentTargetClass
tanımlanmamışsa gereklidir . Arama sonucu amacının gerçekleştirmesi gereken eylemi tanımlar. -
IntentTargetPackage
.IntentAction
tanımlanmamışsa gereklidir . Arama sonucu amacının çözümleneceği paketi tanımlar. -
IntentTargetClass
.IntentAction
tanımlanmamışsa gereklidir . Arama sonucu amacının çözümleneceği sınıfı (etkinliği) tanımlar.
Yalnızca SearchIndexableResource
:
-
XmlResId
. ( Gerekli ) Dizine eklenecek sonuçları içeren sayfanın XML kaynak kimliğini tanımlar.
Yalnızca SearchIndexableRaw
:
-
Title
. ( Gerekli ) Arama sonucunun başlığı. -
SummaryOn
. ( İsteğe bağlı ) Arama sonucunun özeti. -
Keywords
. ( İsteğe bağlı ) Arama sonucuyla ilişkili kelimelerin listesi. Sorguyu sonucunuzla eşleştirir. -
ScreenTitle
. ( İsteğe bağlı ) Arama sonucunuzun bulunduğu sayfanın başlığı.
Verileri gizle
Aksi belirtilmediği sürece her arama sonucu Arama'da görünür. Statik arama sonuçları önbelleğe alınırken, arama her açıldığında indekslenemeyen anahtarların yeni bir listesi alınır. Sonuçların gizlenmesinin nedenleri şunları içerebilir:
- Kopyalamak. Örneğin, birden fazla sayfada görünüyor.
- Yalnızca koşullu olarak gösterilir. Örneğin, yalnızca SIM kart mevcut olduğunda mobil veri ayarlarını gösterir).
- Şablonlu sayfa. Örneğin, bireysel bir uygulamanın ayrıntılar sayfası.
- Ayar, Başlık ve Alt Başlıktan daha fazla bağlama ihtiyaç duyar. Örneğin, yalnızca ekran başlığıyla ilgili olan "Ayarlar" ayarı.
Bir ayarı gizlemek için sağlayıcınız veya SEARCH_INDEX_DATA_PROVIDER
, arama sonucunun anahtarını getNonIndexableKeys
döndürmelidir. Anahtar her zaman döndürülebilir (yinelenen, şablonlu sayfa durumları) veya koşullu olarak eklenebilir (mobil veri durumu yok).
Statik indeks
Dizin verileriniz her zaman aynıysa statik dizini kullanın. Örneğin, XML verilerinin başlığı ve özeti veya sabit kod ham verileri. Statik veriler, Ayarlar araması ilk başlatıldığında yalnızca bir kez indekslenir.
Ayarların içindeki indekslenebilir öğeler için getXmlResourcesToIndex
ve/veya getRawDataToIndex
uygulayın. Eklenen ayarlar için queryXmlResources
ve/veya queryRawData
yöntemlerini uygulayın.
Dinamik dizin
Dizine eklenebilir veriler uygun şekilde güncellenebiliyorsa verilerinizi dizine eklemek için dinamik yöntemi kullanın. Ayarlar araması, başlatıldığında bu dinamik listeyi günceller.
Ayarların içindeki indekslenebilir öğeler için getDynamicRawDataToIndex
uygulayın. Eklenen ayarlar için queryDynamicRawData methods
uygulayın.
Araç Ayarlarında Dizin
Arama özelliğine dahil edilecek farklı ayarları dizine eklemek için bkz. İçerik sağlayıcılar . SettingsLib
ve android.provider
paketleri, indekslenecek yeni girişlerin sağlanması için genişletilecek tanımlı arayüzlere ve soyut sınıflara zaten sahiptir. AOSP ayarlarında, bu sınıfların uygulamaları sonuçları indekslemek için kullanılır. Gerçekleştirilecek birincil arayüz, SettingsIntelligence
tarafından verileri indekslemek için kullanılan SearchIndexablesProvider
.
public abstract class SearchIndexablesProvider extends ContentProvider { public abstract Cursor queryXmlResources(String[] projection); public abstract Cursor queryRawData(String[] projection); public abstract Cursor queryNonIndexableKeys(String[] projection); }
Teorik olarak, her parça SearchIndexablesProvider
sonuçlara eklenebilir; bu durumda SettingsIntelligence
içerik olacaktır. Yeni parçalar eklemek ve işlemin bakımını kolaylaştırmak için SearchIndexableResources
SettingsLib
kod oluşturma özelliğini kullanın. Araç Ayarlarına özel olarak, her indekslenebilir parçaya @SearchIndexable
ile açıklama eklenir ve ardından bu parça için ilgili verileri sağlayan statik bir SearchIndexProvider
alanı bulunur. Ek açıklamaya sahip ancak SearchIndexProvider
eksik olduğu parçalar derleme hatasıyla sonuçlanır.
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); }
Bu parçaların tümü daha sonra, tüm parçalar için SearchIndexProvider
alanları listesinin etrafındaki ince bir sarmalayıcı olan otomatik olarak oluşturulan SearchIndexableResourcesAuto
sınıfına eklenir. Bir ek açıklama için (Otomatik, TV ve Aşınma gibi) belirli bir hedefin belirlenmesine yönelik destek sağlanır, ancak çoğu ek açıklama varsayılanda ( All
) bırakılır. Bu kullanım durumunda Otomatik hedefin belirtilmesine özel bir ihtiyaç yoktur, bu nedenle All
olarak kalır. SearchIndexProvider
temel uygulamasının çoğu parça için yeterli olması amaçlanmıştır.
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; } }
Yeni bir parçayı indeksle
Bu tasarımla, dizine eklenecek yeni bir SettingsFragment
eklemek nispeten kolaydır; genellikle parça için XML ve takip edilecek amaç sağlayan iki satırlı bir güncelleme. Örnek olarak WifiSettingsFragment
ile:
@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
, SearchIndexableResources
kullanan ve SearchIndexProviders
SettingsIntelligence
için veritabanı şemasına çeviri yapan, ancak hangi parçaların dizine eklendiğinden bağımsız olan AAOS uygulaması. SettingsIntelligence
herhangi bir sayıda sağlayıcıyı destekler; böylece özel kullanım durumlarını desteklemek için yeni sağlayıcılar oluşturulabilir ve her birinin benzer yapılarla uzmanlaşmasına ve sonuçlara odaklanmasına olanak sağlanır. Fragman için PreferenceScreen
tanımlanan tercihlerin her birinin indekslenebilmesi için kendilerine atanmış benzersiz bir anahtara sahip olması gerekir. Ek olarak, ekran başlığının dizine eklenmesi için PreferenceScreen
atanmış bir anahtarın olması gerekir.
Dizin örnekleri
Bazı durumlarda, bir parçanın kendisiyle ilişkilendirilmiş belirli bir niyet eylemi olmayabilir. Bu gibi durumlarda, bir eylem yerine bir bileşen kullanarak aktivite sınıfını CarBaseSearchIndexProvider
amacına geçirmek mümkündür. Bu yine de etkinliğin bildirim dosyasında mevcut olmasını ve dışa aktarılmasını gerektirir.
@SearchIndexable public class LanguagesAndInputFragment extends SettingsFragment { [...] public static final CarBaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new CarBaseSearchIndexProvider(R.xml.languages_and_input_fragment, LanguagesAndInputActivity.class); }
Bazı özel durumlarda, indekslenecek istenen sonuçları elde etmek için CarBaseSearchIndexProvider
bazı yöntemlerinin geçersiz kılınması gerekebilir. Örneğin, NetworkAndInternetFragment
, mobil ağ ile ilgili tercihler, mobil ağı olmayan cihazlarda dizine eklenmeyecekti. Bu durumda, getNonIndexableKeys
yöntemini geçersiz kılın ve bir cihazın mobil ağı olmadığında uygun anahtarları indekslenemez olarak işaretleyin.
@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; } }; }
Belirli bir parçanın ihtiyaçlarına bağlı olarak, CarBaseSearchIndexProvider
diğer yöntemleri, statik ve dinamik ham veriler gibi diğer indekslenebilir verileri içerecek şekilde geçersiz kılınabilir.
@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; } }; }
Dizin enjekte edilen ayarlar
Dizine eklenecek bir ayarı enjekte etmek için:
-
android.provider.SearchIndexablesProvider
sınıfını genişleterek uygulamanız için birSearchIndexablesProvider
tanımlayın. - 1. Adımda uygulamanın
AndroidManifest.xml
dosyasını sağlayıcıyla güncelleyin. Format şu şekildedir:<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>
- Sağlayıcınıza indekslenebilir veriler ekleyin. Uygulama, uygulamanın ihtiyaçlarına bağlıdır. İki farklı veri türü dizine eklenebilir:
SearchIndexableResource
veSearchIndexableRaw
.
SearchIndexablesProvider örneği
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; } } }