1 | /* |
2 | * Tomdroid |
3 | * Tomboy on Android |
4 | * http://www.launchpad.net/tomdroid |
5 | * |
6 | * Copyright 2009 Olivier Bilodeau <olivier@bottomlesspit.org> |
7 | * Copyright 2009 Benoit Garret <benoit.garret_launchpad@gadz.org> |
8 | * |
9 | * This file is part of Tomdroid. |
10 | * |
11 | * Tomdroid is free software: you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License as published by |
13 | * the Free Software Foundation, either version 3 of the License, or |
14 | * (at your option) any later version. |
15 | * |
16 | * Tomdroid is distributed in the hope that it will be useful, |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | * GNU General Public License for more details. |
20 | * |
21 | * You should have received a copy of the GNU General Public License |
22 | * along with Tomdroid. If not, see <http://www.gnu.org/licenses/>. |
23 | */ |
24 | /* |
25 | * Parts of this file is Copyright (C) 2007 Google Inc. |
26 | * |
27 | * Licensed under the Apache License, Version 2.0 (the "License"); |
28 | * you may not use this file except in compliance with the License. |
29 | * You may obtain a copy of the License at |
30 | * |
31 | * http://www.apache.org/licenses/LICENSE-2.0 |
32 | * |
33 | * Unless required by applicable law or agreed to in writing, software |
34 | * distributed under the License is distributed on an "AS IS" BASIS, |
35 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
36 | * See the License for the specific language governing permissions and |
37 | * limitations under the License. |
38 | */ |
39 | |
40 | /* |
41 | * This file was inspired by com.example.android.notepad.NotePadProvider |
42 | * available in the Android SDK. |
43 | */ |
44 | package org.tomdroid; |
45 | |
46 | import java.util.HashMap; |
47 | import java.util.UUID; |
48 | |
49 | import org.tomdroid.ui.Tomdroid; |
50 | |
51 | import android.content.ContentProvider; |
52 | import android.content.ContentUris; |
53 | import android.content.ContentValues; |
54 | import android.content.Context; |
55 | import android.content.UriMatcher; |
56 | import android.content.res.Resources; |
57 | import android.database.Cursor; |
58 | import android.database.SQLException; |
59 | import android.database.sqlite.SQLiteDatabase; |
60 | import android.database.sqlite.SQLiteOpenHelper; |
61 | import android.database.sqlite.SQLiteQueryBuilder; |
62 | import android.net.Uri; |
63 | import android.text.TextUtils; |
64 | import android.util.Log; |
65 | |
66 | public class NoteProvider extends ContentProvider { |
67 | |
68 | // ContentProvider stuff |
69 | // -- |
70 | private static final String DATABASE_NAME = "tomdroid-notes.db"; |
71 | private static final String DB_TABLE_NOTES = "notes"; |
72 | private static final int DB_VERSION = 3; |
73 | private static final String DEFAULT_SORT_ORDER = Note.MODIFIED_DATE + " DESC"; |
74 | |
75 | private static HashMap<String, String> notesProjectionMap; |
76 | |
77 | private static final int NOTES = 1; |
78 | private static final int NOTE_ID = 2; |
79 | private static final int NOTE_TITLE = 3; |
80 | |
81 | private static final UriMatcher uriMatcher; |
82 | |
83 | // Logging info |
84 | private static final String TAG = "NoteProvider"; |
85 | |
86 | /** |
87 | * This class helps open, create, and upgrade the database file. |
88 | */ |
89 | private static class DatabaseHelper extends SQLiteOpenHelper { |
90 | |
91 | DatabaseHelper(Context context) { |
92 | super(context, DATABASE_NAME, null, DB_VERSION); |
93 | } |
94 | |
95 | @Override |
96 | public void onCreate(SQLiteDatabase db) { |
97 | db.execSQL("CREATE TABLE " + DB_TABLE_NOTES + " (" |
98 | + Note.ID + " INTEGER PRIMARY KEY," |
99 | + Note.GUID + " TEXT," |
100 | + Note.TITLE + " TEXT," |
101 | + Note.FILE + " TEXT," |
102 | + Note.NOTE_CONTENT + " TEXT," |
103 | + Note.MODIFIED_DATE + " STRING," |
104 | + Note.TAGS + " STRING" |
105 | + ");"); |
106 | } |
107 | |
108 | @Override |
109 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { |
110 | if (Tomdroid.LOGGING_ENABLED) { |
111 | Log.d(TAG, "Upgrading database from version " + oldVersion + " to " |
112 | + newVersion + ", which will destroy all old data"); |
113 | } |
114 | db.execSQL("DROP TABLE IF EXISTS notes"); |
115 | onCreate(db); |
116 | } |
117 | } |
118 | |
119 | private DatabaseHelper dbHelper; |
120 | |
121 | @Override |
122 | public boolean onCreate() { |
123 | dbHelper = new DatabaseHelper(getContext()); |
124 | return true; |
125 | } |
126 | |
127 | @Override |
128 | public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, |
129 | String sortOrder) { |
130 | SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); |
131 | |
132 | switch (uriMatcher.match(uri)) { |
133 | case NOTES: |
134 | qb.setTables(DB_TABLE_NOTES); |
135 | qb.setProjectionMap(notesProjectionMap); |
136 | break; |
137 | |
138 | case NOTE_ID: |
139 | qb.setTables(DB_TABLE_NOTES); |
140 | qb.setProjectionMap(notesProjectionMap); |
141 | qb.appendWhere(Note.ID + "=" + uri.getPathSegments().get(1)); |
142 | break; |
143 | |
144 | case NOTE_TITLE: |
145 | qb.setTables(DB_TABLE_NOTES); |
146 | qb.setProjectionMap(notesProjectionMap); |
147 | // TODO appendWhere + whereArgs instead (new String[] whereArgs = uri.getLas..)? |
148 | qb.appendWhere(Note.TITLE + " LIKE '" + uri.getLastPathSegment()+"'"); |
149 | break; |
150 | |
151 | default: |
152 | throw new IllegalArgumentException("Unknown URI " + uri); |
153 | } |
154 | |
155 | // If no sort order is specified use the default |
156 | String orderBy; |
157 | if (TextUtils.isEmpty(sortOrder)) { |
158 | orderBy = DEFAULT_SORT_ORDER; |
159 | } else { |
160 | orderBy = sortOrder; |
161 | } |
162 | |
163 | |
164 | // Get the database and run the query |
165 | SQLiteDatabase db = dbHelper.getReadableDatabase(); |
166 | Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy); |
167 | |
168 | // Tell the cursor what uri to watch, so it knows when its source data changes |
169 | c.setNotificationUri(getContext().getContentResolver(), uri); |
170 | return c; |
171 | } |
172 | |
173 | @Override |
174 | public String getType(Uri uri) { |
175 | switch (uriMatcher.match(uri)) { |
176 | case NOTES: |
177 | return Tomdroid.CONTENT_TYPE; |
178 | |
179 | case NOTE_ID: |
180 | return Tomdroid.CONTENT_ITEM_TYPE; |
181 | |
182 | case NOTE_TITLE: |
183 | return Tomdroid.CONTENT_ITEM_TYPE; |
184 | |
185 | default: |
186 | throw new IllegalArgumentException("Unknown URI " + uri); |
187 | } |
188 | } |
189 | |
190 | // TODO the following method is probably never called and probably wouldn't work |
191 | @Override |
192 | public Uri insert(Uri uri, ContentValues initialValues) { |
193 | // Validate the requested uri |
194 | if (uriMatcher.match(uri) != NOTES) { |
195 | throw new IllegalArgumentException("Unknown URI " + uri); |
196 | } |
197 | |
198 | ContentValues values; |
199 | if (initialValues != null) { |
200 | values = new ContentValues(initialValues); |
201 | } else { |
202 | values = new ContentValues(); |
203 | } |
204 | |
205 | // TODO either be identical to Tomboy's time format (if sortable) else make sure that this is documented |
206 | Long now = Long.valueOf(System.currentTimeMillis()); |
207 | |
208 | // Make sure that the fields are all set |
209 | if (values.containsKey(Note.MODIFIED_DATE) == false) { |
210 | values.put(Note.MODIFIED_DATE, now); |
211 | } |
212 | |
213 | // The guid is the unique identifier for a note so it has to be set. |
214 | if (values.containsKey(Note.GUID) == false) { |
215 | values.put(Note.GUID, UUID.randomUUID().toString()); |
216 | } |
217 | |
218 | // TODO does this make sense? |
219 | if (values.containsKey(Note.TITLE) == false) { |
220 | Resources r = Resources.getSystem(); |
221 | values.put(Note.TITLE, r.getString(android.R.string.untitled)); |
222 | } |
223 | |
224 | if (values.containsKey(Note.FILE) == false) { |
225 | values.put(Note.FILE, ""); |
226 | } |
227 | |
228 | if (values.containsKey(Note.NOTE_CONTENT) == false) { |
229 | values.put(Note.NOTE_CONTENT, ""); |
230 | } |
231 | |
232 | SQLiteDatabase db = dbHelper.getWritableDatabase(); |
233 | long rowId = db.insert(DB_TABLE_NOTES, Note.FILE, values); // not so sure I did the right thing here |
234 | if (rowId > 0) { |
235 | Uri noteUri = ContentUris.withAppendedId(Tomdroid.CONTENT_URI, rowId); |
236 | getContext().getContentResolver().notifyChange(noteUri, null); |
237 | return noteUri; |
238 | } |
239 | |
240 | throw new SQLException("Failed to insert row into " + uri); |
241 | } |
242 | |
243 | @Override |
244 | public int delete(Uri uri, String where, String[] whereArgs) { |
245 | SQLiteDatabase db = dbHelper.getWritableDatabase(); |
246 | int count; |
247 | switch (uriMatcher.match(uri)) { |
248 | case NOTES: |
249 | count = db.delete(DB_TABLE_NOTES, where, whereArgs); |
250 | break; |
251 | |
252 | case NOTE_ID: |
253 | String noteId = uri.getPathSegments().get(1); |
254 | count = db.delete(DB_TABLE_NOTES, Note.ID + "=" + noteId |
255 | + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs); |
256 | break; |
257 | |
258 | default: |
259 | throw new IllegalArgumentException("Unknown URI " + uri); |
260 | } |
261 | |
262 | getContext().getContentResolver().notifyChange(uri, null); |
263 | return count; |
264 | } |
265 | |
266 | @Override |
267 | public int update(Uri uri, ContentValues values, String where, String[] whereArgs) { |
268 | SQLiteDatabase db = dbHelper.getWritableDatabase(); |
269 | int count; |
270 | switch (uriMatcher.match(uri)) { |
271 | case NOTES: |
272 | count = db.update(DB_TABLE_NOTES, values, where, whereArgs); |
273 | break; |
274 | |
275 | case NOTE_ID: |
276 | String noteId = uri.getPathSegments().get(1); |
277 | count = db.update(DB_TABLE_NOTES, values, Note.ID + "=" + noteId |
278 | + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs); |
279 | break; |
280 | |
281 | default: |
282 | throw new IllegalArgumentException("Unknown URI " + uri); |
283 | } |
284 | |
285 | getContext().getContentResolver().notifyChange(uri, null); |
286 | return count; |
287 | } |
288 | |
289 | static { |
290 | uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); |
291 | uriMatcher.addURI(Tomdroid.AUTHORITY, "notes", NOTES); |
292 | uriMatcher.addURI(Tomdroid.AUTHORITY, "notes/#", NOTE_ID); |
293 | uriMatcher.addURI(Tomdroid.AUTHORITY, "notes/*", NOTE_TITLE); |
294 | |
295 | notesProjectionMap = new HashMap<String, String>(); |
296 | notesProjectionMap.put(Note.ID, Note.ID); |
297 | notesProjectionMap.put(Note.GUID, Note.GUID); |
298 | notesProjectionMap.put(Note.TITLE, Note.TITLE); |
299 | notesProjectionMap.put(Note.FILE, Note.FILE); |
300 | notesProjectionMap.put(Note.NOTE_CONTENT, Note.NOTE_CONTENT); |
301 | notesProjectionMap.put(Note.TAGS, Note.TAGS); |
302 | notesProjectionMap.put(Note.MODIFIED_DATE, Note.MODIFIED_DATE); |
303 | } |
304 | } |