Suchindexierung der Autoeinstellungen

Über die Suche in den Einstellungen können Sie schnell und einfach nach bestimmten Automotive-Einstellungen ändern, ohne über die App-Menüs finden. Die Suche ist die effektivste Möglichkeit, eine bestimmte Einstellung zu finden. Standardmäßig Bei der Suche werden nur die AOSP-Einstellungen gefunden. Zusätzliche Einstellungen, ob eingeschleust oder nicht, für die Indexierung erforderlich sind.

Voraussetzungen

Damit eine Einstellung von der Einstellungssuche indexiert werden kann, müssen die Daten aus einer der folgenden Quellen stammen:

  • Fragment SearchIndexable innerhalb von CarSettings.
  • App auf Systemebene.

Daten definieren

Häufig verwendete Felder:

  • Key (Erforderlich) Eindeutiger menschenlesbarer Stringschlüssel zur Identifizierung des Ergebnisses.
  • IconResId Optional: Wenn in Ihrer App neben dem Symbol und fügen Sie dann die Ressourcen-ID hinzu. Andernfalls ignorieren Sie die Anfrage.
  • IntentAction Erforderlich, wenn IntentTargetPackage oder IntentTargetClass ist nicht definiert. Definiert die Aktion, die das Suchergebnis was Ihre Absicht ist.
  • IntentTargetPackage Erforderlich, wenn IntentAction nicht definiert. Definiert das Paket, in das der Suchergebnis-Intent aufgelöst werden soll.
  • IntentTargetClass Erforderlich, wenn IntentAction nicht definiert. Definiert die Klasse (Aktivität), in die der Suchergebnis-Intent aufgelöst werden soll.

Nur SearchIndexableResource:

  • XmlResId (Erforderlich) Definiert die XML-Ressourcen-ID der Seite, die die zu indexierenden Ergebnisse.

Nur SearchIndexableRaw:

  • Title (Erforderlich) Der Titel des Suchergebnisses.
  • SummaryOn (Optional) Zusammenfassung des Suchergebnisses.
  • Keywords (Optional) Liste der Wörter, die mit dem Suchergebnis verknüpft sind. Ordnet die Abfrage Ihrem Ergebnis zu.
  • ScreenTitle (Optional) Titel der Seite mit Ihrem Suchergebnis.

Daten ausblenden

Jedes Suchergebnis wird in der Suche angezeigt, sofern es nicht anders gekennzeichnet ist. Während statisch Suchergebnisse im Cache gespeichert werden, wird jedes Mal eine neue Liste nicht indizierbarer Schlüssel abgerufen. Suche geöffnet. Mögliche Gründe für das Ausblenden von Ergebnissen:

  • Duplizieren: zum Beispiel auf mehreren Seiten.
  • Wird nur bedingt angezeigt. Zeigt beispielsweise nur Einstellungen für mobile Daten an wenn eine SIM-Karte vorhanden ist).
  • Vorlagenseite: Zum Beispiel eine Detailseite für eine einzelne App.
  • Die Umgebung erfordert mehr Kontext als ein Titel und Untertitel. Für „Einstellungen“ die nur für den Bildschirmtitel relevant ist.

Zum Ausblenden einer Einstellung muss dein Anbieter oder SEARCH_INDEX_DATA_PROVIDER Folgendes tun: gibt den Schlüssel des Suchergebnisses von getNonIndexableKeys zurück. Der Schlüssel kann immer zurückgegeben (doppelte Fälle von Seiten mit Vorlagen) oder unter bestimmten Bedingungen hinzugefügt (keine mobilen Seiten) Data Case).

Statischer Index

Verwenden Sie den statischen Index, wenn die Indexdaten immer identisch sind. Zum Beispiel der Titel Zusammenfassung von XML-Daten oder hartcodierten Rohdaten. Die statischen Daten werden indexiert nur einmal, wenn die Suche in den Einstellungen gestartet wird.

Für indexierbare Dateien in Einstellungen getXmlResourcesToIndex implementieren und/oder getRawDataToIndex. Implementieren Sie für injizierte Einstellungen den queryXmlResources- und/oder queryRawData-Methoden.

Dynamischer Index

Wenn die indexierbaren Daten entsprechend aktualisiert werden können, verwenden Sie die dynamische Methode, Ihre Daten zu indexieren. Die Einstellungssuche aktualisiert diese dynamische Liste, wenn sie aktiviert wird.

Implementieren Sie getDynamicRawDataToIndex für indexierte Inhalte in den Einstellungen. Implementieren Sie für injizierte Einstellungen den queryDynamicRawData methods.

Index in den Autoeinstellungen

Informationen zum Indexieren verschiedener Einstellungen für die Suchfunktion finden Sie unter Inhalt Anbieter. SettingsLib und android.provider Pakete haben bereits definierte Schnittstellen und abstrakte Klassen, die erweitert werden sollen neue Einträge für die Indexierung bereitgestellt. In den AOSP-Einstellungen werden Implementierungen dieser Klassen zum Indexieren von Ergebnissen verwendet werden. Die primäre Schnittstelle, die erfüllt werden muss, SearchIndexablesProvider, das von verwendet wird SettingsIntelligence, um Daten zu indexieren.

public abstract class SearchIndexablesProvider extends ContentProvider {
    public abstract Cursor queryXmlResources(String[] projection);
    public abstract Cursor queryRawData(String[] projection);
    public abstract Cursor queryNonIndexableKeys(String[] projection);
}

Theoretisch könnte jedes Fragment in den Ergebnissen SearchIndexablesProvider, in diesem Fall SettingsIntelligence wären Inhalte. Um den Vorgang zum Hinzufügen neuer Fragmente zu vereinfachen, SettingsLib-Codegenerierung von SearchIndexableResources verwenden. Speziell für die Autoeinstellungen ist jedes indizierbare Fragment mit @SearchIndexable und hat dann einen statischen SearchIndexProvider das die relevanten Daten für dieses Fragment enthält. Fragmente mit dem Annotation, aber ohne SearchIndexProvider führen zu einer Kompilierung Fehler.

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);
    }

Alle diese Fragmente werden dann dem automatisch generierten Die Klasse SearchIndexableResourcesAuto, ein Thin Wrapper, um die Liste der SearchIndexProvider-Felder für alle Fragmente. Es wird unterstützt, ein bestimmtes Ziel für eine Annotation anzugeben (z. B. Auto, TV und Wear). Für die meisten Anmerkungen wird jedoch die Standardeinstellung beibehalten (All). In diesem Anwendungsfall muss das automatische Ziel nicht speziell angegeben werden. Es bleibt also als All. Die Basisimplementierung von SearchIndexProvider für die meisten Fragmente ausreichen.

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;
    }
}

Neues Fragment indexieren

Bei diesem Design ist es relativ einfach, eine neue SettingsFragment in der Regel ein zweizeiliges Update, in dem die XML-Datei für das Fragment und der verfolgt werden soll. Mit WifiSettingsFragment als Beispiel:

@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);
}

Die AAOS-Implementierung von SearchIndexablesProvider, die verwendet SearchIndexableResources und führt die Übersetzung SearchIndexProviders in das Datenbankschema für SettingsIntelligence, ist aber unabhängig von den Fragmenten. bei der Indexierung. SettingsIntelligence unterstützt beliebig viele damit neue Anbieter erstellt werden können, So kann sich jeder spezialisieren und sich auf Ergebnisse mit ähnlichen Strukturen. Die in PreferenceScreen definierten Einstellungen für das Fragment muss jeweils ein eindeutiger Schlüssel zugewiesen sein, damit indexiert. Außerdem muss PreferenceScreen einen Schlüssel haben , dem der Bildschirmtitel zugewiesen ist, der indexiert werden soll.

Indexbeispiele

In einigen Fällen ist einem Fragment keine bestimmte Intent-Aktion zugeordnet damit nichts. In solchen Fällen ist es möglich, die Aktivitätsklasse an die CarBaseSearchIndexProvider-Intent verwendet eine Komponente statt eine Aktion ausführen. Auch dafür muss die Aktivität in der Manifestdatei vorhanden sein. und sie kann exportiert werden.

@SearchIndexable
public class LanguagesAndInputFragment extends SettingsFragment {
[...]
    public static final CarBaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
        new CarBaseSearchIndexProvider(R.xml.languages_and_input_fragment,
                LanguagesAndInputActivity.class);
}

In einigen Sonderfällen können einige CarBaseSearchIndexProvider-Methoden müssen möglicherweise überschrieben werden, damit die gewünschten Ergebnisse indexiert werden. Beispiel: NetworkAndInternetFragment, Einstellungen in Bezug auf Mobilfunknetz waren die auf Geräten ohne Mobilfunknetz nicht indexiert werden dürfen. In diesem Fall überschreiben Sie getNonIndexableKeys und markieren Sie die entsprechenden Schlüssel als nicht indizierbar, wenn ein Gerät kein Mobilfunknetz hat.

@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;
                }
            };
}

Je nach den Anforderungen des jeweiligen Fragments können andere Methoden der CarBaseSearchIndexProvider kann überschrieben werden, um andere Indexierbare Daten wie statische und dynamische Rohdaten.

@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;
                }
            };
}

Einstellungen für in den Index eingefügte Einstellungen

So fügen Sie eine Einstellung ein, die indexiert werden soll:

  1. Definiere ein SearchIndexablesProvider für deine App, indem du die Klasse android.provider.SearchIndexablesProvider.
  2. Aktualisieren Sie in Schritt 1 die AndroidManifest.xml der App durch den Anbieter. Das Format ist:
    <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>
    
    <ph type="x-smartling-placeholder">
  3. Fügen Sie Ihrem Anbieter Indexierbare Daten hinzu. Die Implementierung hängt von den Anforderungen der in der App. Es können zwei verschiedene Datentypen indexiert werden: SearchIndexableResource und SearchIndexableRaw.

Beispiel für 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;
        }
    }
}