BasicSyncAdapter / src / com.example.android.basicsyncadapter / provider /

FeedProvider.java

1
/*
2
 * Copyright 2013 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.basicsyncadapter.provider;
18
 
19
import android.content.ContentProvider;
20
import android.content.ContentValues;
21
import android.content.Context;
22
import android.content.UriMatcher;
23
import android.database.Cursor;
24
import android.database.sqlite.SQLiteDatabase;
25
import android.database.sqlite.SQLiteOpenHelper;
26
import android.net.Uri;
27
 
28
import com.example.android.common.db.SelectionBuilder;
29
 
30
public class FeedProvider extends ContentProvider {
31
    FeedDatabase mDatabaseHelper;
32
 
33
    /**
34
     * Content authority for this provider.
35
     */
36
    private static final String AUTHORITY = FeedContract.CONTENT_AUTHORITY;
37
 
38
    // The constants below represent individual URI routes, as IDs. Every URI pattern recognized by
39
    // this ContentProvider is defined using sUriMatcher.addURI(), and associated with one of these
40
    // IDs.
41
    //
42
    // When a incoming URI is run through sUriMatcher, it will be tested against the defined
43
    // URI patterns, and the corresponding route ID will be returned.
44
    /**
45
     * URI ID for route: /entries
46
     */
47
    public static final int ROUTE_ENTRIES = 1;
48
 
49
    /**
50
     * URI ID for route: /entries/{ID}
51
     */
52
    public static final int ROUTE_ENTRIES_ID = 2;
53
 
54
    /**
55
     * UriMatcher, used to decode incoming URIs.
56
     */
57
    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
58
    static {
59
        sUriMatcher.addURI(AUTHORITY, "entries", ROUTE_ENTRIES);
60
        sUriMatcher.addURI(AUTHORITY, "entries/*", ROUTE_ENTRIES_ID);
61
    }
62
 
63
    @Override
64
    public boolean onCreate() {
65
        mDatabaseHelper = new FeedDatabase(getContext());
66
        return true;
67
    }
68
 
69
    /**
70
     * Determine the mime type for entries returned by a given URI.
71
     */
72
    @Override
73
    public String getType(Uri uri) {
74
        final int match = sUriMatcher.match(uri);
75
        switch (match) {
76
            case ROUTE_ENTRIES:
77
                return FeedContract.Entry.CONTENT_TYPE;
78
            case ROUTE_ENTRIES_ID:
79
                return FeedContract.Entry.CONTENT_ITEM_TYPE;
80
            default:
81
                throw new UnsupportedOperationException("Unknown uri: " + uri);
82
        }
83
    }
84
 
85
    /**
86
     * Perform a database query by URI.
87
     *
88
     * <p>Currently supports returning all entries (/entries) and individual entries by ID
89
     * (/entries/{ID}).
90
     */
91
    @Override
92
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
93
                        String sortOrder) {
94
        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
95
        SelectionBuilder builder = new SelectionBuilder();
96
        int uriMatch = sUriMatcher.match(uri);
97
        switch (uriMatch) {
98
            case ROUTE_ENTRIES_ID:
99
                // Return a single entry, by ID.
100
                String id = uri.getLastPathSegment();
101
                builder.where(FeedContract.Entry._ID + "=?", id);
102
            case ROUTE_ENTRIES:
103
                // Return all known entries.
104
                builder.table(FeedContract.Entry.TABLE_NAME)
105
                       .where(selection, selectionArgs);
106
                Cursor c = builder.query(db, projection, sortOrder);
107
                // Note: Notification URI must be manually set here for loaders to correctly
108
                // register ContentObservers.
109
                Context ctx = getContext();
110
                assert ctx != null;
111
                c.setNotificationUri(ctx.getContentResolver(), uri);
112
                return c;
113
            default:
114
                throw new UnsupportedOperationException("Unknown uri: " + uri);
115
        }
116
    }
117
 
118
    /**
119
     * Insert a new entry into the database.
120
     */
121
    @Override
122
    public Uri insert(Uri uri, ContentValues values) {
123
        final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
124
        assert db != null;
125
        final int match = sUriMatcher.match(uri);
126
        Uri result;
127
        switch (match) {
128
            case ROUTE_ENTRIES:
129
                long id = db.insertOrThrow(FeedContract.Entry.TABLE_NAME, null, values);
130
                result = Uri.parse(FeedContract.Entry.CONTENT_URI + "/" + id);
131
                break;
132
            case ROUTE_ENTRIES_ID:
133
                throw new UnsupportedOperationException("Insert not supported on URI: " + uri);
134
            default:
135
                throw new UnsupportedOperationException("Unknown uri: " + uri);
136
        }
137
        // Send broadcast to registered ContentObservers, to refresh UI.
138
        Context ctx = getContext();
139
        assert ctx != null;
140
        ctx.getContentResolver().notifyChange(uri, null, false);
141
        return result;
142
    }
143
 
144
    /**
145
     * Delete an entry by database by URI.
146
     */
147
    @Override
148
    public int delete(Uri uri, String selection, String[] selectionArgs) {
149
        SelectionBuilder builder = new SelectionBuilder();
150
        final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
151
        final int match = sUriMatcher.match(uri);
152
        int count;
153
        switch (match) {
154
            case ROUTE_ENTRIES:
155
                count = builder.table(FeedContract.Entry.TABLE_NAME)
156
                        .where(selection, selectionArgs)
157
                        .delete(db);
158
                break;
159
            case ROUTE_ENTRIES_ID:
160
                String id = uri.getLastPathSegment();
161
                count = builder.table(FeedContract.Entry.TABLE_NAME)
162
                       .where(FeedContract.Entry._ID + "=?", id)
163
                       .where(selection, selectionArgs)
164
                       .delete(db);
165
                break;
166
            default:
167
                throw new UnsupportedOperationException("Unknown uri: " + uri);
168
        }
169
        // Send broadcast to registered ContentObservers, to refresh UI.
170
        Context ctx = getContext();
171
        assert ctx != null;
172
        ctx.getContentResolver().notifyChange(uri, null, false);
173
        return count;
174
    }
175
 
176
    /**
177
     * Update an etry in the database by URI.
178
     */
179
    @Override
180
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
181
        SelectionBuilder builder = new SelectionBuilder();
182
        final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
183
        final int match = sUriMatcher.match(uri);
184
        int count;
185
        switch (match) {
186
            case ROUTE_ENTRIES:
187
                count = builder.table(FeedContract.Entry.TABLE_NAME)
188
                        .where(selection, selectionArgs)
189
                        .update(db, values);
190
                break;
191
            case ROUTE_ENTRIES_ID:
192
                String id = uri.getLastPathSegment();
193
                count = builder.table(FeedContract.Entry.TABLE_NAME)
194
                        .where(FeedContract.Entry._ID + "=?", id)
195
                        .where(selection, selectionArgs)
196
                        .update(db, values);
197
                break;
198
            default:
199
                throw new UnsupportedOperationException("Unknown uri: " + uri);
200
        }
201
        Context ctx = getContext();
202
        assert ctx != null;
203
        ctx.getContentResolver().notifyChange(uri, null, false);
204
        return count;
205
    }
206
 
207
    /**
208
     * SQLite backend for @{link FeedProvider}.
209
     *
210
     * Provides access to an disk-backed, SQLite datastore which is utilized by FeedProvider. This
211
     * database should never be accessed by other parts of the application directly.
212
     */
213
    static class FeedDatabase extends SQLiteOpenHelper {
214
        /** Schema version. */
215
        public static final int DATABASE_VERSION = 1;
216
        /** Filename for SQLite file. */
217
        public static final String DATABASE_NAME = "feed.db";
218
 
219
        private static final String TYPE_TEXT = " TEXT";
220
        private static final String TYPE_INTEGER = " INTEGER";
221
        private static final String COMMA_SEP = ",";
222
        /** SQL statement to create "entry" table. */
223
        private static final String SQL_CREATE_ENTRIES =
224
                "CREATE TABLE " + FeedContract.Entry.TABLE_NAME + " (" +
225
                        FeedContract.Entry._ID + " INTEGER PRIMARY KEY," +
226
                        FeedContract.Entry.COLUMN_NAME_ENTRY_ID + TYPE_TEXT + COMMA_SEP +
227
                        FeedContract.Entry.COLUMN_NAME_TITLE    + TYPE_TEXT + COMMA_SEP +
228
                        FeedContract.Entry.COLUMN_NAME_LINK + TYPE_TEXT + COMMA_SEP +
229
                        FeedContract.Entry.COLUMN_NAME_PUBLISHED + TYPE_INTEGER + ")";
230
 
231
        /** SQL statement to drop "entry" table. */
232
        private static final String SQL_DELETE_ENTRIES =
233
                "DROP TABLE IF EXISTS " + FeedContract.Entry.TABLE_NAME;
234
 
235
        public FeedDatabase(Context context) {
236
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
237
        }
238
 
239
        @Override
240
        public void onCreate(SQLiteDatabase db) {
241
            db.execSQL(SQL_CREATE_ENTRIES);
242
        }
243
 
244
        @Override
245
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
246
            // This database is only a cache for online data, so its upgrade policy is
247
            // to simply to discard the data and start over
248
            db.execSQL(SQL_DELETE_ENTRIES);
249
            onCreate(db);
250
        }
251
    }
252
}