package edu.mit.mobile.android.livingpostcards.data; /* * Copyright (C) 2012-2013 MIT Mobile Experience Lab * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation version 2 * of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; import android.util.Log; import edu.mit.mobile.android.content.ForeignKeyDBHelper; import edu.mit.mobile.android.content.GenericDBHelper; import edu.mit.mobile.android.content.ProviderUtils; import edu.mit.mobile.android.content.QuerystringWrapper; import edu.mit.mobile.android.flipr.BuildConfig; import edu.mit.mobile.android.locast.Constants; import edu.mit.mobile.android.locast.data.JsonSyncableItem; import edu.mit.mobile.android.locast.data.NoPublicPath; import edu.mit.mobile.android.locast.net.NetworkClient; import edu.mit.mobile.android.locast.sync.SyncableSimpleContentProvider; public class CardProvider extends SyncableSimpleContentProvider { public static final String AUTHORITY = "edu.mit.mobile.android.flipr"; public static final int VERSION = 13; protected static final String TAG = CardProvider.class.getSimpleName(); public CardProvider() { super(AUTHORITY, VERSION); final QuerystringWrapper cards = new QuerystringWrapper(new GenericDBHelper(Card.class) { @Override public void upgradeTables(SQLiteDatabase db, int oldVersion, int newVersion) { db.beginTransaction(); if (Constants.DEBUG) { Log.d(TAG, "upgrading " + getTable() + " from " + oldVersion + " to " + newVersion); } try { // we started managing upgrades with version 6 if (oldVersion >= 6) { // NOTE always use string literals here and not constants if (oldVersion == 6) { // adding the web url db.execSQL("ALTER TABLE card ADD COLUMN web_url TEXT"); invalidateLocalCards(db); } if (oldVersion < 8) { db.execSQL("ALTER TABLE card ADD COLUMN deleted BOOLEAN"); } // no changes between 8-9 if (oldVersion < 10) { db.execSQL("ALTER TABLE card ADD COLUMN video_render TEXT"); db.execSQL("ALTER TABLE card ADD COLUMN video_type TEXT"); invalidateLocalCards(db); } if (oldVersion < 11) { db.execSQL("DROP TRIGGER IF EXISTS trigger_card_modified_update"); invalidateLocalCards(db); } if (oldVersion < 12) { db.execSQL("ALTER TABLE card ADD COLUMN dirty BOOLEAN"); } } else { if (Constants.DEBUG) { Log.d(TAG, "upgrading tables by dropping / recreating them"); } // this deletes everything super.upgradeTables(db, oldVersion, newVersion); } db.setTransactionSuccessful(); } finally { db.endTransaction(); } } /** * Cause all the cards to be re-sync'd from the server. * * @param db */ private void invalidateLocalCards(SQLiteDatabase db) { final ContentValues cv = new ContentValues(); // invalidate all cards so they'll get updated. cv.put("modified", 0); cv.put("server_modified", 0); db.update(getTable(), cv, null, null); } }); // unused ATM // final GenericDBHelper users = new GenericDBHelper(User.class); // content://authority/card // content://authority/card/1 addDirAndItemUri(cards, Card.PATH); // addDirAndItemUri(users, User.PATH); final ForeignKeyDBHelper cardmedia = new ForeignKeyDBHelper(Card.class, CardMedia.class, CardMedia.COL_CARD) { @Override public void upgradeTables(SQLiteDatabase db, int oldVersion, int newVersion) { if (Constants.DEBUG) { Log.d(TAG, "upgrading " + getTable() + " from " + oldVersion + " to " + newVersion); } db.beginTransaction(); try { // started managing upgrades at version 6 if (oldVersion >= 6) { // no changes between v6-7 // no changes between v7-8 // forgot to add the deleted column in rev 8 if (oldVersion < 8 || (oldVersion < 9 && !columnExists(db, "cardmedia", "deleted"))) { db.execSQL("ALTER TABLE cardmedia ADD COLUMN deleted BOOLEAN"); } // no changes between 9-10 if (oldVersion < 11) { db.execSQL("DROP TRIGGER IF EXISTS trigger_cardmedia_modified_update"); } if (oldVersion < 12) { db.execSQL("ALTER TABLE cardmedia ADD COLUMN dirty BOOLEAN"); } if (oldVersion < 13) { db.execSQL("ALTER TABLE cardmedia ADD COLUMN media_dirty BOOLEAN DEFAULT (cardmedia.media_url ISNULL)"); if (!columnExists(db, "cardmedia", "caption")) { db.execSQL("ALTER TABLE cardmedia ADD COLUMN caption TEXT"); } } } else { if (Constants.DEBUG) { Log.d(TAG, "upgrading tables by dropping / recreating them"); } // this deletes everything super.upgradeTables(db, oldVersion, newVersion); } db.setTransactionSuccessful(); } finally { db.endTransaction(); } } }; // content://authority/card/1/media // content://authority/card/1/media/1 addChildDirAndItemUri(cardmedia, Card.PATH, CardMedia.PATH); } private boolean tableExists(SQLiteDatabase db, String table) { final Cursor c = db.rawQuery("SELECT COUNT() FROM sqlite_master WHERE name=?", new String[] { table }); boolean tableExists = false; try { final int count = c.getInt(0); tableExists = count == 1; } finally { c.close(); } return tableExists; } private boolean columnExists(SQLiteDatabase db, String table, String column) { final Cursor c = db.query(table, null, null, null, null, null, "_id LIMIT 1"); try { return c.getColumnIndex(column) != -1; } finally { c.close(); } } @Override public boolean canSync(Uri uri) { // TODO Auto-generated method stub if (BuildConfig.DEBUG) { Log.d(TAG, uri + " can sync"); } return true; } @Override public String getPostPath(Context context, Uri uri, NetworkClient nc) throws NoPublicPath { // item post paths are the public path of the dir if (getType(uri).startsWith(ProviderUtils.TYPE_ITEM_PREFIX)) { uri = ProviderUtils.removeLastPathSegment(uri); } return getPublicPath(context, uri, nc); } @Override public String getPublicPath(Context context, Uri uri, NetworkClient nc) throws NoPublicPath { if (BuildConfig.DEBUG) { Log.d(TAG, "getPublicPath " + uri); } final String type = getType(uri); // TODO this is the only hard-coded URL. This should be removed eventually. if (Card.TYPE_DIR.equals(type)) { return nc.getFullUrlAsString("postcard/"); // TODO find a way to make this generic. Inspect the SYNC_MAP somehow? } else if (CardMedia.TYPE_DIR.equals(type)) { if (uri.toString().contains(ForeignKeyDBHelper.WILDCARD_PATH_SEGMENT)) { throw new NoPublicPath("no public path for wildcard " + uri); } return JsonSyncableItem.SyncChildRelation.getPathFromField(context, CardMedia.getCard(uri), Card.COL_MEDIA_URL); } else { return super.getPublicPath(context, uri, nc); } } @Override public String getAuthority() { return AUTHORITY; } }