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