Araba Ayarları arama dizine ekleme

Ayarlar araması, belirli öğeleri hızlı ve kolay bir şekilde aramanızı ve değiştirmenizi sağlar uygulama menülerinde gezinmeden otomotiv Ayarları uygulamasında onu bulacağım. Arama, belirli bir ayarı bulmanın en etkili yoludur. Varsayılan olarak arama 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çinde SearchIndexable parçası.
  • Sistem düzeyinde uygulama.

Verileri tanımlama

Ortak alanlar:

  • Key (Zorunlu) Sonucu tanımlamak için kullanıcıların okuyabileceği benzersiz dize anahtarı.
  • IconResId İsteğe bağlı Uygulamanızda ekleyin, kaynak kimliğini ekleyin, aksi takdirde yoksayın.
  • IntentAction Zorunlu ise IntentTargetPackage veya IntentTargetClass tanımlı değil. Arama sonucu tarafından yapılacak işlemi tanımlar kabul etmektir.
  • IntentTargetPackage IntentAction değilse zorunlu tanımlanmıştır. Arama sonucu amacının çözümleneceği paketi tanımlar.
  • IntentTargetClass IntentAction değilse zorunlu tanımlanmıştır. Arama sonucu amacının çözümleyeceği sınıfı (etkinliği) tanımlar.

Yalnızca SearchIndexableResource:

  • XmlResId (Zorunlu) Şunu içeren sayfanın XML kaynak kimliğini tanımlar: dizine eklenecek.

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. Sabityken arama sonuçları önbelleğe alınır, her seferinde dizine eklenemeyen anahtarların yeni bir listesi alınır arama açılı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 mobil veri ayarlarını gösterir SIM kart varsa).
  • Şablonlu sayfa. Örneğin, belirli 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 paketlerde halihazırda genişletilecek tanımlanmış arayüzler ve soyut sınıflar bulunur dizine eklenecek yeni girişler sağlar. AOSP ayarlarında, bu uygulamalar sınıfları, sonuçları dizine eklemek için kullanılır. Karşılanacak birincil arayüz: SearchIndexablesProvider şirketinin kullanımı Verileri dizine eklemek için 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);
}

Teoride her parça, 2022'den bu yana SearchIndexablesProvider (bu durumda SettingsIntelligence) içerik olacaktır. 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);
    }

Daha sonra, bu parçalar otomatik oluşturulan İnce bir sarmalayıcı olan SearchIndexableResourcesAuto sınıfı SearchIndexProvider alanları listesinin etrafına yerleştirilir. 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. Temel SearchIndexProvider uygulaması çoğu parça için yeterli olması amaçlanı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. Örnek olarak 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 ö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, PreferenceScreen bir anahtar içermelidir öğesine atanır.

Dizin örnekleri

Bazı durumlarda, bir parçanın ilişkilendirilmiş belirli bir intent işlemi olmayabilir gerçekleşebilir. Bu gibi durumlarda, etkinlik sınıfının CarBaseSearchIndexProvider niyetini kullanmak yerine bir bileşen kullanır bir eylemdir. Bunun için de etkinliğin manifest dosyasında olması gerekir. dışa aktarılabilmesidir.

@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, bazı CarBaseSearchIndexProvider yöntemleri istenen sonuçların dizine eklenmesi için 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 kullanın ve uygun tuşları mobil ağ bağlantısı olmayan cihazlarda dizine eklenemez.

@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, parçanın diğer yöntemleri CarBaseSearchIndexProvider, diğer dizine eklenebilir veriler (ör. statik ve dinamik ham veriler).

@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:

  1. Uygulamanız için bir SearchIndexablesProvider tanımlamak için android.provider.SearchIndexablesProvider sınıf.
  2. 1. adımda uygulamanın AndroidManifest.xml ayarını sağlayıcıyla güncelleyin. Biçimi şöyledir:
    <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>
    
  3. Sağlayıcınıza dizine eklenebilir veriler ekleyin. Uygulama, kurumun görebilirsiniz. İki farklı veri türü dizine eklenebilir: SearchIndexableResource ve SearchIndexableRaw.

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