package com.github.andlyticsproject.db; import java.util.ArrayList; import java.util.Date; import java.util.List; import android.accounts.Account; import android.accounts.AccountManager; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; import com.github.andlyticsproject.Preferences; import com.github.andlyticsproject.model.AppDetails; import com.github.andlyticsproject.model.AppInfo; import com.github.andlyticsproject.model.DeveloperAccount; import com.github.andlyticsproject.model.Link; import com.github.andlyticsproject.model.Revenue; import com.github.andlyticsproject.model.RevenueSummary; import com.github.andlyticsproject.sync.AutosyncHandler; import com.github.andlyticsproject.util.Utils; public class AndlyticsDb extends SQLiteOpenHelper { private static final String TAG = AndlyticsDb.class.getSimpleName(); private static final int DATABASE_VERSION = 24; private static final String DATABASE_NAME = "andlytics"; private static AndlyticsDb instance; private Context context; public static synchronized AndlyticsDb getInstance(Context context) { if (instance == null) { instance = new AndlyticsDb(context); } return instance; } private AndlyticsDb(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); this.context = context; } @Override public void onCreate(SQLiteDatabase db) { Log.d(TAG, "Creating databse"); db.execSQL(AppInfoTable.TABLE_CREATE_APPINFO); db.execSQL(AppStatsTable.TABLE_CREATE_STATS); db.execSQL(CommentsTable.TABLE_CREATE_COMMENTS); db.execSQL(AdmobTable.TABLE_CREATE_ADMOB); db.execSQL(DeveloperAccountsTable.TABLE_CREATE_DEVELOPER_ACCOUNT); db.execSQL(LinksTable.TABLE_CREATE_LINKS); db.execSQL(AppDetailsTable.TABLE_CREATE_APP_DETAILS); db.execSQL(RevenueSummaryTable.TABLE_CREATE_REVENUE_SUMMARY); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion + "."); if (oldVersion < 9) { Log.w(TAG, "Old version < 9 - drop all tables & recreate"); db.execSQL("DROP TABLE IF EXISTS " + AppInfoTable.DATABASE_TABLE_NAME); db.execSQL("DROP TABLE IF EXISTS " + AppStatsTable.DATABASE_TABLE_NAME); db.execSQL(AppInfoTable.TABLE_CREATE_APPINFO); db.execSQL(AppStatsTable.TABLE_CREATE_STATS); } if (oldVersion == 9) { Log.w(TAG, "Old version = 9 - add ghost column"); db.execSQL("ALTER table " + AppInfoTable.DATABASE_TABLE_NAME + " add " + AppInfoTable.KEY_APP_GHOST + " integer"); } if (oldVersion > 8 && oldVersion < 11) { Log.w(TAG, "Old version = 10 or 9 - add rating expand column"); db.execSQL("ALTER table " + AppInfoTable.DATABASE_TABLE_NAME + " add " + AppInfoTable.KEY_APP_RATINGS_EXPANDED + " integer"); } if (oldVersion < 12) { Log.w(TAG, "Old version < 12 - add comments table"); db.execSQL(CommentsTable.TABLE_CREATE_COMMENTS); } if (oldVersion < 13) { Log.w(TAG, "Old version < 13 - add skip notification"); db.execSQL("ALTER table " + AppInfoTable.DATABASE_TABLE_NAME + " add " + AppInfoTable.KEY_APP_SKIP_NOTIFICATION + " integer"); } if (oldVersion < 14) { Log.w(TAG, "Old version < 14 - add admob table"); db.execSQL(AdmobTable.TABLE_CREATE_ADMOB); } if (oldVersion < 15) { Log.w(TAG, "Old version < 15 - add version name"); db.execSQL("ALTER table " + AppInfoTable.DATABASE_TABLE_NAME + " add " + AppInfoTable.KEY_APP_VERSION_NAME + " text"); } if (oldVersion < 16) { Log.w(TAG, "Old version < 16 - add new comments colums"); db.execSQL("ALTER table " + CommentsTable.DATABASE_TABLE_NAME + " add " + CommentsTable.KEY_COMMENT_APP_VERSION + " text"); db.execSQL("ALTER table " + CommentsTable.DATABASE_TABLE_NAME + " add " + CommentsTable.KEY_COMMENT_DEVICE + " text"); } if (oldVersion < 17) { Log.w(TAG, "Old version < 17 - changing comments date format"); db.execSQL("DROP TABLE IF EXISTS " + CommentsTable.DATABASE_TABLE_NAME); db.execSQL(CommentsTable.TABLE_CREATE_COMMENTS); } if (oldVersion < 18) { Log.w(TAG, "Old version < 18 - adding replies to comments"); db.execSQL("DROP TABLE IF EXISTS " + CommentsTable.DATABASE_TABLE_NAME); db.execSQL(CommentsTable.TABLE_CREATE_COMMENTS); } if (oldVersion < 19) { Log.w(TAG, "Old version < 19 - adding developer_accounts table"); db.execSQL("DROP TABLE IF EXISTS " + DeveloperAccountsTable.DATABASE_TABLE_NAME); db.execSQL(DeveloperAccountsTable.TABLE_CREATE_DEVELOPER_ACCOUNT); migrateAccountsFromPrefs(db); Log.d(TAG, "Old version < 19 - adding new appinfo columns"); db.execSQL("ALTER table " + AppInfoTable.DATABASE_TABLE_NAME + " add " + AppInfoTable.KEY_APP_ADMOB_ACCOUNT + " text"); db.execSQL("ALTER table " + AppInfoTable.DATABASE_TABLE_NAME + " add " + AppInfoTable.KEY_APP_ADMOB_SITE_ID + " text"); db.execSQL("ALTER table " + AppInfoTable.DATABASE_TABLE_NAME + " add " + AppInfoTable.KEY_APP_LAST_COMMENTS_UPDATE + " date"); migrateAppInfoPrefs(db); Log.d(TAG, "Old version < 19 - adding new appstats columns"); db.execSQL("ALTER table " + AppStatsTable.DATABASE_TABLE_NAME + " add " + AppStatsTable.KEY_STATS_NUM_ERRORS + " integer"); } if (oldVersion < 20) { Log.w(TAG, "Old version < 20 - add new comments colums"); db.execSQL("ALTER table " + CommentsTable.DATABASE_TABLE_NAME + " add " + CommentsTable.KEY_COMMENT_LANGUAGE + " text"); db.execSQL("ALTER table " + CommentsTable.DATABASE_TABLE_NAME + " add " + CommentsTable.KEY_COMMENT_ORIGINAL_TEXT + " text"); db.execSQL("ALTER table " + CommentsTable.DATABASE_TABLE_NAME + " add " + CommentsTable.KEY_COMMENT_UNIQUE_ID + " text"); Log.w(TAG, "Old version < 20 - adding links table"); db.execSQL("DROP TABLE IF EXISTS " + LinksTable.DATABASE_TABLE_NAME); db.execSQL(LinksTable.TABLE_CREATE_LINKS); Log.d(TAG, "Old version < 20 - adding new app_details table"); db.execSQL("DROP TABLE IF EXISTS " + AppDetailsTable.DATABASE_TABLE_NAME); db.execSQL(AppDetailsTable.TABLE_CREATE_APP_DETAILS); Log.d(TAG, "Old version < 20 - adding new appinfo columns"); db.execSQL("ALTER table " + AppInfoTable.DATABASE_TABLE_NAME + " add " + AppInfoTable.KEY_APP_DEVELOPER_ID + " text"); db.execSQL("ALTER table " + AppInfoTable.DATABASE_TABLE_NAME + " add " + AppInfoTable.KEY_APP_DEVELOPER_NAME + " text"); // XXX // db.execSQL("ALTER table " + DeveloperAccountsTable.DATABASE_TABLE_NAME + " add " // + DeveloperAccountsTable.DEVELOPER_ID + " text"); } if (oldVersion < 21) { Log.w(TAG, "Old version < 21 - adding revenue_summary table"); db.execSQL("DROP TABLE IF EXISTS " + RevenueSummaryTable.DATABASE_TABLE_NAME); db.execSQL(RevenueSummaryTable.TABLE_CREATE_REVENUE_SUMMARY); Log.w(TAG, "Old version < 21 - add new stats colums"); db.execSQL("ALTER table " + AppStatsTable.DATABASE_TABLE_NAME + " add " + AppStatsTable.KEY_STATS_TOTAL_REVENUE + " double"); db.execSQL("ALTER table " + AppStatsTable.DATABASE_TABLE_NAME + " add " + AppStatsTable.KEY_STATS_CURRENCY + " text"); } // only add this if migrating from 21 if (oldVersion == 21) { Log.w(TAG, "Old version < 22 - adding revenue_summary.date column"); db.execSQL("ALTER table " + RevenueSummaryTable.DATABASE_TABLE_NAME + " add " + RevenueSummaryTable.DATE + " date"); // set all 2013-01-01 00:00:00 db.execSQL("UPDATE " + RevenueSummaryTable.DATABASE_TABLE_NAME + " SET " + RevenueSummaryTable.DATE + "= '1356998400'"); } if (oldVersion < 23) { Log.w(TAG, "Old version < 23 - adding appinfo.ad_unit_id column"); db.execSQL("ALTER table " + AppInfoTable.DATABASE_TABLE_NAME + " add " + AppInfoTable.KEY_APP_ADMOB_AD_UNIT_ID + " text"); Log.w(TAG, "Old version < 23 - adding admob.currency column"); db.execSQL("ALTER table " + AdmobTable.DATABASE_TABLE_NAME + " add " + AdmobTable.KEY_CURRENCY + " text"); } if (oldVersion < 24) { Log.w(TAG, "Old version < 24 - adding comment.title column"); db.execSQL("ALTER table " + CommentsTable.DATABASE_TABLE_NAME + " add " + CommentsTable.KEY_COMMENT_TITLE + " text"); db.execSQL("ALTER table " + CommentsTable.DATABASE_TABLE_NAME + " add " + CommentsTable.KEY_COMMENT_ORIGINAL_TITLE + " text"); } } @SuppressWarnings("deprecation") private void migrateAppInfoPrefs(SQLiteDatabase db) { Log.d(TAG, "Migrating app info settings from preferences..."); int migrated = 0; db.beginTransaction(); try { Cursor c = null; class Package { long id; String name; } List<Package> packages = new ArrayList<Package>(); try { c = db.query(AppInfoTable.DATABASE_TABLE_NAME, new String[] { AppInfoTable.KEY_ROWID, AppInfoTable.KEY_APP_PACKAGENAME }, null, null, null, null, "_id asc", null); while (c.moveToNext()) { Package p = new Package(); p.id = c.getLong(0); p.name = c.getString(1); packages.add(p); } } finally { if (c != null) { c.close(); } } for (Package p : packages) { Log.d(TAG, "Migrating package: " + p.name); String admobSiteId = Preferences.getAdmobSiteId(context, p.name); if (admobSiteId != null) { String admobAccount = Preferences.getAdmobAccount(context, admobSiteId); ContentValues values = new ContentValues(); values.put(AppInfoTable.KEY_APP_ADMOB_SITE_ID, admobSiteId); values.put(AppInfoTable.KEY_APP_ADMOB_ACCOUNT, admobAccount); db.update(AppInfoTable.DATABASE_TABLE_NAME, values, "_id = ?", new String[] { Long.toString(p.id) }); } long lastCommentsUpdate = Preferences.getLastCommentsRemoteUpdateTime(context, p.name); if (lastCommentsUpdate != 0) { ContentValues values = new ContentValues(); values.put(AppInfoTable.KEY_APP_LAST_COMMENTS_UPDATE, lastCommentsUpdate); db.update(AppInfoTable.DATABASE_TABLE_NAME, values, "_id = ?", new String[] { Long.toString(p.id) }); } migrated++; } db.setTransactionSuccessful(); } finally { db.endTransaction(); } Log.d(TAG, String.format("Successfully migrated app info settings for %d packages", migrated)); } @SuppressWarnings("deprecation") private void migrateAccountsFromPrefs(SQLiteDatabase db) { Log.d(TAG, "Migrating developer accounts from preferences..."); int migrated = 0; db.beginTransaction(); try { AccountManager am = AccountManager.get(context); Account[] accounts = am.getAccountsByType(AutosyncHandler.ACCOUNT_TYPE_GOOGLE); String activeAccount = Preferences.getAccountName(context); for (Account account : accounts) { boolean isHidden = Preferences.getIsHiddenAccount(context, account.name); long lastStatsUpdate = Preferences.getLastStatsRemoteUpdateTime(context, account.name); DeveloperAccount.State state = DeveloperAccount.State.ACTIVE; if (isHidden) { state = DeveloperAccount.State.HIDDEN; } if (account.name.equals(activeAccount)) { state = DeveloperAccount.State.SELECTED; } DeveloperAccount developerAccount = new DeveloperAccount(account.name, state); if (lastStatsUpdate != 0) { developerAccount.setLastStatsUpdate(new Date(lastStatsUpdate)); } Log.d(TAG, "Adding account: " + developerAccount); addDeveloperAccount(db, developerAccount); migrated++; } db.setTransactionSuccessful(); } finally { db.endTransaction(); } Log.d(TAG, String.format("Successfully migrated %d developer accounts", migrated)); } private long addDeveloperAccount(SQLiteDatabase db, DeveloperAccount account) { ContentValues values = toValues(account); return db.insertOrThrow(DeveloperAccountsTable.DATABASE_TABLE_NAME, null, values); } public synchronized long addDeveloperAccount(DeveloperAccount account) { return addDeveloperAccount(getWritableDatabase(), account); } public static ContentValues toValues(DeveloperAccount account) { ContentValues result = new ContentValues(); result.put(DeveloperAccountsTable.NAME, account.getName()); result.put(DeveloperAccountsTable.STATE, account.getState().ordinal()); long updateTime = account.getLastStatsUpdate() == null ? 0 : account.getLastStatsUpdate() .getTime(); result.put(DeveloperAccountsTable.LAST_STATS_UPDATE, updateTime); // XXX // result.put(DeveloperAccountsTable.DEVELOPER_ID, account.getDeveloperId()); return result; } // account, site ID, ad unit ID (only if migrated to 'new Admob') public String[] getAdmobDetails(String packageName) { SQLiteDatabase db = getWritableDatabase(); Cursor c = null; try { c = db.query(AppInfoTable.DATABASE_TABLE_NAME, new String[] { AppInfoTable.KEY_APP_ADMOB_ACCOUNT, AppInfoTable.KEY_APP_ADMOB_SITE_ID, AppInfoTable.KEY_APP_ADMOB_AD_UNIT_ID }, AppInfoTable.KEY_APP_PACKAGENAME + "=?", new String[] { packageName }, null, null, null); if (!c.moveToNext()) { return null; } String[] result = new String[3]; result[0] = c.getString(c.getColumnIndex(AppInfoTable.KEY_APP_ADMOB_ACCOUNT)); result[1] = c.getString(c.getColumnIndex(AppInfoTable.KEY_APP_ADMOB_SITE_ID)); result[2] = c.getString(c.getColumnIndex(AppInfoTable.KEY_APP_ADMOB_AD_UNIT_ID)); if (result[0] == null && result[1] == null) { return null; } return result; } finally { if (c != null) { c.close(); } } } public synchronized void saveAdmobDetails(String packageName, String admobAccount, String admobSiteId) { saveAdmobDetails(packageName, admobAccount, admobSiteId, null); } public synchronized void saveAdmobDetails(String packageName, String admobAccount, String admobSiteId, String admobAdUnitId) { SQLiteDatabase db = getWritableDatabase(); db.beginTransaction(); try { long id = findPackageId(db, packageName); ContentValues values = new ContentValues(); values.put(AppInfoTable.KEY_APP_ADMOB_ACCOUNT, admobAccount); values.put(AppInfoTable.KEY_APP_ADMOB_SITE_ID, admobSiteId); values.put(AppInfoTable.KEY_APP_ADMOB_AD_UNIT_ID, admobAdUnitId); db.update(AppInfoTable.DATABASE_TABLE_NAME, values, "_id = ?", new String[] { Long.toString(id) }); db.setTransactionSuccessful(); } finally { db.endTransaction(); } } public synchronized void saveAdmobAdUnitId(String packageName, String admobAccount, String admobAdUnitId) { SQLiteDatabase db = getWritableDatabase(); db.beginTransaction(); try { long id = findPackageId(db, packageName); ContentValues values = new ContentValues(); values.put(AppInfoTable.KEY_APP_ADMOB_ACCOUNT, admobAccount); values.put(AppInfoTable.KEY_APP_ADMOB_AD_UNIT_ID, admobAdUnitId); db.update(AppInfoTable.DATABASE_TABLE_NAME, values, "_id = ?", new String[] { Long.toString(id) }); db.setTransactionSuccessful(); } finally { db.endTransaction(); } } public synchronized long getLastCommentsRemoteUpdateTime(String packageName) { SQLiteDatabase db = getReadableDatabase(); Cursor c = null; try { c = db.query(AppInfoTable.DATABASE_TABLE_NAME, new String[] { AppInfoTable.KEY_APP_LAST_COMMENTS_UPDATE }, AppInfoTable.KEY_APP_PACKAGENAME + "=?", new String[] { packageName }, null, null, null); if (c.getCount() != 1) { Log.w(TAG, String.format("Unexpected package count for %s: %d", packageName, c.getCount())); } if (c.getCount() < 1 || !c.moveToNext()) { throw new IllegalStateException(String.format( "Package name not found in AppInfo table: %s. count=%d", packageName, c.getCount())); } int idx = c.getColumnIndex(AppInfoTable.KEY_APP_LAST_COMMENTS_UPDATE); if (c.isNull(idx)) { return 0; } return c.getLong(idx); } finally { if (c != null) { c.close(); } } } public synchronized void saveLastCommentsRemoteUpdateTime(String packageName, long updateTime) { SQLiteDatabase db = getWritableDatabase(); db.beginTransaction(); try { long id = findPackageId(db, packageName); ContentValues values = new ContentValues(); values.put(AppInfoTable.KEY_APP_LAST_COMMENTS_UPDATE, updateTime); db.update(AppInfoTable.DATABASE_TABLE_NAME, values, "_id = ?", new String[] { Long.toString(id) }); db.setTransactionSuccessful(); } finally { db.endTransaction(); } } private long findPackageId(SQLiteDatabase db, String packageName) { Cursor c = null; try { c = db.query(AppInfoTable.DATABASE_TABLE_NAME, new String[] { AppInfoTable.KEY_ROWID }, AppInfoTable.KEY_APP_PACKAGENAME + "=?", new String[] { packageName }, null, null, null); if (c.getCount() != 1) { Log.w(TAG, String.format("Unexpected package count for %s: %d", packageName, c.getCount())); } if (c.getCount() < 1 || !c.moveToNext()) { throw new IllegalStateException(String.format( "Package name not found in AppInfo table: %s. count=%d", packageName, c.getCount())); } return c.getLong(c.getColumnIndex(AppInfoTable.KEY_ROWID)); } finally { if (c != null) { c.close(); } } } public synchronized AppInfo findAppByPackageName(String packageName) { SQLiteDatabase db = getReadableDatabase(); Cursor cursor = null; try { cursor = db.query(AppInfoTable.DATABASE_TABLE_NAME, new String[] { AppInfoTable.KEY_ROWID, AppInfoTable.KEY_APP_VERSION_NAME, AppInfoTable.KEY_APP_PACKAGENAME, AppInfoTable.KEY_APP_LASTUPDATE, AppInfoTable.KEY_APP_NAME, AppInfoTable.KEY_APP_GHOST, AppInfoTable.KEY_APP_SKIP_NOTIFICATION, AppInfoTable.KEY_APP_RATINGS_EXPANDED, AppInfoTable.KEY_APP_ICONURL, AppInfoTable.KEY_APP_ADMOB_ACCOUNT, AppInfoTable.KEY_APP_ADMOB_SITE_ID, AppInfoTable.KEY_APP_LAST_COMMENTS_UPDATE, AppInfoTable.KEY_APP_ACCOUNT, AppInfoTable.KEY_APP_DEVELOPER_ID, AppInfoTable.KEY_APP_DEVELOPER_NAME }, AppInfoTable.KEY_APP_PACKAGENAME + "=?", new String[] { packageName }, null, null, null); if (cursor.getCount() < 1 || !cursor.moveToNext()) { return null; } AppInfo appInfo = new AppInfo(); appInfo.setId(cursor.getLong(cursor.getColumnIndex(AppInfoTable.KEY_ROWID))); appInfo.setAccount(cursor.getString(cursor.getColumnIndex(AppInfoTable.KEY_APP_ACCOUNT))); appInfo.setLastUpdate(Utils.parseDbDate(cursor.getString(cursor .getColumnIndex(AppInfoTable.KEY_APP_LASTUPDATE)))); appInfo.setPackageName(cursor.getString(cursor .getColumnIndex(AppInfoTable.KEY_APP_PACKAGENAME))); appInfo.setName(cursor.getString(cursor.getColumnIndex(AppInfoTable.KEY_APP_NAME))); appInfo.setGhost(cursor.getInt(cursor.getColumnIndex(AppInfoTable.KEY_APP_GHOST)) == 0 ? false : true); appInfo.setSkipNotification(cursor.getInt(cursor .getColumnIndex(AppInfoTable.KEY_APP_SKIP_NOTIFICATION)) == 0 ? false : true); appInfo.setRatingDetailsExpanded(cursor.getInt(cursor .getColumnIndex(AppInfoTable.KEY_APP_RATINGS_EXPANDED)) == 0 ? false : true); appInfo.setIconUrl(cursor.getString(cursor.getColumnIndex(AppInfoTable.KEY_APP_ICONURL))); appInfo.setVersionName(cursor.getString(cursor .getColumnIndex(AppInfoTable.KEY_APP_VERSION_NAME))); int idx = cursor.getColumnIndex(AppInfoTable.KEY_APP_ADMOB_ACCOUNT); if (!cursor.isNull(idx)) { appInfo.setAdmobAccount(cursor.getString(idx)); } idx = cursor.getColumnIndex(AppInfoTable.KEY_APP_ADMOB_SITE_ID); if (!cursor.isNull(idx)) { appInfo.setAdmobSiteId(cursor.getString(idx)); } idx = cursor.getColumnIndex(AppInfoTable.KEY_APP_ADMOB_AD_UNIT_ID); if (!cursor.isNull(idx)) { appInfo.setAdmobAdUnitId(cursor.getString(idx)); } idx = cursor.getColumnIndex(AppInfoTable.KEY_APP_LAST_COMMENTS_UPDATE); if (!cursor.isNull(idx)) { appInfo.setLastCommentsUpdate(new Date(cursor.getLong(idx))); } idx = cursor.getColumnIndex(AppInfoTable.KEY_APP_DEVELOPER_ID); if (!cursor.isNull(idx)) { appInfo.setDeveloperId(cursor.getString(idx)); } idx = cursor.getColumnIndex(AppInfoTable.KEY_APP_DEVELOPER_NAME); if (!cursor.isNull(idx)) { appInfo.setDeveloperName(cursor.getString(idx)); } fetchAppDetails(appInfo); return appInfo; } finally { if (cursor != null) { cursor.close(); } } } public synchronized void fetchAppDetails(AppInfo appInfo) { if (appInfo.getId() == null) { // not persistent return; } SQLiteDatabase db = getReadableDatabase(); Cursor c = null; try { c = db.query(AppDetailsTable.DATABASE_TABLE_NAME, AppDetailsTable.ALL_COLUMNS, AppDetailsTable.APPINFO_ID + "=?", new String[] { Long.toString(appInfo.getId()) }, null, null, null); if (c.getCount() < 1 || !c.moveToNext()) { return; } Long id = c.getLong(c.getColumnIndex(AppDetailsTable.ROWID)); String description = c.getString(c.getColumnIndex(AppDetailsTable.DESCRIPTION)); AppDetails details = new AppDetails(description); details.setId(id); int idx = c.getColumnIndex(AppDetailsTable.CHANGELOG); if (!c.isNull(idx)) { details.setChangelog(c.getString(idx)); } idx = c.getColumnIndex(AppDetailsTable.LAST_STORE_UPDATE); if (!c.isNull(idx)) { details.setLastStoreUpdate(new Date(c.getLong(idx))); } List<Link> links = getLinksForApp(id); details.setLinks(links); appInfo.setDetails(details); } finally { if (c != null) { c.close(); } } } private long saveAppDetails(SQLiteDatabase db, AppInfo appInfo) { ContentValues values = toValues(appInfo); return db.insertOrThrow(AppDetailsTable.DATABASE_TABLE_NAME, null, values); } public synchronized long saveAppDetails(AppInfo appInfo) { return saveAppDetails(getWritableDatabase(), appInfo); } public synchronized void updateAppDetails(AppDetails details) { ContentValues values = new ContentValues(); values.put(AppDetailsTable.DESCRIPTION, details.getDescription()); values.put(AppDetailsTable.CHANGELOG, details.getChangelog()); long updateTime = details.getLastStoreUpdate() == null ? 0 : details.getLastStoreUpdate() .getTime(); values.put(AppDetailsTable.LAST_STORE_UPDATE, updateTime); getWritableDatabase().update(AppDetailsTable.DATABASE_TABLE_NAME, values, "_id = ?", new String[] { Long.toString(details.getId()) }); } public synchronized void insertOrUpdateAppDetails(AppInfo appInfo) { SQLiteDatabase db = getWritableDatabase(); Cursor c = null; try { c = db.query(AppDetailsTable.DATABASE_TABLE_NAME, new String[] { AppDetailsTable.ROWID }, AppDetailsTable.APPINFO_ID + "=?", new String[] { Long.toString(appInfo.getId()) }, null, null, null); if (c.getCount() < 1 || !c.moveToNext()) { saveAppDetails(appInfo); } else { long id = c.getLong(c.getColumnIndex(AppDetailsTable.ROWID)); appInfo.getDetails().setId(id); updateAppDetails(appInfo.getDetails()); } } finally { if (c != null) { c.close(); } } } public static ContentValues toValues(AppInfo appInfo) { AppDetails details = appInfo.getDetails(); ContentValues result = new ContentValues(); result.put(AppDetailsTable.DESCRIPTION, details.getDescription()); result.put(AppDetailsTable.CHANGELOG, details.getChangelog()); long updateTime = details.getLastStoreUpdate() == null ? 0 : details.getLastStoreUpdate() .getTime(); result.put(AppDetailsTable.LAST_STORE_UPDATE, updateTime); result.put(AppDetailsTable.APPINFO_ID, appInfo.getId()); return result; } public synchronized ArrayList<Link> getLinksForApp(long appDetailsId) { SQLiteDatabase db = getReadableDatabase(); ArrayList<Link> result = new ArrayList<Link>(); Cursor cursor = null; try { cursor = db.query(LinksTable.DATABASE_TABLE_NAME, LinksTable.ALL_COLUMNS, LinksTable.APP_DETAILS_ID + " = ?", new String[] { Long.toString(appDetailsId) }, null, null, LinksTable.ROWID); if (cursor == null) { return result; } while (cursor.moveToNext()) { Link link = new Link(); link.setId(cursor.getLong(cursor.getColumnIndex(LinksTable.ROWID))); link.setName(cursor.getString(cursor.getColumnIndex(LinksTable.LINK_NAME))); link.setURL(cursor.getString(cursor.getColumnIndex(LinksTable.LINK_URL))); result.add(link); } return result; } finally { if (cursor != null) { cursor.close(); } } } public synchronized void deleteLink(long id) { getWritableDatabase().delete(LinksTable.DATABASE_TABLE_NAME, LinksTable.ROWID + "=?", new String[] { Long.toString(id) }); } public synchronized void addLink(AppDetails appDetails, String url, String name) { ContentValues values = new ContentValues(); values.put(LinksTable.APP_DETAILS_ID, appDetails.getId()); values.put(LinksTable.LINK_URL, url); values.put(LinksTable.LINK_NAME, name); getWritableDatabase().insertOrThrow(LinksTable.DATABASE_TABLE_NAME, null, values); } public synchronized void editLink(Long id, String url, String name) { ContentValues values = new ContentValues(); values.put(LinksTable.LINK_URL, url); values.put(LinksTable.LINK_NAME, name); getWritableDatabase().update(LinksTable.DATABASE_TABLE_NAME, values, LinksTable.ROWID + " = ?", new String[] { Long.toString(id) }); } public synchronized void fetchRevenueSummary(AppInfo appInfo) { if (appInfo.getId() == null) { // not persistent return; } SQLiteDatabase db = getReadableDatabase(); Cursor c = null; try { c = db.query(RevenueSummaryTable.DATABASE_TABLE_NAME, RevenueSummaryTable.ALL_COLUMNS, RevenueSummaryTable.APPINFO_ID + "=?", new String[] { Long.toString(appInfo.getId()) }, null, null, RevenueSummaryTable.DATE + " desc", "1"); if (c.getCount() < 1 || !c.moveToNext()) { return; } Long id = c.getLong(c.getColumnIndex(RevenueSummaryTable.ROWID)); int typeIdx = c.getInt(c.getColumnIndex(RevenueSummaryTable.TYPE)); String currency = c.getString(c.getColumnIndex(RevenueSummaryTable.CURRENCY)); Date date = Utils.parseDbDate("2013-01-01 00:00:00"); int idx = c.getColumnIndex(RevenueSummaryTable.DATE); if (!c.isNull(idx)) { date = new Date(c.getLong(idx)); } double lastDayTotal = c.getDouble(c.getColumnIndex(RevenueSummaryTable.LAST_DAY_TOTAL)); double last7DaysTotal = c.getDouble(c .getColumnIndex(RevenueSummaryTable.LAST_7DAYS_TOTAL)); double last30DaysTotal = c.getDouble(c .getColumnIndex(RevenueSummaryTable.LAST_30DAYS_TOTAL)); double overallTotal = c.getDouble(c.getColumnIndex(RevenueSummaryTable.OVERALL_TOTAL)); Revenue.Type type = Revenue.Type.values()[typeIdx]; RevenueSummary revenue = new RevenueSummary(type, currency, date, lastDayTotal, last7DaysTotal, last30DaysTotal, overallTotal); revenue.setId(id); appInfo.setTotalRevenueSummary(revenue); } finally { if (c != null) { c.close(); } } } }