Ayarlar araması, uygulama menülerinde arama yapmadan Automotive Ayarları uygulamasında belirli ayarları hızlı ve kolay bir şekilde aramanızı ve değiştirmenizi sağlar. Arama, belirli bir ayarı bulmanın en etkili yoludur. Arama, varsayılan olarak yalnızca AOSP ayarlarını bulur. Yerleştirilmiş olsun veya olmasın ek ayarlar dizine eklenmek için ek değişiklik gerektirir.
Gereksinimler
Bir ayarın Ayarlar araması tarafından dizine eklenebilmesi için verilerin şu kaynaktan gelmesi gerekir:
CarSettings
içindeSearchIndexable
parçası.- Sistem düzeyinde uygulama.
Verileri tanımlama
Ortak alanlar:
Key
. (Zorunlu) Sonucu tanımlamak için kullanıcı tarafından okunabilen benzersiz dize anahtarı.IconResId
İsteğe bağlı Uygulamanızda ekleyin, kaynak kimliğini ekleyin, aksi takdirde yoksayın.IntentAction
.IntentTargetPackage
veyaIntentTargetClass
tanımlanmamışsa zorunludur. Arama sonucu tarafından yapılacak işlemi tanımlar kabul etmektir.IntentTargetPackage
.IntentAction
tanımlanmamışsa zorunludur. Arama sonucu amacının çözüme ulaştıracağı paketi tanımlar.IntentTargetClass
IntentAction
değilse zorunlu tanımlanmıştır. Arama sonucu amacının çözeceği sınıfı (etkinliği) tanımlar.
Yalnızca SearchIndexableResource
:
XmlResId
. (Zorunlu) Dizine eklenecek sonuçları içeren sayfanın XML kaynak kimliğini tanımlar.
Yalnızca SearchIndexableRaw
:
Title
. (Zorunlu) Arama sonucunun başlığı.SummaryOn
. (İsteğe bağlı) Arama sonucunun özeti.Keywords
(İsteğe bağlı) Arama sonucuyla ilişkilendirilen kelimelerin listesi. Sorguyu sonucunuzla eşleştirir.ScreenTitle
(İsteğe bağlı) Arama sonucunuzu içeren 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 dizine eklenemeyen anahtarların yeni bir listesi alınır. Sonuçları gizlemenin nedenleri arasında şunlar yer alabilir:
- Kopyala. Örneğin, birden fazla sayfada görünür.
- Yalnızca koşullu olarak gösterilir. Örneğin, yalnızca SIM kart varsa mobil veri ayarlarını gösterir).
- Şablon sayfası. Örneğin, tek bir uygulamanın ayrıntılar sayfası.
- Ayar, başlık ve alt başlıktan daha fazla bağlam gerektirir. Örneğin, bir "Ayarlar" ayarını değiştirin.
Bir ayarı gizlemek için sağlayıcınız veya SEARCH_INDEX_DATA_PROVIDER
getNonIndexableKeys
kodundaki arama sonucunun anahtarını döndürür. Bu anahtar
her zaman döndürülür (yinelenen, şablonlu sayfa durumları) veya koşullu olarak eklenir (mobil cihaz yok)
veri örneği) ekleyin.
Statik dizin
Dizin verileriniz her zaman aynıysa statik dizini kullanın. Örneğin, başlık ve XML verilerinin veya sabit kod ham verilerinin özetini içerir. Statik veriler dizine eklenir yalnızca bir kez Ayarlar arama özelliği ilk kez başlatıldığında.
Ayarlardaki dizine eklenebilir öğeler için getXmlResourcesToIndex
uygulayın
ve/veya getRawDataToIndex
. Yerleştirilen ayarlar için
queryXmlResources
ve/veya queryRawData
yöntem.
Dinamik dizin
Dizine eklenebilir veriler uygun şekilde güncellenebiliyorsa verilerinizi dizine ekleyin. Ayarlar araması, kullanıma sunulduğunda bu dinamik listeyi günceller.
Ayarlardaki dizine eklenebilir öğeler için getDynamicRawDataToIndex
uygulayın.
Yerleştirilen ayarlar için queryDynamicRawData methods
yönergesini uygulayın.
Araba Ayarları'nda Dizin
Arama özelliğine dahil edilecek farklı ayarları dizine eklemek için bkz.
İçerik
sağlayıcılarını ziyaret edin. SettingsLib
ve android.provider
paketlerinde, dizine eklenecek yeni girişler sağlamak için genişletilecek tanımlanmış arayüzler ve soyut sınıflar zaten mevcuttur. AOSP ayarlarında, bu uygulamalar
sınıfları, sonuçları dizine eklemek için kullanılır. Gerçekleştirilmesi gereken birincil arayüz, SettingsIntelligence
tarafından verileri dizine eklemek için kullanılan SearchIndexablesProvider
arayüzüdür.
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 bir parça SearchIndexablesProvider
'teki sonuçlara eklenebilir. Bu durumda SettingsIntelligence
içerik olur. Yeni parçalar eklemek ve süreci kolayca yürütmek için
SearchIndexableResources
için SettingsLib
kod oluşturma işlemini kullanın.
Araba Ayarları'na özel olarak, dizine eklenebilir her parça
@SearchIndexable
ve ardından statik bir SearchIndexProvider
değerine sahip
alanını kullanabilirsiniz.
ek açıklamaya sahip ancak bir derlemede SearchIndexProvider
sonucu eksik
hatası.
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); }
Ardından bu parçaların tümü, tüm parçaların SearchIndexProvider
alanları listesinin etrafında ince bir sarmalayıcı olan otomatik olarak oluşturulan SearchIndexableResourcesAuto
sınıfına eklenir.
Ek açıklamalar için belirli bir hedef (ör.
Auto, TV ve Wear). Bununla birlikte, çoğu ek açıklama varsayılanda (All
) kalır.
Bu kullanım örneğinde, otomatik hedefin belirtilmesi için özel bir gereklilik yoktur. Dolayısıyla hedef
All
olarak. 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ı dizine ekleme
Bu tasarımla, yeni bir SettingsFragment
eklemek nispeten kolaydır
genellikle parça için XML'i ve parça için XML'i sağlayan iki satırlık bir güncellemedir.
belirli bir amacın gerçekleştirilmesi gerekir. WifiSettingsFragment
örneğini inceleyelim:
@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
örneğinin AAOS uygulanması,
SearchIndexableResources
kullanıyor ve çevirisini şuradan yapıyor:
aşağıdaki örnekle ilgili veritabanı şemasına SearchIndexProviders
ekleyin:
SettingsIntelligence
, ancak parçalardan bağımsızdır
dizine eklenir. SettingsIntelligence
,
Böylece özel kullanımı desteklemek için yeni sağlayıcılar oluşturulabilir
Her birinin özelleştirilmesine ve benzer nitelikteki sonuçlara odaklanmasına imkan tanır.
birlikte çalışır. PreferenceScreen
içinde tanımlanan tercihler
benzersiz bir anahtarın atanabilmesi için parçanın
kendisine atanan benzersiz bir anahtar olması
dizine eklendi. Ayrıca, ekran başlığının dizine eklenmesi için PreferenceScreen
öğesine bir anahtar atanmalıdır.
Dizin örnekleri
Bazı durumlarda, bir parçayla ilişkili belirli bir intent işlemi olmayabilir. Bu tür durumlarda, etkinlik sınıfını bir işlem yerine bileşen kullanarak CarBaseSearchIndexProvider
amacına iletebilirsiniz. Bunun için etkinliğin manifest dosyasında bulunması ve dışa aktarılması gerekir.
@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, istenen sonuçların dizine eklenmesini sağlamak için CarBaseSearchIndexProvider
bazı yöntemlerinin geçersiz kılınması gerekebilir. Örneğin,
NetworkAndInternetFragment
, mobil ağla ilgili tercihler şuydu:
mobil ağ olmayan cihazlarda dizine eklenmemelidir. Bu durumda, getNonIndexableKeys
yöntemini geçersiz kılın ve bir cihazda mobil ağ olmadığında uygun anahtarları dizine eklenemez 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; } }; }
Söz konusu parçanın ihtiyaçlarına bağlı olarak, CarBaseSearchIndexProvider
sınıfının diğer yöntemleri, statik ve dinamik ham veriler gibi dizine eklenebilir diğer 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; } }; }
Dizine eklenen ayarlar
Dizine eklenecek bir ayar eklemek için:
- Uygulamanız için bir
SearchIndexablesProvider
tanımlamak içinandroid.provider.SearchIndexablesProvider
sınıf. - 1. adımda uygulamanın
AndroidManifest.xml
ayarını sağlayıcıyla güncelleyin. Biçim:<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 dizine eklenebilir veriler ekleyin. Uygulama, kurumun
görebilirsiniz. İ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; } } }