|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 package org.mozilla.gecko.db; |
|
6 |
|
7 import org.mozilla.gecko.db.BrowserContract.ReadingListItems; |
|
8 import org.mozilla.gecko.sync.Utils; |
|
9 |
|
10 import android.content.ContentUris; |
|
11 import android.content.ContentValues; |
|
12 import android.content.UriMatcher; |
|
13 import android.database.Cursor; |
|
14 import android.database.sqlite.SQLiteDatabase; |
|
15 import android.database.sqlite.SQLiteQueryBuilder; |
|
16 import android.net.Uri; |
|
17 import android.text.TextUtils; |
|
18 |
|
19 public class ReadingListProvider extends SharedBrowserDatabaseProvider { |
|
20 static final String TABLE_READING_LIST = ReadingListItems.TABLE_NAME; |
|
21 |
|
22 static final int ITEMS = 101; |
|
23 static final int ITEMS_ID = 102; |
|
24 static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH); |
|
25 |
|
26 static { |
|
27 URI_MATCHER.addURI(BrowserContract.READING_LIST_AUTHORITY, "items", ITEMS); |
|
28 URI_MATCHER.addURI(BrowserContract.READING_LIST_AUTHORITY, "items/#", ITEMS_ID); |
|
29 } |
|
30 |
|
31 /** |
|
32 * Updates items that match the selection criteria. If no such items is found |
|
33 * one is inserted with the attributes passed in. Returns 0 if no item updated. |
|
34 * |
|
35 * @return Number of items updated or inserted |
|
36 */ |
|
37 public int updateOrInsertItem(Uri uri, ContentValues values, String selection, String[] selectionArgs) { |
|
38 int updated = updateItems(uri, values, selection, selectionArgs); |
|
39 if (updated <= 0) { |
|
40 updated = insertItem(uri, values) != -1 ? 1 : 0; |
|
41 } |
|
42 return updated; |
|
43 } |
|
44 |
|
45 /** |
|
46 * Updates items that match the selection criteria. |
|
47 * |
|
48 * @return Number of items updated or inserted |
|
49 */ |
|
50 public int updateItems(Uri uri, ContentValues values, String selection, String[] selectionArgs) { |
|
51 trace("Updating ReadingListItems on URI: " + uri); |
|
52 final SQLiteDatabase db = getWritableDatabase(uri); |
|
53 if (!values.containsKey(ReadingListItems.DATE_MODIFIED)) { |
|
54 values.put(ReadingListItems.DATE_MODIFIED, System.currentTimeMillis()); |
|
55 } |
|
56 return db.update(TABLE_READING_LIST, values, selection, selectionArgs); |
|
57 } |
|
58 |
|
59 /** |
|
60 * Inserts a new item into the DB. DATE_CREATED, DATE_MODIFIED |
|
61 * and GUID fields are generated if they are not specified. |
|
62 * |
|
63 * @return ID of the newly inserted item |
|
64 */ |
|
65 long insertItem(Uri uri, ContentValues values) { |
|
66 long now = System.currentTimeMillis(); |
|
67 if (!values.containsKey(ReadingListItems.DATE_CREATED)) { |
|
68 values.put(ReadingListItems.DATE_CREATED, now); |
|
69 } |
|
70 |
|
71 if (!values.containsKey(ReadingListItems.DATE_MODIFIED)) { |
|
72 values.put(ReadingListItems.DATE_MODIFIED, now); |
|
73 } |
|
74 |
|
75 if (!values.containsKey(ReadingListItems.GUID)) { |
|
76 values.put(ReadingListItems.GUID, Utils.generateGuid()); |
|
77 } |
|
78 |
|
79 String url = values.getAsString(ReadingListItems.URL); |
|
80 debug("Inserting item in database with URL: " + url); |
|
81 return getWritableDatabase(uri) |
|
82 .insertOrThrow(TABLE_READING_LIST, null, values); |
|
83 } |
|
84 |
|
85 /** |
|
86 * Deletes items. Item is marked as 'deleted' so that sync can |
|
87 * detect the change. |
|
88 * |
|
89 * @return Number of deleted items |
|
90 */ |
|
91 int deleteItems(Uri uri, String selection, String[] selectionArgs) { |
|
92 debug("Deleting item entry for URI: " + uri); |
|
93 final SQLiteDatabase db = getWritableDatabase(uri); |
|
94 |
|
95 if (isCallerSync(uri)) { |
|
96 return db.delete(TABLE_READING_LIST, selection, selectionArgs); |
|
97 } |
|
98 |
|
99 debug("Marking item entry as deleted for URI: " + uri); |
|
100 ContentValues values = new ContentValues(); |
|
101 values.put(ReadingListItems.IS_DELETED, 1); |
|
102 |
|
103 cleanUpSomeDeletedRecords(uri, TABLE_READING_LIST); |
|
104 return updateItems(uri, values, selection, selectionArgs); |
|
105 } |
|
106 |
|
107 @Override |
|
108 @SuppressWarnings("fallthrough") |
|
109 public int updateInTransaction(Uri uri, ContentValues values, String selection, String[] selectionArgs) { |
|
110 trace("Calling update in transaction on URI: " + uri); |
|
111 |
|
112 int updated = 0; |
|
113 int match = URI_MATCHER.match(uri); |
|
114 |
|
115 switch (match) { |
|
116 case ITEMS_ID: |
|
117 debug("Update on ITEMS_ID: " + uri); |
|
118 selection = DBUtils.concatenateWhere(selection, TABLE_READING_LIST + "._id = ?"); |
|
119 selectionArgs = DBUtils.appendSelectionArgs(selectionArgs, |
|
120 new String[] { Long.toString(ContentUris.parseId(uri)) }); |
|
121 |
|
122 case ITEMS: { |
|
123 debug("Updating ITEMS: " + uri); |
|
124 updated = shouldUpdateOrInsert(uri) ? |
|
125 updateOrInsertItem(uri, values, selection, selectionArgs) : |
|
126 updateItems(uri, values, selection, selectionArgs); |
|
127 break; |
|
128 } |
|
129 |
|
130 default: |
|
131 throw new UnsupportedOperationException("Unknown update URI " + uri); |
|
132 } |
|
133 |
|
134 debug("Updated " + updated + " rows for URI: " + uri); |
|
135 return updated; |
|
136 } |
|
137 |
|
138 |
|
139 @Override |
|
140 @SuppressWarnings("fallthrough") |
|
141 public int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) { |
|
142 trace("Calling delete in transaction on URI: " + uri); |
|
143 |
|
144 int numDeleted = 0; |
|
145 int match = URI_MATCHER.match(uri); |
|
146 |
|
147 switch (match) { |
|
148 case ITEMS_ID: |
|
149 debug("Deleting on ITEMS_ID: " + uri); |
|
150 selection = DBUtils.concatenateWhere(selection, TABLE_READING_LIST + "._id = ?"); |
|
151 selectionArgs = DBUtils.appendSelectionArgs(selectionArgs, |
|
152 new String[] { Long.toString(ContentUris.parseId(uri)) }); |
|
153 |
|
154 case ITEMS: |
|
155 debug("Deleting ITEMS: " + uri); |
|
156 numDeleted = deleteItems(uri, selection, selectionArgs); |
|
157 break; |
|
158 |
|
159 default: |
|
160 throw new UnsupportedOperationException("Unknown update URI " + uri); |
|
161 } |
|
162 |
|
163 debug("Deleted " + numDeleted + " rows for URI: " + uri); |
|
164 return numDeleted; |
|
165 } |
|
166 |
|
167 @Override |
|
168 public Uri insertInTransaction(Uri uri, ContentValues values) { |
|
169 trace("Calling insert in transaction on URI: " + uri); |
|
170 long id = -1; |
|
171 int match = URI_MATCHER.match(uri); |
|
172 |
|
173 switch (match) { |
|
174 case ITEMS: |
|
175 trace("Insert on ITEMS: " + uri); |
|
176 id = insertItem(uri, values); |
|
177 break; |
|
178 |
|
179 default: |
|
180 throw new UnsupportedOperationException("Unknown insert URI " + uri); |
|
181 } |
|
182 |
|
183 debug("Inserted ID in database: " + id); |
|
184 |
|
185 if (id >= 0) { |
|
186 return ContentUris.withAppendedId(uri, id); |
|
187 } |
|
188 |
|
189 return null; |
|
190 } |
|
191 |
|
192 @Override |
|
193 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { |
|
194 String groupBy = null; |
|
195 SQLiteDatabase db = getReadableDatabase(uri); |
|
196 SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); |
|
197 String limit = uri.getQueryParameter(BrowserContract.PARAM_LIMIT); |
|
198 |
|
199 final int match = URI_MATCHER.match(uri); |
|
200 switch (match) { |
|
201 case ITEMS_ID: |
|
202 trace("Query on ITEMS_ID: " + uri); |
|
203 selection = DBUtils.concatenateWhere(selection, ReadingListItems._ID + " = ?"); |
|
204 selectionArgs = DBUtils.appendSelectionArgs(selectionArgs, |
|
205 new String[] { Long.toString(ContentUris.parseId(uri)) }); |
|
206 |
|
207 case ITEMS: |
|
208 trace("Query on ITEMS: " + uri); |
|
209 if (!shouldShowDeleted(uri)) |
|
210 selection = DBUtils.concatenateWhere(ReadingListItems.IS_DELETED + " = 0", selection); |
|
211 break; |
|
212 |
|
213 default: |
|
214 throw new UnsupportedOperationException("Unknown query URI " + uri); |
|
215 } |
|
216 |
|
217 if (TextUtils.isEmpty(sortOrder)) { |
|
218 sortOrder = ReadingListItems.DEFAULT_SORT_ORDER; |
|
219 } |
|
220 |
|
221 trace("Running built query."); |
|
222 qb.setTables(TABLE_READING_LIST); |
|
223 Cursor cursor = qb.query(db, projection, selection, selectionArgs, groupBy, null, sortOrder, limit); |
|
224 cursor.setNotificationUri(getContext().getContentResolver(), uri); |
|
225 |
|
226 return cursor; |
|
227 } |
|
228 |
|
229 @Override |
|
230 public String getType(Uri uri) { |
|
231 trace("Getting URI type: " + uri); |
|
232 |
|
233 final int match = URI_MATCHER.match(uri); |
|
234 switch (match) { |
|
235 case ITEMS: |
|
236 trace("URI is ITEMS: " + uri); |
|
237 return ReadingListItems.CONTENT_TYPE; |
|
238 |
|
239 case ITEMS_ID: |
|
240 trace("URI is ITEMS_ID: " + uri); |
|
241 return ReadingListItems.CONTENT_ITEM_TYPE; |
|
242 } |
|
243 |
|
244 debug("URI has unrecognized type: " + uri); |
|
245 return null; |
|
246 } |
|
247 } |