Home | History | Annotate | Download | only in provider
      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">&lt;manifest&gt;
     41  *    ...
     42  *    &lt;application&gt;
     43  *        ...
     44  *        &lt;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  *            &lt;intent-filter&gt;
     51  *                &lt;action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER" /&gt;
     52  *            &lt;/intent-filter&gt;
     53  *        &lt;/provider&gt;
     54  *        ...
     55  *    &lt;/application&gt;
     56  *&lt;/manifest&gt;</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