| /* | |
| * Copyright 2013 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| package com.example.android.basicsyncadapter.provider; | |
| import android.content.ContentProvider; | |
| import android.content.ContentValues; | |
| import android.content.Context; | |
| import android.content.UriMatcher; | |
| import android.database.Cursor; | |
| import android.database.sqlite.SQLiteDatabase; | |
| import android.database.sqlite.SQLiteOpenHelper; | |
| import android.net.Uri; | |
| import com.example.android.common.db.SelectionBuilder; | |
| public class FeedProvider extends ContentProvider { | |
| FeedDatabase mDatabaseHelper; | |
| /** | |
| * Content authority for this provider. | |
| */ | |
| private static final String AUTHORITY = FeedContract.CONTENT_AUTHORITY; | |
| // The constants below represent individual URI routes, as IDs. Every URI pattern recognized by | |
| // this ContentProvider is defined using sUriMatcher.addURI(), and associated with one of these | |
| // IDs. | |
| // | |
| // When a incoming URI is run through sUriMatcher, it will be tested against the defined | |
| // URI patterns, and the corresponding route ID will be returned. | |
| /** | |
| * URI ID for route: /entries | |
| */ | |
| public static final int ROUTE_ENTRIES = 1; | |
| /** | |
| * URI ID for route: /entries/{ID} | |
| */ | |
| public static final int ROUTE_ENTRIES_ID = 2; | |
| /** | |
| * UriMatcher, used to decode incoming URIs. | |
| */ | |
| private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); | |
| static { | |
| sUriMatcher.addURI(AUTHORITY, "entries", ROUTE_ENTRIES); | |
| sUriMatcher.addURI(AUTHORITY, "entries/*", ROUTE_ENTRIES_ID); | |
| } | |
| @Override | |
| public boolean onCreate() { | |
| mDatabaseHelper = new FeedDatabase(getContext()); | |
| return true; | |
| } | |
| /** | |
| * Determine the mime type for entries returned by a given URI. | |
| */ | |
| @Override | |
| public String getType(Uri uri) { | |
| final int match = sUriMatcher.match(uri); | |
| switch (match) { | |
| case ROUTE_ENTRIES: | |
| return FeedContract.Entry.CONTENT_TYPE; | |
| case ROUTE_ENTRIES_ID: | |
| return FeedContract.Entry.CONTENT_ITEM_TYPE; | |
| default: | |
| throw new UnsupportedOperationException("Unknown uri: " + uri); | |
| } | |
| } | |
| /** | |
| * Perform a database query by URI. | |
| * | |
| * <p>Currently supports returning all entries (/entries) and individual entries by ID | |
| * (/entries/{ID}). | |
| */ | |
| @Override | |
| public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, | |
| String sortOrder) { | |
| SQLiteDatabase db = mDatabaseHelper.getReadableDatabase(); | |
| SelectionBuilder builder = new SelectionBuilder(); | |
| int uriMatch = sUriMatcher.match(uri); | |
| switch (uriMatch) { | |
| case ROUTE_ENTRIES_ID: | |
| // Return a single entry, by ID. | |
| String id = uri.getLastPathSegment(); | |
| builder.where(FeedContract.Entry._ID + "=?", id); | |
| case ROUTE_ENTRIES: | |
| // Return all known entries. | |
| builder.table(FeedContract.Entry.TABLE_NAME) | |
| .where(selection, selectionArgs); | |
| Cursor c = builder.query(db, projection, sortOrder); | |
| // Note: Notification URI must be manually set here for loaders to correctly | |
| // register ContentObservers. | |
| Context ctx = getContext(); | |
| assert ctx != null; | |
| c.setNotificationUri(ctx.getContentResolver(), uri); | |
| return c; | |
| default: | |
| throw new UnsupportedOperationException("Unknown uri: " + uri); | |
| } | |
| } | |
| /** | |
| * Insert a new entry into the database. | |
| */ | |
| @Override | |
| public Uri insert(Uri uri, ContentValues values) { | |
| final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase(); | |
| assert db != null; | |
| final int match = sUriMatcher.match(uri); | |
| Uri result; | |
| switch (match) { | |
| case ROUTE_ENTRIES: | |
| long id = db.insertOrThrow(FeedContract.Entry.TABLE_NAME, null, values); | |
| result = Uri.parse(FeedContract.Entry.CONTENT_URI + "/" + id); | |
| break; | |
| case ROUTE_ENTRIES_ID: | |
| throw new UnsupportedOperationException("Insert not supported on URI: " + uri); | |
| default: | |
| throw new UnsupportedOperationException("Unknown uri: " + uri); | |
| } | |
| // Send broadcast to registered ContentObservers, to refresh UI. | |
| Context ctx = getContext(); | |
| assert ctx != null; | |
| ctx.getContentResolver().notifyChange(uri, null, false); | |
| return result; | |
| } | |
| /** | |
| * Delete an entry by database by URI. | |
| */ | |
| @Override | |
| public int delete(Uri uri, String selection, String[] selectionArgs) { | |
| SelectionBuilder builder = new SelectionBuilder(); | |
| final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase(); | |
| final int match = sUriMatcher.match(uri); | |
| int count; | |
| switch (match) { | |
| case ROUTE_ENTRIES: | |
| count = builder.table(FeedContract.Entry.TABLE_NAME) | |
| .where(selection, selectionArgs) | |
| .delete(db); | |
| break; | |
| case ROUTE_ENTRIES_ID: | |
| String id = uri.getLastPathSegment(); | |
| count = builder.table(FeedContract.Entry.TABLE_NAME) | |
| .where(FeedContract.Entry._ID + "=?", id) | |
| .where(selection, selectionArgs) | |
| .delete(db); | |
| break; | |
| default: | |
| throw new UnsupportedOperationException("Unknown uri: " + uri); | |
| } | |
| // Send broadcast to registered ContentObservers, to refresh UI. | |
| Context ctx = getContext(); | |
| assert ctx != null; | |
| ctx.getContentResolver().notifyChange(uri, null, false); | |
| return count; | |
| } | |
| /** | |
| * Update an etry in the database by URI. | |
| */ | |
| @Override | |
| public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { | |
| SelectionBuilder builder = new SelectionBuilder(); | |
| final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase(); | |
| final int match = sUriMatcher.match(uri); | |
| int count; | |
| switch (match) { | |
| case ROUTE_ENTRIES: | |
| count = builder.table(FeedContract.Entry.TABLE_NAME) | |
| .where(selection, selectionArgs) | |
| .update(db, values); | |
| break; | |
| case ROUTE_ENTRIES_ID: | |
| String id = uri.getLastPathSegment(); | |
| count = builder.table(FeedContract.Entry.TABLE_NAME) | |
| .where(FeedContract.Entry._ID + "=?", id) | |
| .where(selection, selectionArgs) | |
| .update(db, values); | |
| break; | |
| default: | |
| throw new UnsupportedOperationException("Unknown uri: " + uri); | |
| } | |
| Context ctx = getContext(); | |
| assert ctx != null; | |
| ctx.getContentResolver().notifyChange(uri, null, false); | |
| return count; | |
| } | |
| /** | |
| * SQLite backend for @{link FeedProvider}. | |
| * | |
| * Provides access to an disk-backed, SQLite datastore which is utilized by FeedProvider. This | |
| * database should never be accessed by other parts of the application directly. | |
| */ | |
| static class FeedDatabase extends SQLiteOpenHelper { | |
| /** Schema version. */ | |
| public static final int DATABASE_VERSION = 1; | |
| /** Filename for SQLite file. */ | |
| public static final String DATABASE_NAME = "feed.db"; | |
| private static final String TYPE_TEXT = " TEXT"; | |
| private static final String TYPE_INTEGER = " INTEGER"; | |
| private static final String COMMA_SEP = ","; | |
| /** SQL statement to create "entry" table. */ | |
| private static final String SQL_CREATE_ENTRIES = | |
| "CREATE TABLE " + FeedContract.Entry.TABLE_NAME + " (" + | |
| FeedContract.Entry._ID + " INTEGER PRIMARY KEY," + | |
| FeedContract.Entry.COLUMN_NAME_ENTRY_ID + TYPE_TEXT + COMMA_SEP + | |
| FeedContract.Entry.COLUMN_NAME_TITLE + TYPE_TEXT + COMMA_SEP + | |
| FeedContract.Entry.COLUMN_NAME_LINK + TYPE_TEXT + COMMA_SEP + | |
| FeedContract.Entry.COLUMN_NAME_PUBLISHED + TYPE_INTEGER + ")"; | |
| /** SQL statement to drop "entry" table. */ | |
| private static final String SQL_DELETE_ENTRIES = | |
| "DROP TABLE IF EXISTS " + FeedContract.Entry.TABLE_NAME; | |
| public FeedDatabase(Context context) { | |
| super(context, DATABASE_NAME, null, DATABASE_VERSION); | |
| } | |
| @Override | |
| public void onCreate(SQLiteDatabase db) { | |
| db.execSQL(SQL_CREATE_ENTRIES); | |
| } | |
| @Override | |
| public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { | |
| // This database is only a cache for online data, so its upgrade policy is | |
| // to simply to discard the data and start over | |
| db.execSQL(SQL_DELETE_ENTRIES); | |
| onCreate(db); | |
| } | |
| } | |
| } |