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;
}
}