La recherche dans les paramètres vous permet de rechercher et de modifier rapidement et facilement dans l'application Automotive Settings sans avoir à naviguer dans les menus de l'application pour le trouver. La recherche est le moyen le plus efficace de trouver un paramètre spécifique. Par défaut, la recherche ne trouve que les paramètres AOSP. Des paramètres supplémentaires, injectés ou non, nécessitent des modifications supplémentaires pour être indexées.
Conditions requises
Pour qu'un paramètre puisse être indexé par la recherche de paramètres, les données doivent provenir:
- Fragment
SearchIndexable
dansCarSettings
. - Application système.
Définir les données
Champs courants:
Key
(Obligatoire) Clé de chaîne unique et lisible pour identifier le résultat.IconResId
Facultatif. Si une icône apparaît dans votre application à côté de l'icône résultat, puis ajoutez l'ID de ressource. Sinon, ignorez-le.IntentAction
Obligatoire siIntentTargetPackage
ouIntentTargetClass
n'est pas défini. Définit l'action que le résultat de recherche l'intention est de prendre.IntentTargetPackage
Obligatoire siIntentAction
n'est pas défini définis. Définit le package vers lequel l'intent des résultats de recherche doit être résolu.IntentTargetClass
Obligatoire siIntentAction
n'est pas défini définis. Définit la classe (activité) à laquelle doit renvoyer l'intent des résultats de recherche.
SearchIndexableResource
uniquement:
XmlResId
(Obligatoire) Définit l'ID de ressource XML de la page contenant les résultats à indexer.
SearchIndexableRaw
uniquement:
Title
(Obligatoire) Titre du résultat de recherche.SummaryOn
(Facultatif) Récapitulatif du résultat de recherche.Keywords
(Facultatif) Liste des mots associés au résultat de recherche. Associe la requête à votre résultat.ScreenTitle
(Facultatif) Titre de la page contenant votre résultat de recherche.
Masquer les données
Chaque résultat de recherche apparaît dans la recherche, sauf indication contraire. En mode statique les résultats de recherche sont mis en cache, une nouvelle liste de clés non indexables est récupérée à chaque fois la recherche est ouverte. Vous pouvez masquer des résultats dans les cas suivants:
- Dupliquer. Par exemple, s'affiche sur plusieurs pages.
- Affichage sous conditions uniquement. Par exemple, n'affiche que les paramètres de données mobiles en présence d'une carte SIM).
- Modèle de page : (page d'informations concernant une application, par exemple).
- Le paramètre nécessite plus de contexte qu'un titre et un sous-titre. Pour exemple, une section "Paramètres" qui ne concerne que le titre de l'écran.
Pour masquer un paramètre, votre fournisseur ou SEARCH_INDEX_DATA_PROVIDER
doit
renvoie la clé du résultat de recherche à partir de getNonIndexableKeys
. La clé peut
toujours être renvoyées (cas de pages modélisés en double) ou ajoutées sous condition (pas de version mobile
cas de données).
Index statique
Utilisez l'index statique si vos données d'index sont toujours les mêmes. Par exemple, le titre et le résumé des données XML ou les données brutes codées en dur. Les données statiques sont indexées qu'une seule fois, lorsque la recherche de paramètres est lancée pour la première fois.
Pour les éléments indexables dans les paramètres, implémentez getXmlResourcesToIndex
.
et/ou getRawDataToIndex
. Pour les paramètres injectés, implémentez la
Méthodes queryXmlResources
et/ou queryRawData
.
Index dynamique
Si les données indexables peuvent être mises à jour en conséquence, utilisez la méthode dynamique pour pour indexer vos données. La recherche dans les paramètres met à jour cette liste dynamique lorsqu'elle est lancée.
Pour les éléments indexables dans les paramètres, implémentez getDynamicRawDataToIndex
.
Pour les paramètres injectés, implémentez queryDynamicRawData methods
.
Indexer dans les paramètres du véhicule
Pour indexer différents paramètres à inclure dans la fonctionnalité de recherche, consultez
Contenu
fournisseurs. SettingsLib
et android.provider
Les packages ont déjà des interfaces définies et des classes abstraites à étendre pour
en fournissant de nouvelles entrées à indexer. Dans les paramètres AOSP, les implémentations de ces
sont utilisées pour indexer les résultats. La principale interface à utiliser est
SearchIndexablesProvider
, utilisé par
SettingsIntelligence
pour indexer des données.
public abstract class SearchIndexablesProvider extends ContentProvider { public abstract Cursor queryXmlResources(String[] projection); public abstract Cursor queryRawData(String[] projection); public abstract Cursor queryNonIndexableKeys(String[] projection); }
En théorie, chaque fragment pourrait être ajouté aux résultats dans
SearchIndexablesProvider
, auquel cas SettingsIntelligence
serait le contenu. Pour faciliter la gestion du processus et l'ajout de nouveaux fragments,
utilisez la génération de code SettingsLib
pour SearchIndexableResources
.
Spécifique aux paramètres de la voiture, chaque fragment indexable est annoté avec
@SearchIndexable
, puis une SearchIndexProvider
statique
qui fournit les données pertinentes pour ce fragment. Les fragments avec le paramètre
mais qu'il manque un élément SearchIndexProvider
, cela entraîne une compilation
.
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); }
Tous ces fragments sont ensuite ajoutés au
La classe SearchIndexableResourcesAuto
, qui est un wrapper léger
autour de la liste des champs SearchIndexProvider
pour tous les fragments.
La prise en charge de la spécification d'une cible spécifique pour une annotation (comme
"Auto", "TV" et "Wear") mais la plupart des annotations conservent les valeurs par défaut (All
).
Dans ce cas d'utilisation, il n'est pas nécessaire de spécifier la cible automatique. Elle reste donc
en tant que All
. L'implémentation de base de SearchIndexProvider
est suffisant pour la plupart des fragments.
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; } }
Indexer un nouveau fragment
Avec cette conception, il est relativement facile d'ajouter un nouveau SettingsFragment
.
à indexer, il s'agit généralement d'une mise à jour de deux lignes fournissant le code XML du fragment et de l'élément
à suivre. Avec WifiSettingsFragment
comme exemple:
@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); }
L'implémentation AAOS de SearchIndexablesProvider
, qui
utilise SearchIndexableResources
et effectue la traduction
SearchIndexProviders
dans le schéma de base de données
SettingsIntelligence
, mais est indépendant de ce que sont les fragments
en cours d'indexation. SettingsIntelligence
accepte n'importe quel nombre de
de fournisseurs, ce qui permet de créer des fournisseurs pour des cas d'utilisation
chacun d'eux étant spécialisé et axé sur des résultats similaires
différentes. Les préférences définies dans les PreferenceScreen
du fragment doivent être associés à une clé unique
peut être indexée. De plus, PreferenceScreen
doit comporter une clé
attribué pour que le titre de l'écran soit indexé.
Exemples d'index
Dans certains cas, un fragment peut ne pas être associé à une action d'intent spécifique.
avec lui. Dans ce cas, il est possible de transmettre la classe d'activité
l'intent CarBaseSearchIndexProvider
à l'aide d'un composant plutôt que
une action. L'activité doit toujours être présente dans le fichier manifeste
et son exportation.
@SearchIndexable public class LanguagesAndInputFragment extends SettingsFragment { [...] public static final CarBaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new CarBaseSearchIndexProvider(R.xml.languages_and_input_fragment, LanguagesAndInputActivity.class); }
Dans certains cas particuliers, certaines méthodes de CarBaseSearchIndexProvider
qu'il peut être nécessaire de remplacer pour que les résultats souhaités soient indexés. Par exemple, dans
NetworkAndInternetFragment
, les préférences liées au réseau mobile étaient
ne pas être indexées sur des appareils
sans réseau mobile. Dans ce cas, remplacez la
getNonIndexableKeys
et marquer les clés appropriées comme
non indexable lorsqu'un appareil ne dispose pas d'un réseau mobile.
@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; } }; }
Selon les besoins du fragment particulier, d'autres méthodes de
CarBaseSearchIndexProvider
peut être remplacé pour inclure d'autres
les données indexables, telles que les données brutes statiques et dynamiques.
@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; } }; }
Paramètres d'injection d'index
Pour injecter un paramètre à indexer:
- Définissez un
SearchIndexablesProvider
pour votre application en étendant laandroid.provider.SearchIndexablesProvider
. - Mettez à jour le
AndroidManifest.xml
de l'application auprès du fournisseur à l'étape 1. Le format est le suivant: <ph type="x-smartling-placeholder"><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>
-
Ajoutez des données indexables à votre fournisseur. L'implémentation dépend des besoins
l'application. Deux types de données différents peuvent être indexés:
SearchIndexableResource
etSearchIndexableRaw
.
Exemple 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; } } }