1/*
2 * Copyright (C) 2010 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
17package com.example.android.searchabledict;
18
19import android.app.SearchManager;
20import android.content.ContentProvider;
21import android.content.ContentResolver;
22import android.content.ContentValues;
23import android.content.UriMatcher;
24import android.database.Cursor;
25import android.net.Uri;
26import android.provider.BaseColumns;
27
28/**
29 * Provides access to the dictionary database.
30 */
31public class DictionaryProvider extends ContentProvider {
32    String TAG = "DictionaryProvider";
33
34    public static String AUTHORITY = "com.example.android.searchabledict.DictionaryProvider";
35    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/dictionary");
36
37    // MIME types used for searching words or looking up a single definition
38    public static final String WORDS_MIME_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE +
39                                                  "/vnd.example.android.searchabledict";
40    public static final String DEFINITION_MIME_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE +
41                                                       "/vnd.example.android.searchabledict";
42
43    private DictionaryDatabase mDictionary;
44
45    // UriMatcher stuff
46    private static final int SEARCH_WORDS = 0;
47    private static final int GET_WORD = 1;
48    private static final int SEARCH_SUGGEST = 2;
49    private static final int REFRESH_SHORTCUT = 3;
50    private static final UriMatcher sURIMatcher = buildUriMatcher();
51
52    /**
53     * Builds up a UriMatcher for search suggestion and shortcut refresh queries.
54     */
55    private static UriMatcher buildUriMatcher() {
56        UriMatcher matcher =  new UriMatcher(UriMatcher.NO_MATCH);
57        // to get definitions...
58        matcher.addURI(AUTHORITY, "dictionary", SEARCH_WORDS);
59        matcher.addURI(AUTHORITY, "dictionary/#", GET_WORD);
60        // to get suggestions...
61        matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, SEARCH_SUGGEST);
62        matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", SEARCH_SUGGEST);
63
64        /* The following are unused in this implementation, but if we include
65         * {@link SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} as a column in our suggestions table, we
66         * could expect to receive refresh queries when a shortcutted suggestion is displayed in
67         * Quick Search Box, in which case, the following Uris would be provided and we
68         * would return a cursor with a single item representing the refreshed suggestion data.
69         */
70        matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT, REFRESH_SHORTCUT);
71        matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*", REFRESH_SHORTCUT);
72        return matcher;
73    }
74
75    @Override
76    public boolean onCreate() {
77        mDictionary = new DictionaryDatabase(getContext());
78        return true;
79    }
80
81    /**
82     * Handles all the dictionary searches and suggestion queries from the Search Manager.
83     * When requesting a specific word, the uri alone is required.
84     * When searching all of the dictionary for matches, the selectionArgs argument must carry
85     * the search query as the first element.
86     * All other arguments are ignored.
87     */
88    @Override
89    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
90                        String sortOrder) {
91
92        // Use the UriMatcher to see what kind of query we have and format the db query accordingly
93        switch (sURIMatcher.match(uri)) {
94            case SEARCH_SUGGEST:
95                if (selectionArgs == null) {
96                  throw new IllegalArgumentException(
97                      "selectionArgs must be provided for the Uri: " + uri);
98                }
99                return getSuggestions(selectionArgs[0]);
100            case SEARCH_WORDS:
101                if (selectionArgs == null) {
102                  throw new IllegalArgumentException(
103                      "selectionArgs must be provided for the Uri: " + uri);
104                }
105                return search(selectionArgs[0]);
106            case GET_WORD:
107                return getWord(uri);
108            case REFRESH_SHORTCUT:
109                return refreshShortcut(uri);
110            default:
111                throw new IllegalArgumentException("Unknown Uri: " + uri);
112        }
113    }
114
115    private Cursor getSuggestions(String query) {
116      query = query.toLowerCase();
117      String[] columns = new String[] {
118          BaseColumns._ID,
119          DictionaryDatabase.KEY_WORD,
120          DictionaryDatabase.KEY_DEFINITION,
121       /* SearchManager.SUGGEST_COLUMN_SHORTCUT_ID,
122                        (only if you want to refresh shortcuts) */
123          SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID};
124
125      return mDictionary.getWordMatches(query, columns);
126    }
127
128    private Cursor search(String query) {
129      query = query.toLowerCase();
130      String[] columns = new String[] {
131          BaseColumns._ID,
132          DictionaryDatabase.KEY_WORD,
133          DictionaryDatabase.KEY_DEFINITION};
134
135      return mDictionary.getWordMatches(query, columns);
136    }
137
138    private Cursor getWord(Uri uri) {
139      String rowId = uri.getLastPathSegment();
140      String[] columns = new String[] {
141          DictionaryDatabase.KEY_WORD,
142          DictionaryDatabase.KEY_DEFINITION};
143
144      return mDictionary.getWord(rowId, columns);
145    }
146
147    private Cursor refreshShortcut(Uri uri) {
148      /* This won't be called with the current implementation, but if we include
149       * {@link SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} as a column in our suggestions table, we
150       * could expect to receive refresh queries when a shortcutted suggestion is displayed in
151       * Quick Search Box. In which case, this method will query the table for the specific
152       * word, using the given item Uri and provide all the columns originally provided with the
153       * suggestion query.
154       */
155      String rowId = uri.getLastPathSegment();
156      String[] columns = new String[] {
157          BaseColumns._ID,
158          DictionaryDatabase.KEY_WORD,
159          DictionaryDatabase.KEY_DEFINITION,
160          SearchManager.SUGGEST_COLUMN_SHORTCUT_ID,
161          SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID};
162
163      return mDictionary.getWord(rowId, columns);
164    }
165
166    /**
167     * This method is required in order to query the supported types.
168     * It's also useful in our own query() method to determine the type of Uri received.
169     */
170    @Override
171    public String getType(Uri uri) {
172        switch (sURIMatcher.match(uri)) {
173            case SEARCH_WORDS:
174                return WORDS_MIME_TYPE;
175            case GET_WORD:
176                return DEFINITION_MIME_TYPE;
177            case SEARCH_SUGGEST:
178                return SearchManager.SUGGEST_MIME_TYPE;
179            case REFRESH_SHORTCUT:
180                return SearchManager.SHORTCUT_MIME_TYPE;
181            default:
182                throw new IllegalArgumentException("Unknown URL " + uri);
183        }
184    }
185
186    // Other required implementations...
187
188    @Override
189    public Uri insert(Uri uri, ContentValues values) {
190        throw new UnsupportedOperationException();
191    }
192
193    @Override
194    public int delete(Uri uri, String selection, String[] selectionArgs) {
195        throw new UnsupportedOperationException();
196    }
197
198    @Override
199    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
200        throw new UnsupportedOperationException();
201    }
202
203}
204