1b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio/*
2b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * Copyright (C) 2014 The Android Open Source Project
3b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *
4b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * Licensed under the Apache License, Version 2.0 (the "License");
5b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * you may not use this file except in compliance with the License.
6b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * You may obtain a copy of the License at
7b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *
8b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *      http://www.apache.org/licenses/LICENSE-2.0
9b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *
10b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * Unless required by applicable law or agreed to in writing, software
11b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * distributed under the License is distributed on an "AS IS" BASIS,
12b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * See the License for the specific language governing permissions and
14b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * limitations under the License.
15b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio */
16b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio
17b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Megliopackage android.provider;
18b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio
19b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglioimport android.content.ContentProvider;
20b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglioimport android.content.ContentValues;
21b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglioimport android.content.Context;
22b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglioimport android.content.UriMatcher;
23b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglioimport android.content.pm.ProviderInfo;
24b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglioimport android.database.Cursor;
25b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglioimport android.net.Uri;
26b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio
27b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio/**
28b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * Base class for a search indexable provider. Such provider offers data to be indexed either
29b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * as a reference to an XML file (like a {@link android.preference.PreferenceScreen}) or either
30b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * as some raw data.
31b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *
32b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * @see SearchIndexableResource
33b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * @see SearchIndexableData
34b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * @see SearchIndexablesContract
35b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *
36b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * To create a search indexables provider, extend this class, then implement the abstract methods,
37b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * and add it to your manifest like this:
38b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *
39b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * <pre class="prettyprint">&lt;manifest&gt;
40b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *    ...
41b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *    &lt;application&gt;
42b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *        ...
43b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *        &lt;provider
44b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *            android:name="com.example.MyIndexablesProvider"
45b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *            android:authorities="com.example.myindexablesprovider"
46b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *            android:exported="true"
47b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *            android:grantUriPermissions="true"
48b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *            android:permission="android.permission.READ_SEARCH_INDEXABLES"
49b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *            &lt;intent-filter&gt;
50b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *                &lt;action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER" /&gt;
51b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *            &lt;/intent-filter&gt;
52b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *        &lt;/provider&gt;
53b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *        ...
54b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *    &lt;/application&gt;
55b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *&lt;/manifest&gt;</pre>
56b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * <p>
57b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * When defining your provider, you must protect it with
58b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * {@link android.Manifest.permission#READ_SEARCH_INDEXABLES}, which is a permission only the system
59b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * can obtain.
60b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * </p>
61b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio *
62b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio * @hide
63b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio */
64b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Megliopublic abstract class SearchIndexablesProvider extends ContentProvider {
65b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    private static final String TAG = "IndexablesProvider";
66b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio
67b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    private String mAuthority;
68b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    private UriMatcher mMatcher;
69b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio
70b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    private static final int MATCH_RES_CODE = 1;
71b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    private static final int MATCH_RAW_CODE = 2;
7297babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio    private static final int MATCH_NON_INDEXABLE_KEYS_CODE = 3;
73b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio
74b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    /**
75b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio     * Implementation is provided by the parent class.
76b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio     */
77b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    @Override
78b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    public void attachInfo(Context context, ProviderInfo info) {
79b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio        mAuthority = info.authority;
80b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio
81b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio        mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
82b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio        mMatcher.addURI(mAuthority, SearchIndexablesContract.INDEXABLES_XML_RES_PATH,
83b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio                MATCH_RES_CODE);
84b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio        mMatcher.addURI(mAuthority, SearchIndexablesContract.INDEXABLES_RAW_PATH,
85b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio                MATCH_RAW_CODE);
8697babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio        mMatcher.addURI(mAuthority, SearchIndexablesContract.NON_INDEXABLES_KEYS_PATH,
8797babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio                MATCH_NON_INDEXABLE_KEYS_CODE);
88b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio
89b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio        // Sanity check our setup
90b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio        if (!info.exported) {
91b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio            throw new SecurityException("Provider must be exported");
92b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio        }
93b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio        if (!info.grantUriPermissions) {
94b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio            throw new SecurityException("Provider must grantUriPermissions");
95b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio        }
96b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio        if (!android.Manifest.permission.READ_SEARCH_INDEXABLES.equals(info.readPermission)) {
97b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio            throw new SecurityException("Provider must be protected by READ_SEARCH_INDEXABLES");
98b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio        }
99b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio
100b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio        super.attachInfo(context, info);
101b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    }
102b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio
103b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    @Override
104b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
105b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio                        String sortOrder) {
106b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio        switch (mMatcher.match(uri)) {
107b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio            case MATCH_RES_CODE:
108b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio                return queryXmlResources(null);
109b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio            case MATCH_RAW_CODE:
110b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio                return queryRawData(null);
11197babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio            case MATCH_NON_INDEXABLE_KEYS_CODE:
11297babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio                return queryNonIndexableKeys(null);
113b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio            default:
114b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio                throw new UnsupportedOperationException("Unknown Uri " + uri);
115b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio        }
116b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    }
117b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio
118b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    /**
119b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio     * Returns all {@link android.provider.SearchIndexablesContract.XmlResource}.
120b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio     *
12197babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio     * Those are Xml resource IDs to some {@link android.preference.PreferenceScreen}.
122b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio     *
123b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio     * @param projection list of {@link android.provider.SearchIndexablesContract.XmlResource}
124b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio     *                   columns to put into the cursor. If {@code null} all supported columns
125b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio     *                   should be included.
126b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio     */
127b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    public abstract Cursor queryXmlResources(String[] projection);
128b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio
129b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    /**
130b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio     * Returns all {@link android.provider.SearchIndexablesContract.RawData}.
131b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio     *
13297babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio     * Those are the raw indexable data.
133b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio     *
134b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio     * @param projection list of {@link android.provider.SearchIndexablesContract.RawData} columns
135b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio     *                   to put into the cursor. If {@code null} all supported columns should be
136b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio     *                   included.
137b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio     */
138b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    public abstract Cursor queryRawData(String[] projection);
139b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio
14097babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio    /**
14197babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio     * Returns all {@link android.provider.SearchIndexablesContract.NonIndexableKey}.
14297babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio     *
14397babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio     * Those are the non indexable data keys.
14497babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio     *
14597babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio     * @param projection list of {@link android.provider.SearchIndexablesContract.NonIndexableKey}
14697babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio     *                   columns to put into the cursor. If {@code null} all supported columns
14797babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio     *                   should be included.
14897babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio     */
14997babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio    public abstract Cursor queryNonIndexableKeys(String[] projection);
15097babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio
151b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    @Override
152b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    public String getType(Uri uri) {
153b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio        switch (mMatcher.match(uri)) {
154b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio            case MATCH_RES_CODE:
155b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio                return SearchIndexablesContract.XmlResource.MIME_TYPE;
156b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio            case MATCH_RAW_CODE:
157b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio                return SearchIndexablesContract.RawData.MIME_TYPE;
15897babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio            case MATCH_NON_INDEXABLE_KEYS_CODE:
15997babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio                return SearchIndexablesContract.NonIndexableKey.MIME_TYPE;
160b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio            default:
161b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio                throw new IllegalArgumentException("Unknown URI " + uri);
162b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio        }
163b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    }
164b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio
165b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    /**
16697babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio     * Implementation is provided by the parent class. Throws by default, and cannot be overriden.
167b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio     */
168b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    @Override
169b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    public final Uri insert(Uri uri, ContentValues values) {
170b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio        throw new UnsupportedOperationException("Insert not supported");
171b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    }
172b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio
173b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    /**
17497babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio     * Implementation is provided by the parent class. Throws by default, and cannot be overriden.
175b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio     */
176b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    @Override
177b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    public final int delete(Uri uri, String selection, String[] selectionArgs) {
178b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio        throw new UnsupportedOperationException("Delete not supported");
179b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    }
180b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio
181b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    /**
18297babb1e9a2b859ff01a633edad8e2ac5b02ab8aFabrice Di Meglio     * Implementation is provided by the parent class. Throws by default, and cannot be overriden.
183b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio     */
184b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    @Override
185b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    public final int update(
186b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio            Uri uri, ContentValues values, String selection, String[] selectionArgs) {
187b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio        throw new UnsupportedOperationException("Update not supported");
188b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio    }
189b49995d4d997bf086c2f3214ca410b2a30861b13Fabrice Di Meglio}
190