DatabaseBackend.java

  1package eu.siacs.conversations.persistance;
  2
  3import java.util.ArrayList;
  4import java.util.List;
  5import java.util.concurrent.CopyOnWriteArrayList;
  6
  7import eu.siacs.conversations.entities.Account;
  8import eu.siacs.conversations.entities.Contact;
  9import eu.siacs.conversations.entities.Conversation;
 10import eu.siacs.conversations.entities.Message;
 11import eu.siacs.conversations.entities.Roster;
 12import android.content.Context;
 13import android.database.Cursor;
 14import android.database.sqlite.SQLiteDatabase;
 15import android.database.sqlite.SQLiteOpenHelper;
 16import android.util.Log;
 17
 18public class DatabaseBackend extends SQLiteOpenHelper {
 19
 20	private static DatabaseBackend instance = null;
 21
 22	private static final String DATABASE_NAME = "history";
 23	private static final int DATABASE_VERSION = 7;
 24
 25	private static String CREATE_CONTATCS_STATEMENT = "create table "
 26			+ Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, "
 27			+ Contact.SERVERNAME + " TEXT, " + Contact.SYSTEMNAME + " TEXT,"
 28			+ Contact.JID + " TEXT," + Contact.KEYS + " TEXT,"
 29			+ Contact.PHOTOURI + " TEXT," + Contact.OPTIONS + " NUMBER,"
 30			+ Contact.SYSTEMACCOUNT + " NUMBER, " + Contact.AVATAR + " TEXT, "
 31			+ "FOREIGN KEY(" + Contact.ACCOUNT + ") REFERENCES "
 32			+ Account.TABLENAME + "(" + Account.UUID
 33			+ ") ON DELETE CASCADE, UNIQUE(" + Contact.ACCOUNT + ", "
 34			+ Contact.JID + ") ON CONFLICT REPLACE);";
 35
 36	public DatabaseBackend(Context context) {
 37		super(context, DATABASE_NAME, null, DATABASE_VERSION);
 38	}
 39
 40	@Override
 41	public void onCreate(SQLiteDatabase db) {
 42		db.execSQL("PRAGMA foreign_keys=ON;");
 43		db.execSQL("create table " + Account.TABLENAME + "(" + Account.UUID
 44				+ " TEXT PRIMARY KEY," + Account.USERNAME + " TEXT,"
 45				+ Account.SERVER + " TEXT," + Account.PASSWORD + " TEXT,"
 46				+ Account.ROSTERVERSION + " TEXT," + Account.OPTIONS
 47				+ " NUMBER, " + Account.AVATAR + " TEXT, " + Account.KEYS
 48				+ " TEXT)");
 49		db.execSQL("create table " + Conversation.TABLENAME + " ("
 50				+ Conversation.UUID + " TEXT PRIMARY KEY, " + Conversation.NAME
 51				+ " TEXT, " + Conversation.CONTACT + " TEXT, "
 52				+ Conversation.ACCOUNT + " TEXT, " + Conversation.CONTACTJID
 53				+ " TEXT, " + Conversation.CREATED + " NUMBER, "
 54				+ Conversation.STATUS + " NUMBER," + Conversation.MODE
 55				+ " NUMBER," + "FOREIGN KEY(" + Conversation.ACCOUNT
 56				+ ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID
 57				+ ") ON DELETE CASCADE);");
 58		db.execSQL("create table " + Message.TABLENAME + "( " + Message.UUID
 59				+ " TEXT PRIMARY KEY, " + Message.CONVERSATION + " TEXT, "
 60				+ Message.TIME_SENT + " NUMBER, " + Message.COUNTERPART
 61				+ " TEXT, " + Message.TRUE_COUNTERPART + " TEXT,"
 62				+ Message.BODY + " TEXT, " + Message.ENCRYPTION + " NUMBER, "
 63				+ Message.STATUS + " NUMBER," + Message.TYPE + " NUMBER, "
 64				+ Message.REMOTE_MSG_ID + " TEXT, FOREIGN KEY("
 65				+ Message.CONVERSATION + ") REFERENCES "
 66				+ Conversation.TABLENAME + "(" + Conversation.UUID
 67				+ ") ON DELETE CASCADE);");
 68
 69		db.execSQL(CREATE_CONTATCS_STATEMENT);
 70	}
 71
 72	@Override
 73	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
 74		if (oldVersion < 2 && newVersion >= 2) {
 75			db.execSQL("update " + Account.TABLENAME + " set "
 76					+ Account.OPTIONS + " = " + Account.OPTIONS + " | 8");
 77		}
 78		if (oldVersion < 3 && newVersion >= 3) {
 79			db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN "
 80					+ Message.TYPE + " NUMBER");
 81		}
 82		if (oldVersion < 5 && newVersion >= 5) {
 83			db.execSQL("DROP TABLE " + Contact.TABLENAME);
 84			db.execSQL(CREATE_CONTATCS_STATEMENT);
 85			db.execSQL("UPDATE " + Account.TABLENAME + " SET "
 86					+ Account.ROSTERVERSION + " = NULL");
 87		}
 88		if (oldVersion < 6 && newVersion >= 6) {
 89			db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN "
 90					+ Message.TRUE_COUNTERPART + " TEXT");
 91		}
 92		if (oldVersion < 7 && newVersion >= 7) {
 93			db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN "
 94					+ Message.REMOTE_MSG_ID + " TEXT");
 95			db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN "
 96					+ Contact.AVATAR + " TEXT");
 97			db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN "
 98					+ Account.AVATAR + " TEXT");
 99		}
100	}
101
102	public static synchronized DatabaseBackend getInstance(Context context) {
103		if (instance == null) {
104			instance = new DatabaseBackend(context);
105		}
106		return instance;
107	}
108
109	public void createConversation(Conversation conversation) {
110		SQLiteDatabase db = this.getWritableDatabase();
111		db.insert(Conversation.TABLENAME, null, conversation.getContentValues());
112	}
113
114	public void createMessage(Message message) {
115		SQLiteDatabase db = this.getWritableDatabase();
116		db.insert(Message.TABLENAME, null, message.getContentValues());
117	}
118
119	public void createAccount(Account account) {
120		SQLiteDatabase db = this.getWritableDatabase();
121		db.insert(Account.TABLENAME, null, account.getContentValues());
122	}
123
124	public void createContact(Contact contact) {
125		SQLiteDatabase db = this.getWritableDatabase();
126		db.insert(Contact.TABLENAME, null, contact.getContentValues());
127	}
128
129	public int getConversationCount() {
130		SQLiteDatabase db = this.getReadableDatabase();
131		Cursor cursor = db.rawQuery("select count(uuid) as count from "
132				+ Conversation.TABLENAME + " where " + Conversation.STATUS
133				+ "=" + Conversation.STATUS_AVAILABLE, null);
134		cursor.moveToFirst();
135		return cursor.getInt(0);
136	}
137
138	public CopyOnWriteArrayList<Conversation> getConversations(int status) {
139		CopyOnWriteArrayList<Conversation> list = new CopyOnWriteArrayList<Conversation>();
140		SQLiteDatabase db = this.getReadableDatabase();
141		String[] selectionArgs = { "" + status };
142		Cursor cursor = db.rawQuery("select * from " + Conversation.TABLENAME
143				+ " where " + Conversation.STATUS + " = ? order by "
144				+ Conversation.CREATED + " desc", selectionArgs);
145		while (cursor.moveToNext()) {
146			list.add(Conversation.fromCursor(cursor));
147		}
148		return list;
149	}
150
151	public CopyOnWriteArrayList<Message> getMessages(
152			Conversation conversations, int limit) {
153		return getMessages(conversations, limit, -1);
154	}
155
156	public CopyOnWriteArrayList<Message> getMessages(Conversation conversation,
157			int limit, long timestamp) {
158		CopyOnWriteArrayList<Message> list = new CopyOnWriteArrayList<Message>();
159		SQLiteDatabase db = this.getReadableDatabase();
160		Cursor cursor;
161		if (timestamp == -1) {
162			String[] selectionArgs = { conversation.getUuid() };
163			cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION
164					+ "=?", selectionArgs, null, null, Message.TIME_SENT
165					+ " DESC", String.valueOf(limit));
166		} else {
167			String[] selectionArgs = { conversation.getUuid(), "" + timestamp };
168			cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION
169					+ "=? and " + Message.TIME_SENT + "<?", selectionArgs,
170					null, null, Message.TIME_SENT + " DESC",
171					String.valueOf(limit));
172		}
173		if (cursor.getCount() > 0) {
174			cursor.moveToLast();
175			do {
176				list.add(Message.fromCursor(cursor));
177			} while (cursor.moveToPrevious());
178		}
179		return list;
180	}
181
182	public Conversation findConversation(Account account, String contactJid) {
183		SQLiteDatabase db = this.getReadableDatabase();
184		String[] selectionArgs = { account.getUuid(), contactJid + "%" };
185		Cursor cursor = db.query(Conversation.TABLENAME, null,
186				Conversation.ACCOUNT + "=? AND " + Conversation.CONTACTJID
187						+ " like ?", selectionArgs, null, null, null);
188		if (cursor.getCount() == 0)
189			return null;
190		cursor.moveToFirst();
191		return Conversation.fromCursor(cursor);
192	}
193
194	public void updateConversation(Conversation conversation) {
195		SQLiteDatabase db = this.getWritableDatabase();
196		String[] args = { conversation.getUuid() };
197		db.update(Conversation.TABLENAME, conversation.getContentValues(),
198				Conversation.UUID + "=?", args);
199	}
200
201	public List<Account> getAccounts() {
202		List<Account> list = new ArrayList<Account>();
203		SQLiteDatabase db = this.getReadableDatabase();
204		Cursor cursor = db.query(Account.TABLENAME, null, null, null, null,
205				null, null);
206		Log.d("gultsch", "found " + cursor.getCount() + " accounts");
207		while (cursor.moveToNext()) {
208			list.add(Account.fromCursor(cursor));
209		}
210		return list;
211	}
212
213	public void updateAccount(Account account) {
214		SQLiteDatabase db = this.getWritableDatabase();
215		String[] args = { account.getUuid() };
216		db.update(Account.TABLENAME, account.getContentValues(), Account.UUID
217				+ "=?", args);
218	}
219
220	public void deleteAccount(Account account) {
221		SQLiteDatabase db = this.getWritableDatabase();
222		String[] args = { account.getUuid() };
223		db.delete(Account.TABLENAME, Account.UUID + "=?", args);
224	}
225
226	@Override
227	public SQLiteDatabase getWritableDatabase() {
228		SQLiteDatabase db = super.getWritableDatabase();
229		db.execSQL("PRAGMA foreign_keys=ON;");
230		return db;
231	}
232
233	public void updateMessage(Message message) {
234		SQLiteDatabase db = this.getWritableDatabase();
235		String[] args = { message.getUuid() };
236		db.update(Message.TABLENAME, message.getContentValues(), Message.UUID
237				+ "=?", args);
238	}
239
240	public void readRoster(Roster roster) {
241		SQLiteDatabase db = this.getReadableDatabase();
242		Cursor cursor;
243		String args[] = { roster.getAccount().getUuid() };
244		cursor = db.query(Contact.TABLENAME, null, Contact.ACCOUNT + "=?",
245				args, null, null, null);
246		while (cursor.moveToNext()) {
247			roster.initContact(Contact.fromCursor(cursor));
248		}
249	}
250
251	public void writeRoster(Roster roster) {
252		Account account = roster.getAccount();
253		SQLiteDatabase db = this.getWritableDatabase();
254		for (Contact contact : roster.getContacts()) {
255			if (contact.getOption(Contact.Options.IN_ROSTER)) {
256				db.insert(Contact.TABLENAME, null, contact.getContentValues());
257			} else {
258				String where = Contact.ACCOUNT + "=? AND " + Contact.JID + "=?";
259				String[] whereArgs = { account.getUuid(), contact.getJid() };
260				db.delete(Contact.TABLENAME, where, whereArgs);
261			}
262		}
263		account.setRosterVersion(roster.getVersion());
264		updateAccount(account);
265	}
266
267	public void deleteMessage(Message message) {
268		SQLiteDatabase db = this.getWritableDatabase();
269		String[] args = { message.getUuid() };
270		db.delete(Message.TABLENAME, Message.UUID + "=?", args);
271	}
272
273	public void deleteMessagesInConversation(Conversation conversation) {
274		SQLiteDatabase db = this.getWritableDatabase();
275		String[] args = { conversation.getUuid() };
276		db.delete(Message.TABLENAME, Message.CONVERSATION + "=?", args);
277	}
278
279	public Conversation findConversationByUuid(String conversationUuid) {
280		SQLiteDatabase db = this.getReadableDatabase();
281		String[] selectionArgs = { conversationUuid };
282		Cursor cursor = db.query(Conversation.TABLENAME, null,
283				Conversation.UUID + "=?", selectionArgs, null, null, null);
284		if (cursor.getCount() == 0) {
285			return null;
286		}
287		cursor.moveToFirst();
288		return Conversation.fromCursor(cursor);
289	}
290
291	public Message findMessageByUuid(String messageUuid) {
292		SQLiteDatabase db = this.getReadableDatabase();
293		String[] selectionArgs = { messageUuid };
294		Cursor cursor = db.query(Message.TABLENAME, null, Message.UUID + "=?",
295				selectionArgs, null, null, null);
296		if (cursor.getCount() == 0) {
297			return null;
298		}
299		cursor.moveToFirst();
300		return Message.fromCursor(cursor);
301	}
302
303	public Account findAccountByUuid(String accountUuid) {
304		SQLiteDatabase db = this.getReadableDatabase();
305		String[] selectionArgs = { accountUuid };
306		Cursor cursor = db.query(Account.TABLENAME, null, Account.UUID + "=?",
307				selectionArgs, null, null, null);
308		if (cursor.getCount() == 0) {
309			return null;
310		}
311		cursor.moveToFirst();
312		return Account.fromCursor(cursor);
313	}
314}