michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: package org.mozilla.gecko.db; michael@0: michael@0: import java.io.IOException; michael@0: michael@0: import org.json.JSONArray; michael@0: import org.json.JSONException; michael@0: import org.json.JSONObject; michael@0: import org.mozilla.gecko.R; michael@0: import org.mozilla.gecko.db.BrowserContract.HomeItems; michael@0: import org.mozilla.gecko.db.DBUtils; michael@0: import org.mozilla.gecko.sqlite.SQLiteBridge; michael@0: import org.mozilla.gecko.util.RawResource; michael@0: michael@0: import android.content.ContentResolver; michael@0: import android.content.ContentValues; michael@0: import android.content.UriMatcher; michael@0: import android.database.Cursor; michael@0: import android.database.MatrixCursor; michael@0: import android.net.Uri; michael@0: import android.util.Log; michael@0: michael@0: public class HomeProvider extends SQLiteBridgeContentProvider { michael@0: private static final String LOGTAG = "GeckoHomeProvider"; michael@0: michael@0: // This should be kept in sync with the db version in mobile/android/modules/HomeProvider.jsm michael@0: private static int DB_VERSION = 2; michael@0: private static String DB_FILENAME = "home.sqlite"; michael@0: private static final String TELEMETRY_TAG = "SQLITEBRIDGE_PROVIDER_HOME"; michael@0: michael@0: private static final String TABLE_ITEMS = "items"; michael@0: michael@0: // Endpoint to return static fake data. michael@0: static final int ITEMS_FAKE = 100; michael@0: static final int ITEMS = 101; michael@0: static final int ITEMS_ID = 102; michael@0: michael@0: static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH); michael@0: michael@0: static { michael@0: URI_MATCHER.addURI(BrowserContract.HOME_AUTHORITY, "items/fake", ITEMS_FAKE); michael@0: URI_MATCHER.addURI(BrowserContract.HOME_AUTHORITY, "items", ITEMS); michael@0: URI_MATCHER.addURI(BrowserContract.HOME_AUTHORITY, "items/#", ITEMS_ID); michael@0: } michael@0: michael@0: public HomeProvider() { michael@0: super(LOGTAG); michael@0: } michael@0: michael@0: @Override michael@0: public String getType(Uri uri) { michael@0: final int match = URI_MATCHER.match(uri); michael@0: michael@0: switch (match) { michael@0: case ITEMS_FAKE: { michael@0: return HomeItems.CONTENT_TYPE; michael@0: } michael@0: case ITEMS: { michael@0: return HomeItems.CONTENT_TYPE; michael@0: } michael@0: default: { michael@0: throw new UnsupportedOperationException("Unknown type " + uri); michael@0: } michael@0: } michael@0: } michael@0: michael@0: @Override michael@0: public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { michael@0: final int match = URI_MATCHER.match(uri); michael@0: michael@0: // If we're querying the fake items, don't try to get the database. michael@0: if (match == ITEMS_FAKE) { michael@0: return queryFakeItems(uri, projection, selection, selectionArgs, sortOrder); michael@0: } michael@0: michael@0: final String datasetId = uri.getQueryParameter(BrowserContract.PARAM_DATASET_ID); michael@0: if (datasetId == null) { michael@0: throw new IllegalArgumentException("All queries should contain a dataset ID parameter"); michael@0: } michael@0: michael@0: selection = DBUtils.concatenateWhere(selection, HomeItems.DATASET_ID + " = ?"); michael@0: selectionArgs = DBUtils.appendSelectionArgs(selectionArgs, michael@0: new String[] { datasetId }); michael@0: michael@0: // Otherwise, let the SQLiteContentProvider implementation take care of this query for us! michael@0: Cursor c = super.query(uri, projection, selection, selectionArgs, sortOrder); michael@0: michael@0: // SQLiteBridgeContentProvider may return a null Cursor if the database hasn't been created yet. michael@0: // However, we need a non-null cursor in order to listen for notifications. michael@0: if (c == null) { michael@0: c = new MatrixCursor(projection != null ? projection : HomeItems.DEFAULT_PROJECTION); michael@0: } michael@0: michael@0: final ContentResolver cr = getContext().getContentResolver(); michael@0: c.setNotificationUri(cr, getDatasetNotificationUri(datasetId)); michael@0: michael@0: return c; michael@0: } michael@0: michael@0: /** michael@0: * Returns a cursor populated with static fake data. michael@0: */ michael@0: private Cursor queryFakeItems(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { michael@0: JSONArray items = null; michael@0: try { michael@0: final String jsonString = RawResource.getAsString(getContext(), R.raw.fake_home_items); michael@0: items = new JSONArray(jsonString); michael@0: } catch (IOException e) { michael@0: Log.e(LOGTAG, "Error getting fake home items", e); michael@0: return null; michael@0: } catch (JSONException e) { michael@0: Log.e(LOGTAG, "Error parsing fake_home_items.json", e); michael@0: return null; michael@0: } michael@0: michael@0: final MatrixCursor c = new MatrixCursor(HomeItems.DEFAULT_PROJECTION); michael@0: for (int i = 0; i < items.length(); i++) { michael@0: try { michael@0: final JSONObject item = items.getJSONObject(i); michael@0: c.addRow(new Object[] { michael@0: item.getInt("id"), michael@0: item.getString("dataset_id"), michael@0: item.getString("url"), michael@0: item.getString("title"), michael@0: item.getString("description"), michael@0: item.getString("image_url"), michael@0: item.getString("filter") michael@0: }); michael@0: } catch (JSONException e) { michael@0: Log.e(LOGTAG, "Error creating cursor row for fake home item", e); michael@0: } michael@0: } michael@0: return c; michael@0: } michael@0: michael@0: /** michael@0: * SQLiteBridgeContentProvider implementation michael@0: */ michael@0: michael@0: @Override michael@0: protected String getDBName(){ michael@0: return DB_FILENAME; michael@0: } michael@0: michael@0: @Override michael@0: protected String getTelemetryPrefix() { michael@0: return TELEMETRY_TAG; michael@0: } michael@0: michael@0: @Override michael@0: protected int getDBVersion(){ michael@0: return DB_VERSION; michael@0: } michael@0: michael@0: @Override michael@0: public String getTable(Uri uri) { michael@0: final int match = URI_MATCHER.match(uri); michael@0: switch (match) { michael@0: case ITEMS: { michael@0: return TABLE_ITEMS; michael@0: } michael@0: default: { michael@0: throw new UnsupportedOperationException("Unknown table " + uri); michael@0: } michael@0: } michael@0: } michael@0: michael@0: @Override michael@0: public String getSortOrder(Uri uri, String aRequested) { michael@0: return null; michael@0: } michael@0: michael@0: @Override michael@0: public void setupDefaults(Uri uri, ContentValues values) { } michael@0: michael@0: @Override michael@0: public void initGecko() { } michael@0: michael@0: @Override michael@0: public void onPreInsert(ContentValues values, Uri uri, SQLiteBridge db) { } michael@0: michael@0: @Override michael@0: public void onPreUpdate(ContentValues values, Uri uri, SQLiteBridge db) { } michael@0: michael@0: @Override michael@0: public void onPostQuery(Cursor cursor, Uri uri, SQLiteBridge db) { } michael@0: michael@0: public static Uri getDatasetNotificationUri(String datasetId) { michael@0: return Uri.withAppendedPath(HomeItems.CONTENT_URI, datasetId); michael@0: } michael@0: }