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 
17 package com.example.android.searchabledict;
18 
19 import android.app.SearchManager;
20 import android.content.ContentProvider;
21 import android.content.ContentResolver;
22 import android.content.ContentValues;
23 import android.content.UriMatcher;
24 import android.database.Cursor;
25 import android.net.Uri;
26 import android.provider.BaseColumns;
27 
28 /**
29  * Provides access to the dictionary database.
30  */
31 public 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      */
buildUriMatcher()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
onCreate()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
query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)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 
getSuggestions(String query)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 
search(String query)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 
getWord(Uri uri)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 
refreshShortcut(Uri uri)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
getType(Uri uri)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
insert(Uri uri, ContentValues values)189     public Uri insert(Uri uri, ContentValues values) {
190         throw new UnsupportedOperationException();
191     }
192 
193     @Override
delete(Uri uri, String selection, String[] selectionArgs)194     public int delete(Uri uri, String selection, String[] selectionArgs) {
195         throw new UnsupportedOperationException();
196     }
197 
198     @Override
update(Uri uri, ContentValues values, String selection, String[] selectionArgs)199     public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
200         throw new UnsupportedOperationException();
201     }
202 
203 }
204