1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.search; 18 19 import android.content.Context; 20 import android.database.Cursor; 21 import android.database.MatrixCursor; 22 import android.provider.SearchIndexableResource; 23 import android.provider.SearchIndexablesProvider; 24 import android.util.Log; 25 26 import com.android.settings.search2.DatabaseIndexingUtils; 27 28 import java.util.Collection; 29 import java.util.Collections; 30 import java.util.HashSet; 31 import java.util.List; 32 33 import static android.provider.SearchIndexablesContract.COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE; 34 import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_CLASS_NAME; 35 import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_ICON_RESID; 36 import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_ACTION; 37 import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS; 38 import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE; 39 import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_RANK; 40 import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_RESID; 41 import static android.provider.SearchIndexablesContract.INDEXABLES_RAW_COLUMNS; 42 import static android.provider.SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS; 43 import static android.provider.SearchIndexablesContract.NON_INDEXABLES_KEYS_COLUMNS; 44 45 public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider { 46 private static final String TAG = "SettingsSearchProvider"; 47 48 @Override onCreate()49 public boolean onCreate() { 50 return true; 51 } 52 53 @Override queryXmlResources(String[] projection)54 public Cursor queryXmlResources(String[] projection) { 55 MatrixCursor cursor = new MatrixCursor(INDEXABLES_XML_RES_COLUMNS); 56 Collection<SearchIndexableResource> values = SearchIndexableResources.values(); 57 for (SearchIndexableResource val : values) { 58 Object[] ref = new Object[INDEXABLES_XML_RES_COLUMNS.length]; 59 ref[COLUMN_INDEX_XML_RES_RANK] = val.rank; 60 ref[COLUMN_INDEX_XML_RES_RESID] = val.xmlResId; 61 ref[COLUMN_INDEX_XML_RES_CLASS_NAME] = val.className; 62 ref[COLUMN_INDEX_XML_RES_ICON_RESID] = val.iconResId; 63 ref[COLUMN_INDEX_XML_RES_INTENT_ACTION] = null; // intent action 64 ref[COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE] = null; // intent target package 65 ref[COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS] = null; // intent target class 66 cursor.addRow(ref); 67 } 68 return cursor; 69 } 70 71 @Override queryRawData(String[] projection)72 public Cursor queryRawData(String[] projection) { 73 MatrixCursor result = new MatrixCursor(INDEXABLES_RAW_COLUMNS); 74 return result; 75 } 76 77 /** 78 * Gets a combined list non-indexable keys that come from providers inside of settings. 79 * The non-indexable keys are used in Settings search at both index and update time to verify 80 * the validity of results in the database. 81 */ 82 @Override queryNonIndexableKeys(String[] projection)83 public Cursor queryNonIndexableKeys(String[] projection) { 84 MatrixCursor cursor = new MatrixCursor(NON_INDEXABLES_KEYS_COLUMNS); 85 final Collection<String> values = new HashSet<>(); 86 final Context context = getContext(); 87 88 for (SearchIndexableResource sir : SearchIndexableResources.values()) { 89 final Class<?> clazz = DatabaseIndexingUtils.getIndexableClass(sir.className); 90 if (clazz == null) { 91 Log.d(TAG, "SearchIndexableResource '" + sir.className + 92 "' should implement the " + Indexable.class.getName() + " interface!"); 93 continue; 94 } 95 96 final Indexable.SearchIndexProvider provider = 97 DatabaseIndexingUtils.getSearchIndexProvider(clazz); 98 99 if (provider == null) { 100 Log.d(TAG, "Unable to get SearchIndexableProvider from " + 101 Indexable.class.getName()); 102 continue; 103 } 104 105 List<String> providerNonIndexableKeys = provider.getNonIndexableKeys(context); 106 107 if (providerNonIndexableKeys == null || providerNonIndexableKeys.isEmpty()) { 108 continue; 109 } 110 111 if (providerNonIndexableKeys.removeAll(Collections.singleton(null)) 112 || providerNonIndexableKeys.removeAll(Collections.singleton(""))) { 113 Log.v(TAG, clazz.getName() + " tried to add an empty non-indexable key"); 114 } 115 116 values.addAll(providerNonIndexableKeys); 117 } 118 119 for (String nik : values) { 120 121 final Object[] ref = new Object[NON_INDEXABLES_KEYS_COLUMNS.length]; 122 ref[COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE] = nik; 123 cursor.addRow(ref); 124 } 125 return cursor; 126 } 127 } 128