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