/*
* Sonet - Android Social Networking Widget
* Copyright (C) 2009 Bryan Emmanuel
*
* 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, either version 3 of the License, or
* (at your option) any later version.
*
* 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/>.
*
* Bryan Emmanuel piusvelte@gmail.com
*/
package com.piusvelte.sonet;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import com.piusvelte.eidos.Eidos;
import com.piusvelte.sonet.provider.Accounts;
import com.piusvelte.sonet.provider.Entity;
import com.piusvelte.sonet.provider.Notifications;
import com.piusvelte.sonet.provider.StatusImages;
import com.piusvelte.sonet.provider.StatusLinks;
import com.piusvelte.sonet.provider.Statuses;
import com.piusvelte.sonet.provider.StatusesStyles;
import com.piusvelte.sonet.provider.WidgetAccounts;
import com.piusvelte.sonet.provider.WidgetAccountsView;
import com.piusvelte.sonet.provider.Widgets;
import com.piusvelte.sonet.provider.WidgetsSettings;
import com.piusvelte.sonet.util.DatabaseUtils;
import java.util.HashMap;
public class SonetProvider extends ContentProvider {
private static final String TAG = "SonetProvider";
public static final String AUTHORITY = "com.piusvelte.sonet.SonetProvider";
public static final String PRO_AUTHORITY = "com.piusvelte.sonetpro.SonetProvider";
private static final UriMatcher sUriMatcher;
private static final int ACCOUNTS = 0;
private static final int WIDGETS = 1;
private static final int STATUSES = 2;
public static final int STATUSES_STYLES = 3;
private static final int STATUSES_STYLES_WIDGET = 4;
private static final int ENTITIES = 5;
private static final int WIDGET_ACCOUNTS = 6;
private static final int WIDGET_ACCOUNTS_VIEW = 7;
public static final int NOTIFICATIONS = 8;
protected static final int WIDGETS_SETTINGS = 9;
protected static final int DISTINCT_WIDGETS_SETTINGS = 10;
protected static final int STATUS_LINKS = 11;
protected static final int STATUS_IMAGES = 12;
protected static final String DATABASE_NAME = "sonet.db";
private static final int DATABASE_VERSION = 31;
private static HashMap<String, String> accountsProjectionMap;
private static HashMap<String, String> widgetsProjectionMap;
private static HashMap<String, String> statusesProjectionMap;
private static HashMap<String, String> statuses_stylesProjectionMap;
private static HashMap<String, String> entitiesProjectionMap;
private static HashMap<String, String> widget_accountsProjectionMap;
private static HashMap<String, String> widget_accounts_viewProjectionMap;
private static HashMap<String, String> notificationsProjectionMap;
private static final String VIEW_DISTINCT_WIDGETS_SETTINGS = "distinct_widgets_settings";
private static HashMap<String, String> status_linksProjectionMap;
private static HashMap<String, String> status_imagesProjectionMap;
private DatabaseHelper mDatabaseHelper;
static {
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sUriMatcher.addURI(AUTHORITY, Accounts.TABLE, ACCOUNTS);
sUriMatcher.addURI(PRO_AUTHORITY, Accounts.TABLE, ACCOUNTS);
accountsProjectionMap = new HashMap<>();
accountsProjectionMap.put(Accounts._ID, Accounts._ID);
accountsProjectionMap.put(Accounts.USERNAME, Accounts.USERNAME);
accountsProjectionMap.put(Accounts.TOKEN, Accounts.TOKEN);
accountsProjectionMap.put(Accounts.SECRET, Accounts.SECRET);
accountsProjectionMap.put(Accounts.SERVICE, Accounts.SERVICE);
accountsProjectionMap.put(Accounts.EXPIRY, Accounts.EXPIRY);
accountsProjectionMap.put(Accounts.SID, Accounts.SID);
sUriMatcher.addURI(AUTHORITY, WidgetAccounts.TABLE, WIDGET_ACCOUNTS);
sUriMatcher.addURI(PRO_AUTHORITY, WidgetAccounts.TABLE, WIDGET_ACCOUNTS);
widget_accountsProjectionMap = new HashMap<>();
widget_accountsProjectionMap.put(WidgetAccounts._ID, WidgetAccounts._ID);
widget_accountsProjectionMap.put(WidgetAccounts.ACCOUNT, WidgetAccounts.ACCOUNT);
widget_accountsProjectionMap.put(WidgetAccounts.WIDGET, WidgetAccounts.WIDGET);
sUriMatcher.addURI(AUTHORITY, WidgetAccountsView.VIEW, WIDGET_ACCOUNTS_VIEW);
sUriMatcher.addURI(PRO_AUTHORITY, WidgetAccountsView.VIEW, WIDGET_ACCOUNTS_VIEW);
widget_accounts_viewProjectionMap = new HashMap<>();
widget_accounts_viewProjectionMap.put(WidgetAccountsView._ID, WidgetAccountsView._ID);
widget_accounts_viewProjectionMap.put(WidgetAccountsView.ACCOUNT, WidgetAccountsView.ACCOUNT);
widget_accounts_viewProjectionMap.put(WidgetAccountsView.WIDGET, WidgetAccountsView.WIDGET);
widget_accounts_viewProjectionMap.put(WidgetAccountsView.USERNAME, WidgetAccountsView.USERNAME);
widget_accounts_viewProjectionMap.put(WidgetAccountsView.TOKEN, WidgetAccountsView.TOKEN);
widget_accounts_viewProjectionMap.put(WidgetAccountsView.SECRET, WidgetAccountsView.SECRET);
widget_accounts_viewProjectionMap.put(WidgetAccountsView.SERVICE, WidgetAccountsView.SERVICE);
widget_accounts_viewProjectionMap.put(WidgetAccountsView.EXPIRY, WidgetAccountsView.EXPIRY);
widget_accounts_viewProjectionMap.put(WidgetAccountsView.SID, WidgetAccountsView.SID);
sUriMatcher.addURI(AUTHORITY, Widgets.TABLE, WIDGETS);
sUriMatcher.addURI(PRO_AUTHORITY, Widgets.TABLE, WIDGETS);
widgetsProjectionMap = new HashMap<>();
widgetsProjectionMap.put(Widgets._ID, Widgets._ID);
widgetsProjectionMap.put(Widgets.WIDGET, Widgets.WIDGET);
widgetsProjectionMap.put(Widgets.INTERVAL, Widgets.INTERVAL);
widgetsProjectionMap.put(Widgets.TIME24HR, Widgets.TIME24HR);
widgetsProjectionMap.put(Widgets.ACCOUNT, Widgets.ACCOUNT);
widgetsProjectionMap.put(Widgets.BACKGROUND_UPDATE, Widgets.BACKGROUND_UPDATE);
widgetsProjectionMap.put(Widgets.SOUND, Widgets.SOUND);
widgetsProjectionMap.put(Widgets.VIBRATE, Widgets.VIBRATE);
widgetsProjectionMap.put(Widgets.LIGHTS, Widgets.LIGHTS);
widgetsProjectionMap.put(Widgets.INSTANT_UPLOAD, Widgets.INSTANT_UPLOAD);
sUriMatcher.addURI(AUTHORITY, Statuses.TABLE, STATUSES);
sUriMatcher.addURI(PRO_AUTHORITY, Statuses.TABLE, STATUSES);
statusesProjectionMap = new HashMap<>();
statusesProjectionMap.put(Statuses._ID, Statuses._ID);
statusesProjectionMap.put(Statuses.CREATED, Statuses.CREATED);
statusesProjectionMap.put(Statuses.MESSAGE, Statuses.MESSAGE);
statusesProjectionMap.put(Statuses.SERVICE, Statuses.SERVICE);
statusesProjectionMap.put(Statuses.CREATEDTEXT, Statuses.CREATEDTEXT);
statusesProjectionMap.put(Statuses.WIDGET, Statuses.WIDGET);
statusesProjectionMap.put(Statuses.ACCOUNT, Statuses.ACCOUNT);
statusesProjectionMap.put(Statuses.SID, Statuses.SID);
statusesProjectionMap.put(Statuses.ENTITY, Statuses.ENTITY);
sUriMatcher.addURI(AUTHORITY, StatusesStyles.VIEW, STATUSES_STYLES);
sUriMatcher.addURI(PRO_AUTHORITY, StatusesStyles.VIEW, STATUSES_STYLES);
sUriMatcher.addURI(AUTHORITY, StatusesStyles.VIEW + "/*", STATUSES_STYLES_WIDGET);
sUriMatcher.addURI(PRO_AUTHORITY, StatusesStyles.VIEW + "/*", STATUSES_STYLES_WIDGET);
statuses_stylesProjectionMap = new HashMap<>();
statuses_stylesProjectionMap.put(StatusesStyles._ID, StatusesStyles._ID);
statuses_stylesProjectionMap.put(StatusesStyles.CREATED, StatusesStyles.CREATED);
statuses_stylesProjectionMap.put(StatusesStyles.FRIEND, StatusesStyles.FRIEND);
statuses_stylesProjectionMap.put(StatusesStyles.MESSAGE, StatusesStyles.MESSAGE);
statuses_stylesProjectionMap.put(StatusesStyles.SERVICE, StatusesStyles.SERVICE);
statuses_stylesProjectionMap.put(StatusesStyles.CREATEDTEXT, StatusesStyles.CREATEDTEXT);
statuses_stylesProjectionMap.put(StatusesStyles.WIDGET, StatusesStyles.WIDGET);
statuses_stylesProjectionMap.put(StatusesStyles.ACCOUNT, StatusesStyles.ACCOUNT);
statuses_stylesProjectionMap.put(StatusesStyles.SID, StatusesStyles.SID);
statuses_stylesProjectionMap.put(StatusesStyles.ENTITY, StatusesStyles.ENTITY);
statuses_stylesProjectionMap.put(StatusesStyles.ESID, StatusesStyles.ESID);
statuses_stylesProjectionMap.put(StatusesStyles.IMAGE_URL, StatusesStyles.IMAGE_URL);
statuses_stylesProjectionMap.put(StatusesStyles.PROFILE_URL, StatusesStyles.PROFILE_URL);
sUriMatcher.addURI(AUTHORITY, Entity.TABLE, ENTITIES);
sUriMatcher.addURI(PRO_AUTHORITY, Entity.TABLE, ENTITIES);
entitiesProjectionMap = new HashMap<>();
entitiesProjectionMap.put(Entity._ID, Entity._ID);
entitiesProjectionMap.put(Entity.ESID, Entity.ESID);
entitiesProjectionMap.put(Entity.FRIEND, Entity.FRIEND);
entitiesProjectionMap.put(Entity.ACCOUNT, Entity.ACCOUNT);
entitiesProjectionMap.put(Entity.PROFILE_URL, Entity.PROFILE_URL);
sUriMatcher.addURI(AUTHORITY, Notifications.TABLE, NOTIFICATIONS);
sUriMatcher.addURI(PRO_AUTHORITY, Notifications.TABLE, NOTIFICATIONS);
notificationsProjectionMap = new HashMap<>();
notificationsProjectionMap.put(Notifications._ID, Notifications._ID);
notificationsProjectionMap.put(Notifications.SID, Notifications.SID);
notificationsProjectionMap.put(Notifications.ESID, Notifications.ESID);
notificationsProjectionMap.put(Notifications.FRIEND, Notifications.FRIEND);
notificationsProjectionMap.put(Notifications.MESSAGE, Notifications.MESSAGE);
notificationsProjectionMap.put(Notifications.CREATED, Notifications.CREATED);
notificationsProjectionMap.put(Notifications.NOTIFICATION, Notifications.NOTIFICATION);
notificationsProjectionMap.put(Notifications.ACCOUNT, Notifications.ACCOUNT);
notificationsProjectionMap.put(Notifications.CLEARED, Notifications.CLEARED);
notificationsProjectionMap.put(Notifications.UPDATED, Notifications.UPDATED);
sUriMatcher.addURI(AUTHORITY, WidgetsSettings.VIEW, WIDGETS_SETTINGS);
sUriMatcher.addURI(PRO_AUTHORITY, WidgetsSettings.VIEW, WIDGETS_SETTINGS);
sUriMatcher.addURI(AUTHORITY, VIEW_DISTINCT_WIDGETS_SETTINGS, DISTINCT_WIDGETS_SETTINGS);
sUriMatcher.addURI(PRO_AUTHORITY, VIEW_DISTINCT_WIDGETS_SETTINGS, DISTINCT_WIDGETS_SETTINGS);
sUriMatcher.addURI(AUTHORITY, StatusLinks.TABLE, STATUS_LINKS);
sUriMatcher.addURI(PRO_AUTHORITY, StatusLinks.TABLE, STATUS_LINKS);
status_linksProjectionMap = new HashMap<>();
status_linksProjectionMap.put(StatusLinks._ID, StatusLinks._ID);
status_linksProjectionMap.put(StatusLinks.STATUS_ID, StatusLinks.STATUS_ID);
status_linksProjectionMap.put(StatusLinks.LINK_URI, StatusLinks.LINK_URI);
status_linksProjectionMap.put(StatusLinks.LINK_TYPE, StatusLinks.LINK_TYPE);
sUriMatcher.addURI(AUTHORITY, StatusImages.TABLE, STATUS_IMAGES);
sUriMatcher.addURI(PRO_AUTHORITY, StatusImages.TABLE, STATUS_IMAGES);
status_imagesProjectionMap = new HashMap<>();
status_imagesProjectionMap.put(StatusImages._ID, StatusImages._ID);
status_imagesProjectionMap.put(StatusImages.STATUS_ID, StatusImages.STATUS_ID);
status_imagesProjectionMap.put(StatusImages.URL, StatusImages.URL);
}
@Override
public boolean onCreate() {
mDatabaseHelper = new DatabaseHelper(getContext());
return true;
}
@Override
public String getType(Uri uri) {
switch (sUriMatcher.match(uri)) {
case ACCOUNTS:
return Accounts.CONTENT_TYPE;
case WIDGET_ACCOUNTS:
return WidgetAccounts.CONTENT_TYPE;
case WIDGET_ACCOUNTS_VIEW:
return WidgetAccountsView.CONTENT_TYPE;
case WIDGETS:
return Widgets.CONTENT_TYPE;
case STATUSES:
return Statuses.CONTENT_TYPE;
case STATUSES_STYLES:
return StatusesStyles.CONTENT_TYPE;
case STATUSES_STYLES_WIDGET:
return StatusesStyles.CONTENT_TYPE;
case ENTITIES:
return Entity.CONTENT_TYPE;
case NOTIFICATIONS:
return Notifications.CONTENT_TYPE;
case WIDGETS_SETTINGS:
return WidgetsSettings.CONTENT_TYPE;
case DISTINCT_WIDGETS_SETTINGS:
return WidgetsSettings.CONTENT_TYPE;
case STATUS_LINKS:
return StatusLinks.CONTENT_TYPE;
case STATUS_IMAGES:
return StatusImages.CONTENT_TYPE;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
}
@Override
public int delete(Uri uri, String whereClause, String[] whereArgs) {
SQLiteDatabase db;
synchronized (Eidos.DatabaseLock) {
db = mDatabaseHelper.getWritableDatabase();
}
int count;
switch (sUriMatcher.match(uri)) {
case ACCOUNTS:
synchronized (Eidos.DatabaseLock) {
count = db.delete(Accounts.TABLE, whereClause, whereArgs);
}
break;
case WIDGET_ACCOUNTS:
synchronized (Eidos.DatabaseLock) {
count = db.delete(WidgetAccounts.TABLE, whereClause, whereArgs);
}
break;
case WIDGETS:
count = db.delete(Widgets.TABLE, whereClause, whereArgs);
break;
case STATUSES:
synchronized (Eidos.DatabaseLock) {
count = db.delete(Statuses.TABLE, whereClause, whereArgs);
}
break;
case ENTITIES:
synchronized (Eidos.DatabaseLock) {
count = db.delete(Entity.TABLE, whereClause, whereArgs);
}
break;
case NOTIFICATIONS:
synchronized (Eidos.DatabaseLock) {
count = db.delete(Notifications.TABLE, whereClause, whereArgs);
}
break;
case WIDGETS_SETTINGS:
synchronized (Eidos.DatabaseLock) {
count = db.delete(WidgetsSettings.VIEW, whereClause, whereArgs);
}
break;
case STATUS_LINKS:
synchronized (Eidos.DatabaseLock) {
count = db.delete(StatusLinks.TABLE, whereClause, whereArgs);
}
break;
case STATUS_IMAGES:
synchronized (Eidos.DatabaseLock) {
count = db.delete(StatusImages.TABLE, whereClause, whereArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db;
synchronized (Eidos.DatabaseLock) {
db = mDatabaseHelper.getWritableDatabase();
}
long rowId;
Uri returnUri = null;
SonetCrypto sonetCrypto;
switch (sUriMatcher.match(uri)) {
case ACCOUNTS:
// encrypt the data
sonetCrypto = SonetCrypto.getInstance(getContext());
if (values.containsKey(Accounts.TOKEN)) {
values.put(Accounts.TOKEN, sonetCrypto.Encrypt(values.getAsString(Accounts.TOKEN)));
}
if (values.containsKey(Accounts.SECRET)) {
values.put(Accounts.SECRET, sonetCrypto.Encrypt(values.getAsString(Accounts.SECRET)));
}
if (values.containsKey(Accounts.SID)) {
values.put(Accounts.SID, sonetCrypto.Encrypt(values.getAsString(Accounts.SID)));
}
synchronized (Eidos.DatabaseLock) {
rowId = db.insert(Accounts.TABLE, Accounts._ID, values);
}
returnUri = ContentUris.withAppendedId(Accounts.getContentUri(getContext()), rowId);
getContext().getContentResolver().notifyChange(returnUri, null);
break;
case WIDGET_ACCOUNTS:
synchronized (Eidos.DatabaseLock) {
rowId = db.insert(WidgetAccounts.TABLE, WidgetAccounts._ID, values);
}
returnUri = ContentUris.withAppendedId(WidgetAccounts.getContentUri(getContext()), rowId);
getContext().getContentResolver().notifyChange(returnUri, null);
break;
case WIDGETS:
synchronized (Eidos.DatabaseLock) {
rowId = db.insert(Widgets.TABLE, Widgets._ID, values);
}
returnUri = ContentUris.withAppendedId(Widgets.getContentUri(getContext()), rowId);
getContext().getContentResolver().notifyChange(returnUri, null);
break;
case STATUSES:
// encrypt the data
sonetCrypto = SonetCrypto.getInstance(getContext());
if (values.containsKey(Statuses.SID)) {
values.put(Statuses.SID, sonetCrypto.Encrypt(values.getAsString(Statuses.SID)));
}
synchronized (Eidos.DatabaseLock) {
rowId = db.insert(Statuses.TABLE, Accounts._ID, values);
}
returnUri = ContentUris.withAppendedId(Accounts.getContentUri(getContext()), rowId);
// many statuses will be inserted at once, so don't trigger a refresh for each one
// getContext().getContentResolver().notifyChange(returnUri, null);
break;
case ENTITIES:
// encrypt the data
sonetCrypto = SonetCrypto.getInstance(getContext());
if (values.containsKey(Entity.ESID)) {
values.put(Entity.ESID, sonetCrypto.Encrypt(values.getAsString(Entity.ESID)));
}
synchronized (Eidos.DatabaseLock) {
rowId = db.insert(Entity.TABLE, Entity._ID, values);
}
returnUri = ContentUris.withAppendedId(Entity.getContentUri(getContext()), rowId);
break;
case NOTIFICATIONS:
// encrypt the data
sonetCrypto = SonetCrypto.getInstance(getContext());
if (values.containsKey(Notifications.SID)) {
values.put(Notifications.SID, sonetCrypto.Encrypt(values.getAsString(Notifications.SID)));
}
if (values.containsKey(Notifications.ESID)) {
values.put(Notifications.ESID, sonetCrypto.Encrypt(values.getAsString(Notifications.ESID)));
}
synchronized (Eidos.DatabaseLock) {
rowId = db.insert(Notifications.TABLE, Notifications._ID, values);
}
returnUri = ContentUris.withAppendedId(Notifications.getContentUri(getContext()), rowId);
getContext().getContentResolver().notifyChange(returnUri, null);
break;
case WIDGETS_SETTINGS:
synchronized (Eidos.DatabaseLock) {
rowId = db.insert(WidgetsSettings.VIEW, WidgetsSettings._ID, values);
}
returnUri = ContentUris.withAppendedId(WidgetsSettings.getContentUri(getContext()), rowId);
getContext().getContentResolver().notifyChange(returnUri, null);
break;
case STATUS_LINKS:
synchronized (Eidos.DatabaseLock) {
rowId = db.insert(StatusLinks.TABLE, StatusLinks._ID, values);
}
returnUri = ContentUris.withAppendedId(StatusLinks.getContentUri(getContext()), rowId);
getContext().getContentResolver().notifyChange(returnUri, null);
break;
case STATUS_IMAGES:
synchronized (Eidos.DatabaseLock) {
rowId = db.insert(StatusImages.TABLE, StatusImages._ID, values);
}
returnUri = ContentUris.withAppendedId(StatusImages.getContentUri(getContext()), rowId);
getContext().getContentResolver().notifyChange(returnUri, null);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
return returnUri;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String orderBy) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
switch (sUriMatcher.match(uri)) {
case ACCOUNTS:
qb.setTables(Accounts.TABLE);
qb.setProjectionMap(accountsProjectionMap);
break;
case WIDGET_ACCOUNTS:
qb.setTables(WidgetAccounts.TABLE);
qb.setProjectionMap(widget_accountsProjectionMap);
break;
case WIDGET_ACCOUNTS_VIEW:
qb.setTables(WidgetAccountsView.VIEW);
qb.setProjectionMap(widget_accounts_viewProjectionMap);
break;
case WIDGETS:
qb.setTables(Widgets.TABLE);
qb.setProjectionMap(widgetsProjectionMap);
break;
case STATUSES:
qb.setTables(Statuses.TABLE);
qb.setProjectionMap(statusesProjectionMap);
break;
case STATUSES_STYLES:
qb.setTables(StatusesStyles.VIEW);
qb.setProjectionMap(statuses_stylesProjectionMap);
break;
case STATUSES_STYLES_WIDGET:
qb.setTables(StatusesStyles.VIEW);
qb.setProjectionMap(statuses_stylesProjectionMap);
if ((selection == null) || (selectionArgs == null)) {
selection = StatusesStyles.WIDGET + "=?";
selectionArgs = new String[] { uri.getLastPathSegment() };
}
break;
case ENTITIES:
qb.setTables(Entity.TABLE);
qb.setProjectionMap(entitiesProjectionMap);
break;
case NOTIFICATIONS:
qb.setTables(Notifications.TABLE);
qb.setProjectionMap(notificationsProjectionMap);
break;
case WIDGETS_SETTINGS:
qb.setTables(WidgetsSettings.VIEW);
qb.setProjectionMap(widgetsProjectionMap);
break;
case DISTINCT_WIDGETS_SETTINGS:
qb.setTables(WidgetsSettings.VIEW);
qb.setProjectionMap(widgetsProjectionMap);
qb.setDistinct(true);
break;
case STATUS_LINKS:
qb.setTables(StatusLinks.TABLE);
qb.setProjectionMap(status_linksProjectionMap);
break;
case STATUS_IMAGES:
qb.setTables(StatusImages.TABLE);
qb.setProjectionMap(status_imagesProjectionMap);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
SQLiteDatabase db;
synchronized (Eidos.DatabaseLock) {
db = mDatabaseHelper.getWritableDatabase();
}
int count;
SonetCrypto sonetCrypto;
switch (sUriMatcher.match(uri)) {
case ACCOUNTS:
// encrypt the data
sonetCrypto = SonetCrypto.getInstance(getContext());
if (values.containsKey(Accounts.TOKEN)) {
values.put(Accounts.TOKEN, sonetCrypto.Encrypt(values.getAsString(Accounts.TOKEN)));
}
if (values.containsKey(Accounts.SECRET)) {
values.put(Accounts.SECRET, sonetCrypto.Encrypt(values.getAsString(Accounts.SECRET)));
}
if (values.containsKey(Accounts.SID)) {
values.put(Accounts.SID, sonetCrypto.Encrypt(values.getAsString(Accounts.SID)));
}
synchronized (Eidos.DatabaseLock) {
count = db.update(Accounts.TABLE, values, selection, selectionArgs);
}
break;
case WIDGET_ACCOUNTS:
synchronized (Eidos.DatabaseLock) {
count = db.update(WidgetAccounts.TABLE, values, selection, selectionArgs);
}
break;
case WIDGETS:
synchronized (Eidos.DatabaseLock) {
count = db.update(Widgets.TABLE, values, selection, selectionArgs);
}
break;
case STATUSES:
// encrypt the data
sonetCrypto = SonetCrypto.getInstance(getContext());
if (values.containsKey(Statuses.SID)) {
values.put(Statuses.SID, sonetCrypto.Encrypt(values.getAsString(Statuses.SID)));
}
synchronized (Eidos.DatabaseLock) {
count = db.update(Statuses.TABLE, values, selection, selectionArgs);
}
break;
case ENTITIES:
// encrypt the data
sonetCrypto = SonetCrypto.getInstance(getContext());
if (values.containsKey(Entity.ESID)) {
values.put(Entity.ESID, sonetCrypto.Encrypt(values.getAsString(Entity.ESID)));
}
synchronized (Eidos.DatabaseLock) {
count = db.update(Entity.TABLE, values, selection, selectionArgs);
}
break;
case NOTIFICATIONS:
// encrypt the data
sonetCrypto = SonetCrypto.getInstance(getContext());
if (values.containsKey(Notifications.SID)) {
values.put(Notifications.SID, sonetCrypto.Encrypt(values.getAsString(Notifications.SID)));
}
if (values.containsKey(Notifications.ESID)) {
values.put(Notifications.ESID, sonetCrypto.Encrypt(values.getAsString(Notifications.ESID)));
}
synchronized (Eidos.DatabaseLock) {
count = db.update(Notifications.TABLE, values, selection, selectionArgs);
}
break;
case STATUS_LINKS:
synchronized (Eidos.DatabaseLock) {
count = db.update(StatusLinks.TABLE, values, selection, selectionArgs);
}
break;
case STATUS_IMAGES:
synchronized (Eidos.DatabaseLock) {
count = db.update(StatusImages.TABLE, values, selection, selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
private static class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
Accounts.createTable(db);
WidgetAccounts.createTable(db);
WidgetAccountsView.createView(db);
Widgets.createTable(db);
Statuses.createTable(db);
Entity.createTable(db);
Notifications.createTable(db);
StatusLinks.createTable(db);
StatusImages.createTable(db);
StatusesStyles.createView(db);
WidgetsSettings.createView(db);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// aliases used for addCase
String[] aliases = new String[] { "a", "b", "c" };
if (oldVersion < 2) {
// add column for expiry
DatabaseUtils.growTable(db, Accounts.TABLE, Accounts.EXPIRY, "integer", "", true);
}
if (oldVersion < 3) {
// remove not null constraints as facebook uses oauth2 and doesn't require a secret, add timezone
db.execSQL("drop table if exists " + Accounts.TABLE + "_bkp;");
db.execSQL("create temp table " + Accounts.TABLE + "_bkp as select * from " + Accounts.TABLE + ";");
db.execSQL("drop table if exists " + Accounts.TABLE + ";");
db.execSQL("create table if not exists " + Accounts.TABLE
+ " (" + Accounts._ID + " integer primary key autoincrement, "
+ Accounts.USERNAME + " text, "
+ Accounts.TOKEN + " text, "
+ Accounts.SECRET + " text, "
+ Accounts.SERVICE + " integer, "
+ Accounts.EXPIRY + " integer, "
+ "timezone integer);");
db.execSQL(
"insert into " + Accounts.TABLE + " select " + Accounts._ID + "," + Accounts.USERNAME + "," + Accounts.TOKEN + "," +
Accounts.SECRET + "," + Accounts.SERVICE + "," + Accounts.EXPIRY + ",\"\" from " + Accounts.TABLE + "_bkp;");
db.execSQL("drop table if exists " + Accounts.TABLE + "_bkp;");
}
if (oldVersion < 4) {
// add column for widget
DatabaseUtils.growTable(db, Accounts.TABLE, "widget", "integer", "", true);
// move preferences to db
db.execSQL("create table if not exists " + Widgets.TABLE
+ " (" + Widgets._ID + " integer primary key autoincrement, "
+ Widgets.WIDGET + " integer, "
+ Widgets.INTERVAL + " integer, "
+ Widgets.TIME24HR + " integer);");
}
if (oldVersion < 5) {
// cache for statuses
db.execSQL("create table if not exists " + Statuses.TABLE
+ " (" + Statuses._ID + " integer primary key autoincrement, "
+ Statuses.CREATED + " integer, "
+ "link text, "
+ "friend text, "
+ "profile blob, "
+ Statuses.MESSAGE + " text, "
+ Statuses.SERVICE + " integer, "
+ Statuses.CREATEDTEXT + " text, "
+ Statuses.WIDGET + " integer);");
}
if (oldVersion < 6) {
// NO-OP textsize columns removed in version 28
}
if (oldVersion < 7) {
// add column for account to handle account specific widget settings
DatabaseUtils.growTable(db, Widgets.TABLE, Widgets.ACCOUNT, "integer", Long.toString(Sonet.INVALID_ACCOUNT_ID), false);
// add column for status background and rename createdText > createdtext
db.execSQL("create temp table " + Statuses.TABLE + "_bkp as select * from " + Statuses.TABLE + ";");
db.execSQL("drop table if exists " + Statuses.TABLE + ";");
db.execSQL("create table if not exists " + Statuses.TABLE
+ " (" + Statuses._ID + " integer primary key autoincrement, "
+ Statuses.CREATED + " integer, "
+ "link text, "
+ "friend text, "
+ "profile blob, "
+ Statuses.MESSAGE + " text, "
+ Statuses.SERVICE + " integer, "
+ Statuses.CREATEDTEXT + " text, "
+ Statuses.WIDGET + " integer, "
+ Statuses.ACCOUNT + " integer);");
db.execSQL("insert into " + Statuses.TABLE
+ " select "
+ Statuses._ID + ","
+ Statuses.CREATED + ","
+ "link,"
+ "profile,"
+ Statuses.MESSAGE + ","
+ Statuses.SERVICE + ","
+ "createdText,"
+ Statuses.WIDGET + ","
+ Sonet.INVALID_ACCOUNT_ID + ",null from " + Statuses.TABLE + "_bkp;");
db.execSQL("drop table if exists " + Statuses.TABLE + "_bkp;");
// create a view for the statuses and account/widget/default styles
StatusesStyles.createView(db);
}
if (oldVersion < 8) {
// change the view to be more efficient
db.execSQL("drop view if exists " + StatusesStyles.VIEW + ";");
StatusesStyles.createView(db);
}
if (oldVersion < 9) {
// support additional timezones, with partial hour increments
// change timezone column from integer to real
db.execSQL("drop table if exists " + Accounts.TABLE + "_bkp;");
db.execSQL("create temp table " + Accounts.TABLE + "_bkp as select * from " + Accounts.TABLE + ";");
db.execSQL("drop table if exists " + Accounts.TABLE + ";");
db.execSQL("create table if not exists " + Accounts.TABLE
+ " (" + Accounts._ID + " integer primary key autoincrement, "
+ Accounts.USERNAME + " text, "
+ Accounts.TOKEN + " text, "
+ Accounts.SECRET + " text, "
+ Accounts.SERVICE + " integer, "
+ Accounts.EXPIRY + " integer, "
+ "timezone real, "
+ "widget integer);");
db.execSQL("insert into " + Accounts.TABLE
+ " select "
+ Accounts._ID + ","
+ Accounts.USERNAME + ","
+ Accounts.TOKEN + ","
+ Accounts.SECRET + ","
+ Accounts.SERVICE + ","
+ Accounts.EXPIRY + ","
+ "timezone,"
+ "widget from " + Accounts.TABLE + "_bkp;");
db.execSQL("drop table if exists " + Accounts.TABLE + "_bkp;");
}
if (oldVersion < 10) {
// NO-OP icons removed in version 28
}
if (oldVersion < 11) {
// using device timezone, doesn't need to be stored now
db.execSQL("drop table if exists " + Accounts.TABLE + "_bkp;");
db.execSQL("create temp table " + Accounts.TABLE + "_bkp as select * from " + Accounts.TABLE + ";");
db.execSQL("drop table if exists " + Accounts.TABLE + ";");
db.execSQL("create table if not exists " + Accounts.TABLE
+ " (" + Accounts._ID + " integer primary key autoincrement, "
+ Accounts.USERNAME + " text, "
+ Accounts.TOKEN + " text, "
+ Accounts.SECRET + " text, "
+ Accounts.SERVICE + " integer, "
+ Accounts.EXPIRY + " integer, "
+ "widget integer);");
db.execSQL("insert into " + Accounts.TABLE
+ " select "
+ Accounts._ID + ","
+ Accounts.USERNAME + ","
+ Accounts.TOKEN + ","
+ Accounts.SECRET + ","
+ Accounts.SERVICE + ","
+ Accounts.EXPIRY + ","
+ "widget from " + Accounts.TABLE + "_bkp;");
db.execSQL("drop table if exists " + Accounts.TABLE + "_bkp;");
}
if (oldVersion < 12) {
// store the service id's for posting and linking
db.execSQL("drop table if exists " + Accounts.TABLE + "_bkp;");
db.execSQL("create temp table " + Accounts.TABLE + "_bkp as select * from " + Accounts.TABLE + ";");
db.execSQL("drop table if exists " + Accounts.TABLE + ";");
db.execSQL("create table if not exists " + Accounts.TABLE
+ " (" + Accounts._ID + " integer primary key autoincrement, "
+ Accounts.USERNAME + " text, "
+ Accounts.TOKEN + " text, "
+ Accounts.SECRET + " text, "
+ Accounts.SERVICE + " integer, "
+ Accounts.EXPIRY + " integer, "
+ "widget integer, "
+ Accounts.SID + " integer);");
db.execSQL("insert into " + Accounts.TABLE
+ " select "
+ Accounts._ID + ","
+ Accounts.USERNAME + ","
+ Accounts.TOKEN + ","
+ Accounts.SECRET + ","
+ Accounts.SERVICE + ","
+ Accounts.EXPIRY + ","
+ "widget,\"\" from " + Accounts.TABLE + "_bkp;");
db.execSQL("drop table if exists " + Accounts.TABLE + "_bkp;");
db.execSQL("drop table if exists " + Statuses.TABLE + "_bkp;");
db.execSQL("create temp table " + Statuses.TABLE + "_bkp as select * from " + Statuses.TABLE + ";");
DatabaseUtils.growTable(db, Statuses.TABLE, Statuses.SID, "integer", "", true);
DatabaseUtils.growTable(db, Statuses.TABLE, Statuses.ENTITY, "integer", "", true);
db.execSQL("create table if not exists " + Entity.TABLE
+ " (" + Entity._ID + " integer primary key autoincrement, "
+ Entity.FRIEND + " text, "
+ Entity.ACCOUNT + " integer, "
+ Entity.ESID + " text);");
Cursor from_bkp = db.query(Statuses.TABLE + "_bkp", new String[] { Statuses._ID, "friend", "profile" }, null, null, null, null, null);
if (from_bkp.moveToFirst()) {
int iid = from_bkp.getColumnIndex(Statuses._ID);
int ifriend = from_bkp.getColumnIndex("friend");
while (!from_bkp.isAfterLast()) {
ContentValues values = new ContentValues();
values.put(Entity.FRIEND, from_bkp.getString(ifriend));
int id = (int) db.insert(Entity.TABLE, Entity._ID, values);
values = new ContentValues();
values.put(Statuses.ENTITY, id);
db.update(Statuses.TABLE, values, Statuses._ID + "=?", new String[] { Integer.toString(from_bkp.getInt(iid)) });
from_bkp.moveToNext();
}
}
from_bkp.close();
db.execSQL("drop table if exists " + Statuses.TABLE + "_bkp;");
db.execSQL("drop view if exists " + StatusesStyles.VIEW + ";");
StatusesStyles.createView(db);
// background updating option
DatabaseUtils.growTable(db, Widgets.TABLE, Widgets.BACKGROUND_UPDATE, "integer", "1", false);
}
if (oldVersion < 13) {
// NO-OP scrollable removed in version 28
}
if (oldVersion < 14) {
// need to redesign the accounts table so that multiple widgets can use the same accounts
db.execSQL("create table if not exists " + WidgetAccounts.TABLE
+ " (" + WidgetAccounts._ID + " integer primary key autoincrement, "
+ WidgetAccounts.ACCOUNT + " integer, "
+ WidgetAccounts.WIDGET + " integer);");
// migrate accounts over to widget_accounts
db.execSQL("drop table if exists " + Accounts.TABLE + "_bkp;");
db.execSQL("create temp table " + Accounts.TABLE + "_bkp as select * from " + Accounts.TABLE + ";");
db.execSQL("drop table if exists " + Accounts.TABLE + ";");
db.execSQL("create table if not exists " + Accounts.TABLE
+ " (" + Accounts._ID + " integer primary key autoincrement, "
+ Accounts.USERNAME + " text, "
+ Accounts.TOKEN + " text, "
+ Accounts.SECRET + " text, "
+ Accounts.SERVICE + " integer, "
+ Accounts.EXPIRY + " integer, "
+ Accounts.SID + " text);");
Cursor accounts = db.query(Accounts.TABLE + "_bkp",
new String[] { Accounts._ID,
Accounts.USERNAME,
Accounts.TOKEN,
Accounts.SECRET,
Accounts.SERVICE,
Accounts.EXPIRY,
"widget",
Accounts.SID },
null,
null,
null,
null,
null);
if (accounts.moveToFirst()) {
int iid = accounts.getColumnIndex(Accounts._ID),
iusername = accounts.getColumnIndex(Accounts.USERNAME),
itoken = accounts.getColumnIndex(Accounts.TOKEN),
isecret = accounts.getColumnIndex(Accounts.SECRET),
iservice = accounts.getColumnIndex(Accounts.SERVICE),
iexpiry = accounts.getColumnIndex(Accounts.EXPIRY),
iwidget = accounts.getColumnIndex("widget"),
isid = accounts.getColumnIndex(Accounts.SID);
while (!accounts.isAfterLast()) {
ContentValues values = new ContentValues();
values.put(WidgetAccounts.ACCOUNT, accounts.getLong(iid));
values.put(WidgetAccounts.WIDGET, accounts.getInt(iwidget));
db.insert(WidgetAccounts.TABLE, WidgetAccounts._ID, values);
values.clear();
values.put(Accounts._ID, accounts.getLong(iid));
values.put(Accounts.USERNAME, accounts.getString(iusername));
values.put(Accounts.TOKEN, accounts.getString(itoken));
values.put(Accounts.SECRET, accounts.getString(isecret));
values.put(Accounts.SERVICE, accounts.getString(iservice));
values.put(Accounts.EXPIRY, accounts.getLong(iexpiry));
values.put(Accounts.SID, accounts.getString(isid));
db.insert(Accounts.TABLE, Accounts._ID, values);
accounts.moveToNext();
}
}
accounts.close();
db.execSQL("drop table if exists " + Accounts.TABLE + "_bkp;");
db.execSQL("create view if not exists " + WidgetAccountsView.VIEW + " as select "
+ WidgetAccounts.TABLE + "." + WidgetAccounts._ID
+ "," + WidgetAccounts.ACCOUNT
+ "," + WidgetAccounts.WIDGET
+ "," + Accounts.EXPIRY
+ "," + Accounts.SECRET
+ "," + Accounts.SERVICE
+ "," + Accounts.SID
+ "," + Accounts.TOKEN
+ "," + Accounts.USERNAME
+ " from "
+ WidgetAccounts.TABLE
+ "," + Accounts.TABLE
+ " where "
+ Accounts.TABLE + "." + Accounts._ID + "=" + WidgetAccounts.ACCOUNT
+ ";");
}
if (oldVersion < 15) {
DatabaseUtils.growTable(db, Widgets.TABLE, Widgets.SOUND, "integer", "0", false);
DatabaseUtils.growTable(db, Widgets.TABLE, Widgets.VIBRATE, "integer", "0", false);
DatabaseUtils.growTable(db, Widgets.TABLE, Widgets.LIGHTS, "integer", "0", false);
// notifications
db.execSQL("create table if not exists " + Notifications.TABLE
+ " (" + Notifications._ID + " integer primary key autoincrement, "
+ Notifications.SID + " text, "
+ Notifications.ESID + " text, "
+ Notifications.FRIEND + " text, "
+ Notifications.MESSAGE + " text, "
+ Notifications.CREATED + " integer, "
+ Notifications.NOTIFICATION + " text, "
+ Notifications.ACCOUNT + " integer, "
+ Notifications.CLEARED + " integer);");
// allow friend name override in cases of facebook wall posts
DatabaseUtils.growTable(db, Statuses.TABLE, Statuses.FRIEND_OVERRIDE, "text", "null", false);
db.execSQL("drop view if exists " + StatusesStyles.VIEW + ";");
StatusesStyles.createView(db);
}
if (oldVersion < 16) {
// create a view for the widget settings
db.execSQL("create view if not exists " + WidgetsSettings.VIEW + " as select a."
+ Widgets._ID + " as " + Widgets._ID
+ ",a." + Widgets.WIDGET + " as " + Widgets.WIDGET
+ "," + DatabaseUtils.addCase(aliases, Widgets.INTERVAL, Sonet.default_interval, Widgets.INTERVAL)
+ "," + DatabaseUtils.addCase(aliases, Widgets.TIME24HR, 0, Widgets.TIME24HR)
+ ",a." + Widgets.ACCOUNT + " as " + Widgets.ACCOUNT
+ "," + DatabaseUtils.addCase(aliases, Widgets.BACKGROUND_UPDATE, 1, Widgets.BACKGROUND_UPDATE)
+ "," + DatabaseUtils.addCase(aliases, Widgets.SOUND, 0, Widgets.SOUND)
+ "," + DatabaseUtils.addCase(aliases, Widgets.VIBRATE, 0, Widgets.VIBRATE)
+ "," + DatabaseUtils.addCase(aliases, Widgets.LIGHTS, 0, Widgets.LIGHTS)
+ " from " + Widgets.TABLE + " a,"
+ Widgets.TABLE + " b,"
+ Widgets.TABLE + " c WHERE b." + Widgets.WIDGET + "=a." + Widgets.WIDGET + " and b." + Widgets.ACCOUNT + "=-1 and c." +
Widgets.WIDGET + "=0 and c." + Widgets.ACCOUNT + "=-1;");
}
if (oldVersion < 17) {
// add updated column, this will clear all current notifications, to avoid duplicates
db.execSQL("drop table if exists " + Notifications.TABLE + ";");
db.execSQL("create table if not exists " + Notifications.TABLE
+ " (" + Notifications._ID + " integer primary key autoincrement, "
+ Notifications.SID + " text, "
+ Notifications.ESID + " text, "
+ Notifications.FRIEND + " text, "
+ Notifications.MESSAGE + " text, "
+ Notifications.CREATED + " integer, "
+ Notifications.NOTIFICATION + " text, "
+ Notifications.ACCOUNT + " integer, "
+ Notifications.CLEARED + " integer, "
+ Notifications.UPDATED + " integer);");
// update statuses view to account for the new default settings handling
db.execSQL("drop table if exists " + Statuses.TABLE + "_bkp;");
db.execSQL("drop view if exists " + StatusesStyles.VIEW + ";");
StatusesStyles.createView(db);
}
if (oldVersion < 18) {
// an error was reported where the updated column wasn't added, attempt to verify that the last database update went through
boolean update = false;
Cursor c = db.rawQuery("select sql from sqlite_master where name='notifications';", null);
if (c.moveToFirst()) {
String sql = c.getString(0);
if (!sql.contains(Notifications.UPDATED)) {
update = true;
}
} else {
update = true;
}
c.close();
if (update) {
// add updated column, this will clear all current notifications, to avoid duplicates
db.execSQL("drop table if exists " + Notifications.TABLE + ";");
db.execSQL("create table if not exists " + Notifications.TABLE
+ " (" + Notifications._ID + " integer primary key autoincrement, "
+ Notifications.SID + " text, "
+ Notifications.ESID + " text, "
+ Notifications.FRIEND + " text, "
+ Notifications.MESSAGE + " text, "
+ Notifications.CREATED + " integer, "
+ Notifications.NOTIFICATION + " text, "
+ Notifications.ACCOUNT + " integer, "
+ Notifications.CLEARED + " integer, "
+ Notifications.UPDATED + " integer);");
// update statuses view to account for the new default settings handling
db.execSQL("drop table if exists " + Statuses.TABLE + "_bkp;");
db.execSQL("drop view if exists " + StatusesStyles.VIEW + ";");
StatusesStyles.createView(db);
}
}
if (oldVersion < 19) {
// add support for instant upload
DatabaseUtils.growTable(db, Widgets.TABLE, Widgets.INSTANT_UPLOAD, "integer", "0", false);
db.execSQL("drop view if exists " + WidgetsSettings.VIEW + ";");
db.execSQL("create view if not exists " + WidgetsSettings.VIEW + " as select a."
+ Widgets._ID + " as " + Widgets._ID
+ ",a." + Widgets.WIDGET + " as " + Widgets.WIDGET
+ "," + DatabaseUtils.addCase(aliases, Widgets.INTERVAL, Sonet.default_interval, Widgets.INTERVAL)
+ "," + DatabaseUtils.addCase(aliases, Widgets.TIME24HR, 0, Widgets.TIME24HR)
+ ",a." + Widgets.ACCOUNT + " as " + Widgets.ACCOUNT
+ "," + DatabaseUtils.addCase(aliases, Widgets.BACKGROUND_UPDATE, 1, Widgets.BACKGROUND_UPDATE)
+ "," + DatabaseUtils.addCase(aliases, Widgets.SOUND, 0, Widgets.SOUND)
+ "," + DatabaseUtils.addCase(aliases, Widgets.VIBRATE, 0, Widgets.VIBRATE)
+ "," + DatabaseUtils.addCase(aliases, Widgets.LIGHTS, 0, Widgets.LIGHTS)
+ "," + DatabaseUtils.addCase(aliases, Widgets.INSTANT_UPLOAD, 0, Widgets.INSTANT_UPLOAD)
+ " from " + Widgets.TABLE + " a,"
+ Widgets.TABLE + " b,"
+ Widgets.TABLE + " c WHERE b." + Widgets.WIDGET + "=a." + Widgets.WIDGET + " and b." + Widgets.ACCOUNT + "=-1 and c." +
Widgets.WIDGET + "=0 and c." + Widgets.ACCOUNT + "=-1;");
}
if (oldVersion < 20) {
// move instant upload setting from account specific to widget specific
Cursor c = db
.query(Widgets.TABLE, new String[] { Widgets.WIDGET }, Widgets.ACCOUNT + "!=-1 and " + Widgets.INSTANT_UPLOAD + "=1", null,
null, null, null);
if (c.moveToFirst()) {
while (!c.isAfterLast()) {
ContentValues values = new ContentValues();
values.put(Widgets.INSTANT_UPLOAD, 1);
db.update(Widgets.TABLE,
values,
Widgets.WIDGET + "=? and " + Widgets.ACCOUNT + "=-1",
new String[] { Integer.toString(c.getInt(0)) });
c.moveToNext();
}
}
c.close();
}
if (oldVersion < 21) {
// update wasn't added in onCreate, patch it up
boolean update = false;
Cursor c = db.rawQuery("select sql from sqlite_master where name='notifications';", null);
if (c.moveToFirst()) {
String sql = c.getString(0);
if (!sql.contains(Notifications.UPDATED)) {
update = true;
}
} else {
update = true;
}
c.close();
if (update) {
// add updated column, this will clear all current notifications, to avoid duplicates
db.execSQL("drop table if exists " + Notifications.TABLE + "_bkp;");
db.execSQL("create temp table " + Notifications.TABLE + "_bkp as select * from " + Notifications.TABLE + ";");
db.execSQL("drop table if exists " + Notifications.TABLE + ";");
db.execSQL("create table if not exists " + Notifications.TABLE
+ " (" + Notifications._ID + " integer primary key autoincrement, "
+ Notifications.SID + " text, "
+ Notifications.ESID + " text, "
+ Notifications.FRIEND + " text, "
+ Notifications.MESSAGE + " text, "
+ Notifications.CREATED + " integer, "
+ Notifications.NOTIFICATION + " text, "
+ Notifications.ACCOUNT + " integer, "
+ Notifications.CLEARED + " integer, "
+ Notifications.UPDATED + " integer);");
db.execSQL("insert into " + Notifications.TABLE
+ " select "
+ Notifications._ID
+ "," + Notifications.SID
+ "," + Notifications.ESID
+ "," + Notifications.FRIEND
+ "," + Notifications.MESSAGE
+ "," + Notifications.CREATED
+ "," + Notifications.NOTIFICATION
+ "," + Notifications.ACCOUNT
+ "," + Notifications.CLEARED
+ "," + Notifications.CREATED + " from " + Notifications.TABLE + "_bkp;");
db.execSQL("drop table if exists " + Notifications.TABLE + "_bkp;");
}
}
if (oldVersion < 22) {
db.execSQL("create table if not exists " + StatusLinks.TABLE
+ " (" + StatusLinks._ID + " integer primary key autoincrement, "
+ StatusLinks.STATUS_ID + " integer, "
+ StatusLinks.LINK_URI + " text, "
+ StatusLinks.LINK_TYPE + " text);");
}
if (oldVersion < 23) {
// clean up duplicate widget settings
Cursor c = db.query(Widgets.TABLE,
new String[] { Widgets._ID },
Widgets.WIDGET + "=0 and " + Widgets.ACCOUNT + "=-1",
null,
null,
null,
null);
if (c.moveToFirst()) {
if (c.moveToNext()) {
while (!c.isAfterLast()) {
db.delete(Widgets.TABLE, Widgets._ID + "=?", new String[] { Long.toString(c.getLong(0)) });
c.moveToNext();
}
}
}
c.close();
}
if (oldVersion < 24) {
db.execSQL("drop view if exists " + StatusesStyles.VIEW + ";");
StatusesStyles.createView(db);
db.execSQL("drop view if exists " + WidgetsSettings.VIEW + ";");
db.execSQL("create view if not exists " + WidgetsSettings.VIEW + " as select a."
+ Widgets._ID + " as " + Widgets._ID
+ ",a." + Widgets.WIDGET + " as " + Widgets.WIDGET
+ "," + DatabaseUtils.addCase(aliases, Widgets.INTERVAL, Sonet.default_interval, Widgets.INTERVAL)
+ "," + DatabaseUtils.addCase(aliases, Widgets.TIME24HR, 0, Widgets.TIME24HR)
+ ",a." + Widgets.ACCOUNT + " as " + Widgets.ACCOUNT
+ "," + DatabaseUtils.addCase(aliases, Widgets.BACKGROUND_UPDATE, 1, Widgets.BACKGROUND_UPDATE)
+ "," + DatabaseUtils.addCase(aliases, Widgets.SOUND, 0, Widgets.SOUND)
+ "," + DatabaseUtils.addCase(aliases, Widgets.VIBRATE, 0, Widgets.VIBRATE)
+ "," + DatabaseUtils.addCase(aliases, Widgets.LIGHTS, 0, Widgets.LIGHTS)
+ "," + DatabaseUtils.addCase(aliases, Widgets.INSTANT_UPLOAD, 0, Widgets.INSTANT_UPLOAD)
+ " from " + Widgets.TABLE + " a,"
+ Widgets.TABLE + " b,"
+ Widgets.TABLE + " c WHERE b." + Widgets.WIDGET + "=a." + Widgets.WIDGET + " and b." + Widgets.ACCOUNT + "=-1 and c." +
Widgets.WIDGET + "=0 and c." + Widgets.ACCOUNT + "=-1;");
}
if (oldVersion < 25) {
db.execSQL("drop view if exists " + StatusesStyles.VIEW + ";");
StatusesStyles.createView(db);
db.execSQL("drop view if exists " + WidgetsSettings.VIEW + ";");
// create a view for the widget settings
db.execSQL("create view if not exists " + WidgetsSettings.VIEW + " as select a."
+ Widgets._ID + " as " + Widgets._ID
+ ",a." + Widgets.WIDGET + " as " + Widgets.WIDGET
+ "," + DatabaseUtils.addCase(aliases, Widgets.INTERVAL, Sonet.default_interval, Widgets.INTERVAL)
+ "," + DatabaseUtils.addCase(aliases, Widgets.TIME24HR, 0, Widgets.TIME24HR)
+ ",a." + Widgets.ACCOUNT + " as " + Widgets.ACCOUNT
+ "," + DatabaseUtils.addCase(aliases, Widgets.BACKGROUND_UPDATE, 1, Widgets.BACKGROUND_UPDATE)
+ "," + DatabaseUtils.addCase(aliases, Widgets.SOUND, 0, Widgets.SOUND)
+ "," + DatabaseUtils.addCase(aliases, Widgets.VIBRATE, 0, Widgets.VIBRATE)
+ "," + DatabaseUtils.addCase(aliases, Widgets.LIGHTS, 0, Widgets.LIGHTS)
+ "," + DatabaseUtils.addCase(aliases, Widgets.INSTANT_UPLOAD, 0, Widgets.INSTANT_UPLOAD)
+ " from " + Widgets.TABLE + " a,"
+ Widgets.TABLE + " b,"
+ Widgets.TABLE + " c WHERE b." + Widgets.WIDGET + "=a." + Widgets.WIDGET + " and b." + Widgets.ACCOUNT + "=-1 and c." +
Widgets.WIDGET + "=0 and c." + Widgets.ACCOUNT + "=-1;");
}
if (oldVersion < 26) {
db.execSQL("drop table if exists " + StatusImages.TABLE + ";");
db.execSQL("create table if not exists " + StatusImages.TABLE
+ " (" + StatusImages._ID + " integer primary key autoincrement, "
+ StatusImages.STATUS_ID + " integer);");
db.execSQL("drop view if exists " + StatusesStyles.VIEW + ";");
StatusesStyles.createView(db);
}
// 27, 28, 29 were used during development
// add profile_url
if (oldVersion < 30) {
DatabaseUtils.growTable(db,
Entity.TABLE,
Entity.PROFILE_URL,
"text",
"null",
false);
// drop Entity.PROFILE blob
Entity.migrateTable(db);
// drop styles columns
Widgets.migrateTable(db);
db.execSQL("drop view if exists " + WidgetsSettings.VIEW + ";");
WidgetsSettings.createView(db);
// add url
DatabaseUtils.growTable(db,
StatusImages.TABLE,
StatusImages.URL,
"text",
"null",
false);
// drop the image blob
StatusImages.migrateTable(db);
Statuses.migrateTable(db);
db.execSQL("drop view if exists " + StatusesStyles.VIEW + ";");
StatusesStyles.createView(db);
}
// remove widget dependency for accounts
if (oldVersion < 31) {
db.execSQL("drop view if exists " + StatusesStyles.VIEW + ";");
StatusesStyles.createView(db);
}
}
}
}