1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/base/db/ReadingListProvider.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,247 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +package org.mozilla.gecko.db; 1.9 + 1.10 +import org.mozilla.gecko.db.BrowserContract.ReadingListItems; 1.11 +import org.mozilla.gecko.sync.Utils; 1.12 + 1.13 +import android.content.ContentUris; 1.14 +import android.content.ContentValues; 1.15 +import android.content.UriMatcher; 1.16 +import android.database.Cursor; 1.17 +import android.database.sqlite.SQLiteDatabase; 1.18 +import android.database.sqlite.SQLiteQueryBuilder; 1.19 +import android.net.Uri; 1.20 +import android.text.TextUtils; 1.21 + 1.22 +public class ReadingListProvider extends SharedBrowserDatabaseProvider { 1.23 + static final String TABLE_READING_LIST = ReadingListItems.TABLE_NAME; 1.24 + 1.25 + static final int ITEMS = 101; 1.26 + static final int ITEMS_ID = 102; 1.27 + static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH); 1.28 + 1.29 + static { 1.30 + URI_MATCHER.addURI(BrowserContract.READING_LIST_AUTHORITY, "items", ITEMS); 1.31 + URI_MATCHER.addURI(BrowserContract.READING_LIST_AUTHORITY, "items/#", ITEMS_ID); 1.32 + } 1.33 + 1.34 + /** 1.35 + * Updates items that match the selection criteria. If no such items is found 1.36 + * one is inserted with the attributes passed in. Returns 0 if no item updated. 1.37 + * 1.38 + * @return Number of items updated or inserted 1.39 + */ 1.40 + public int updateOrInsertItem(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 1.41 + int updated = updateItems(uri, values, selection, selectionArgs); 1.42 + if (updated <= 0) { 1.43 + updated = insertItem(uri, values) != -1 ? 1 : 0; 1.44 + } 1.45 + return updated; 1.46 + } 1.47 + 1.48 + /** 1.49 + * Updates items that match the selection criteria. 1.50 + * 1.51 + * @return Number of items updated or inserted 1.52 + */ 1.53 + public int updateItems(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 1.54 + trace("Updating ReadingListItems on URI: " + uri); 1.55 + final SQLiteDatabase db = getWritableDatabase(uri); 1.56 + if (!values.containsKey(ReadingListItems.DATE_MODIFIED)) { 1.57 + values.put(ReadingListItems.DATE_MODIFIED, System.currentTimeMillis()); 1.58 + } 1.59 + return db.update(TABLE_READING_LIST, values, selection, selectionArgs); 1.60 + } 1.61 + 1.62 + /** 1.63 + * Inserts a new item into the DB. DATE_CREATED, DATE_MODIFIED 1.64 + * and GUID fields are generated if they are not specified. 1.65 + * 1.66 + * @return ID of the newly inserted item 1.67 + */ 1.68 + long insertItem(Uri uri, ContentValues values) { 1.69 + long now = System.currentTimeMillis(); 1.70 + if (!values.containsKey(ReadingListItems.DATE_CREATED)) { 1.71 + values.put(ReadingListItems.DATE_CREATED, now); 1.72 + } 1.73 + 1.74 + if (!values.containsKey(ReadingListItems.DATE_MODIFIED)) { 1.75 + values.put(ReadingListItems.DATE_MODIFIED, now); 1.76 + } 1.77 + 1.78 + if (!values.containsKey(ReadingListItems.GUID)) { 1.79 + values.put(ReadingListItems.GUID, Utils.generateGuid()); 1.80 + } 1.81 + 1.82 + String url = values.getAsString(ReadingListItems.URL); 1.83 + debug("Inserting item in database with URL: " + url); 1.84 + return getWritableDatabase(uri) 1.85 + .insertOrThrow(TABLE_READING_LIST, null, values); 1.86 + } 1.87 + 1.88 + /** 1.89 + * Deletes items. Item is marked as 'deleted' so that sync can 1.90 + * detect the change. 1.91 + * 1.92 + * @return Number of deleted items 1.93 + */ 1.94 + int deleteItems(Uri uri, String selection, String[] selectionArgs) { 1.95 + debug("Deleting item entry for URI: " + uri); 1.96 + final SQLiteDatabase db = getWritableDatabase(uri); 1.97 + 1.98 + if (isCallerSync(uri)) { 1.99 + return db.delete(TABLE_READING_LIST, selection, selectionArgs); 1.100 + } 1.101 + 1.102 + debug("Marking item entry as deleted for URI: " + uri); 1.103 + ContentValues values = new ContentValues(); 1.104 + values.put(ReadingListItems.IS_DELETED, 1); 1.105 + 1.106 + cleanUpSomeDeletedRecords(uri, TABLE_READING_LIST); 1.107 + return updateItems(uri, values, selection, selectionArgs); 1.108 + } 1.109 + 1.110 + @Override 1.111 + @SuppressWarnings("fallthrough") 1.112 + public int updateInTransaction(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 1.113 + trace("Calling update in transaction on URI: " + uri); 1.114 + 1.115 + int updated = 0; 1.116 + int match = URI_MATCHER.match(uri); 1.117 + 1.118 + switch (match) { 1.119 + case ITEMS_ID: 1.120 + debug("Update on ITEMS_ID: " + uri); 1.121 + selection = DBUtils.concatenateWhere(selection, TABLE_READING_LIST + "._id = ?"); 1.122 + selectionArgs = DBUtils.appendSelectionArgs(selectionArgs, 1.123 + new String[] { Long.toString(ContentUris.parseId(uri)) }); 1.124 + 1.125 + case ITEMS: { 1.126 + debug("Updating ITEMS: " + uri); 1.127 + updated = shouldUpdateOrInsert(uri) ? 1.128 + updateOrInsertItem(uri, values, selection, selectionArgs) : 1.129 + updateItems(uri, values, selection, selectionArgs); 1.130 + break; 1.131 + } 1.132 + 1.133 + default: 1.134 + throw new UnsupportedOperationException("Unknown update URI " + uri); 1.135 + } 1.136 + 1.137 + debug("Updated " + updated + " rows for URI: " + uri); 1.138 + return updated; 1.139 + } 1.140 + 1.141 + 1.142 + @Override 1.143 + @SuppressWarnings("fallthrough") 1.144 + public int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) { 1.145 + trace("Calling delete in transaction on URI: " + uri); 1.146 + 1.147 + int numDeleted = 0; 1.148 + int match = URI_MATCHER.match(uri); 1.149 + 1.150 + switch (match) { 1.151 + case ITEMS_ID: 1.152 + debug("Deleting on ITEMS_ID: " + uri); 1.153 + selection = DBUtils.concatenateWhere(selection, TABLE_READING_LIST + "._id = ?"); 1.154 + selectionArgs = DBUtils.appendSelectionArgs(selectionArgs, 1.155 + new String[] { Long.toString(ContentUris.parseId(uri)) }); 1.156 + 1.157 + case ITEMS: 1.158 + debug("Deleting ITEMS: " + uri); 1.159 + numDeleted = deleteItems(uri, selection, selectionArgs); 1.160 + break; 1.161 + 1.162 + default: 1.163 + throw new UnsupportedOperationException("Unknown update URI " + uri); 1.164 + } 1.165 + 1.166 + debug("Deleted " + numDeleted + " rows for URI: " + uri); 1.167 + return numDeleted; 1.168 + } 1.169 + 1.170 + @Override 1.171 + public Uri insertInTransaction(Uri uri, ContentValues values) { 1.172 + trace("Calling insert in transaction on URI: " + uri); 1.173 + long id = -1; 1.174 + int match = URI_MATCHER.match(uri); 1.175 + 1.176 + switch (match) { 1.177 + case ITEMS: 1.178 + trace("Insert on ITEMS: " + uri); 1.179 + id = insertItem(uri, values); 1.180 + break; 1.181 + 1.182 + default: 1.183 + throw new UnsupportedOperationException("Unknown insert URI " + uri); 1.184 + } 1.185 + 1.186 + debug("Inserted ID in database: " + id); 1.187 + 1.188 + if (id >= 0) { 1.189 + return ContentUris.withAppendedId(uri, id); 1.190 + } 1.191 + 1.192 + return null; 1.193 + } 1.194 + 1.195 + @Override 1.196 + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { 1.197 + String groupBy = null; 1.198 + SQLiteDatabase db = getReadableDatabase(uri); 1.199 + SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 1.200 + String limit = uri.getQueryParameter(BrowserContract.PARAM_LIMIT); 1.201 + 1.202 + final int match = URI_MATCHER.match(uri); 1.203 + switch (match) { 1.204 + case ITEMS_ID: 1.205 + trace("Query on ITEMS_ID: " + uri); 1.206 + selection = DBUtils.concatenateWhere(selection, ReadingListItems._ID + " = ?"); 1.207 + selectionArgs = DBUtils.appendSelectionArgs(selectionArgs, 1.208 + new String[] { Long.toString(ContentUris.parseId(uri)) }); 1.209 + 1.210 + case ITEMS: 1.211 + trace("Query on ITEMS: " + uri); 1.212 + if (!shouldShowDeleted(uri)) 1.213 + selection = DBUtils.concatenateWhere(ReadingListItems.IS_DELETED + " = 0", selection); 1.214 + break; 1.215 + 1.216 + default: 1.217 + throw new UnsupportedOperationException("Unknown query URI " + uri); 1.218 + } 1.219 + 1.220 + if (TextUtils.isEmpty(sortOrder)) { 1.221 + sortOrder = ReadingListItems.DEFAULT_SORT_ORDER; 1.222 + } 1.223 + 1.224 + trace("Running built query."); 1.225 + qb.setTables(TABLE_READING_LIST); 1.226 + Cursor cursor = qb.query(db, projection, selection, selectionArgs, groupBy, null, sortOrder, limit); 1.227 + cursor.setNotificationUri(getContext().getContentResolver(), uri); 1.228 + 1.229 + return cursor; 1.230 + } 1.231 + 1.232 + @Override 1.233 + public String getType(Uri uri) { 1.234 + trace("Getting URI type: " + uri); 1.235 + 1.236 + final int match = URI_MATCHER.match(uri); 1.237 + switch (match) { 1.238 + case ITEMS: 1.239 + trace("URI is ITEMS: " + uri); 1.240 + return ReadingListItems.CONTENT_TYPE; 1.241 + 1.242 + case ITEMS_ID: 1.243 + trace("URI is ITEMS_ID: " + uri); 1.244 + return ReadingListItems.CONTENT_ITEM_TYPE; 1.245 + } 1.246 + 1.247 + debug("URI has unrecognized type: " + uri); 1.248 + return null; 1.249 + } 1.250 +}