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 android.provider; 18 19 import android.content.ContentProvider; 20 import android.content.ContentValues; 21 import android.content.Context; 22 import android.content.UriMatcher; 23 import android.content.pm.ProviderInfo; 24 import android.database.Cursor; 25 import android.net.Uri; 26 27 /** 28 * Base class for a search indexable provider. Such provider offers data to be indexed either 29 * as a reference to an XML file (like a {@link android.preference.PreferenceScreen}) or either 30 * as some raw data. 31 * 32 * @see SearchIndexableResource 33 * @see SearchIndexableData 34 * @see SearchIndexablesContract 35 * 36 * To create a search indexables provider, extend this class, then implement the abstract methods, 37 * and add it to your manifest like this: 38 * 39 * <pre class="prettyprint"><manifest> 40 * ... 41 * <application> 42 * ... 43 * <provider 44 * android:name="com.example.MyIndexablesProvider" 45 * android:authorities="com.example.myindexablesprovider" 46 * android:exported="true" 47 * android:grantUriPermissions="true" 48 * android:permission="android.permission.READ_SEARCH_INDEXABLES" 49 * <intent-filter> 50 * <action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER" /> 51 * </intent-filter> 52 * </provider> 53 * ... 54 * </application> 55 *</manifest></pre> 56 * <p> 57 * When defining your provider, you must protect it with 58 * {@link android.Manifest.permission#READ_SEARCH_INDEXABLES}, which is a permission only the system 59 * can obtain. 60 * </p> 61 * 62 * @hide 63 */ 64 public abstract class SearchIndexablesProvider extends ContentProvider { 65 private static final String TAG = "IndexablesProvider"; 66 67 private String mAuthority; 68 private UriMatcher mMatcher; 69 70 private static final int MATCH_RES_CODE = 1; 71 private static final int MATCH_RAW_CODE = 2; 72 private static final int MATCH_NON_INDEXABLE_KEYS_CODE = 3; 73 74 /** 75 * Implementation is provided by the parent class. 76 */ 77 @Override attachInfo(Context context, ProviderInfo info)78 public void attachInfo(Context context, ProviderInfo info) { 79 mAuthority = info.authority; 80 81 mMatcher = new UriMatcher(UriMatcher.NO_MATCH); 82 mMatcher.addURI(mAuthority, SearchIndexablesContract.INDEXABLES_XML_RES_PATH, 83 MATCH_RES_CODE); 84 mMatcher.addURI(mAuthority, SearchIndexablesContract.INDEXABLES_RAW_PATH, 85 MATCH_RAW_CODE); 86 mMatcher.addURI(mAuthority, SearchIndexablesContract.NON_INDEXABLES_KEYS_PATH, 87 MATCH_NON_INDEXABLE_KEYS_CODE); 88 89 // Sanity check our setup 90 if (!info.exported) { 91 throw new SecurityException("Provider must be exported"); 92 } 93 if (!info.grantUriPermissions) { 94 throw new SecurityException("Provider must grantUriPermissions"); 95 } 96 if (!android.Manifest.permission.READ_SEARCH_INDEXABLES.equals(info.readPermission)) { 97 throw new SecurityException("Provider must be protected by READ_SEARCH_INDEXABLES"); 98 } 99 100 super.attachInfo(context, info); 101 } 102 103 @Override query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)104 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 105 String sortOrder) { 106 switch (mMatcher.match(uri)) { 107 case MATCH_RES_CODE: 108 return queryXmlResources(null); 109 case MATCH_RAW_CODE: 110 return queryRawData(null); 111 case MATCH_NON_INDEXABLE_KEYS_CODE: 112 return queryNonIndexableKeys(null); 113 default: 114 throw new UnsupportedOperationException("Unknown Uri " + uri); 115 } 116 } 117 118 /** 119 * Returns all {@link android.provider.SearchIndexablesContract.XmlResource}. 120 * 121 * Those are Xml resource IDs to some {@link android.preference.PreferenceScreen}. 122 * 123 * @param projection list of {@link android.provider.SearchIndexablesContract.XmlResource} 124 * columns to put into the cursor. If {@code null} all supported columns 125 * should be included. 126 */ queryXmlResources(String[] projection)127 public abstract Cursor queryXmlResources(String[] projection); 128 129 /** 130 * Returns all {@link android.provider.SearchIndexablesContract.RawData}. 131 * 132 * Those are the raw indexable data. 133 * 134 * @param projection list of {@link android.provider.SearchIndexablesContract.RawData} columns 135 * to put into the cursor. If {@code null} all supported columns should be 136 * included. 137 */ queryRawData(String[] projection)138 public abstract Cursor queryRawData(String[] projection); 139 140 /** 141 * Returns all {@link android.provider.SearchIndexablesContract.NonIndexableKey}. 142 * 143 * Those are the non indexable data keys. 144 * 145 * @param projection list of {@link android.provider.SearchIndexablesContract.NonIndexableKey} 146 * columns to put into the cursor. If {@code null} all supported columns 147 * should be included. 148 */ queryNonIndexableKeys(String[] projection)149 public abstract Cursor queryNonIndexableKeys(String[] projection); 150 151 @Override getType(Uri uri)152 public String getType(Uri uri) { 153 switch (mMatcher.match(uri)) { 154 case MATCH_RES_CODE: 155 return SearchIndexablesContract.XmlResource.MIME_TYPE; 156 case MATCH_RAW_CODE: 157 return SearchIndexablesContract.RawData.MIME_TYPE; 158 case MATCH_NON_INDEXABLE_KEYS_CODE: 159 return SearchIndexablesContract.NonIndexableKey.MIME_TYPE; 160 default: 161 throw new IllegalArgumentException("Unknown URI " + uri); 162 } 163 } 164 165 /** 166 * Implementation is provided by the parent class. Throws by default, and cannot be overriden. 167 */ 168 @Override insert(Uri uri, ContentValues values)169 public final Uri insert(Uri uri, ContentValues values) { 170 throw new UnsupportedOperationException("Insert not supported"); 171 } 172 173 /** 174 * Implementation is provided by the parent class. Throws by default, and cannot be overriden. 175 */ 176 @Override delete(Uri uri, String selection, String[] selectionArgs)177 public final int delete(Uri uri, String selection, String[] selectionArgs) { 178 throw new UnsupportedOperationException("Delete not supported"); 179 } 180 181 /** 182 * Implementation is provided by the parent class. Throws by default, and cannot be overriden. 183 */ 184 @Override update( Uri uri, ContentValues values, String selection, String[] selectionArgs)185 public final int update( 186 Uri uri, ContentValues values, String selection, String[] selectionArgs) { 187 throw new UnsupportedOperationException("Update not supported"); 188 } 189 } 190