/*
* TeleStax, Open Source Cloud Communications
* Copyright 2011-2015, Telestax Inc and individual contributors
* by the @authors tag.
*
* This program is free software: you can redistribute it and/or modify
* under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
* For questions related to commercial use licensing, please contact sales@telestax.com.
*
*/
package org.restcomm.android.olympus;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
// Provides access to DB facilities
class DatabaseManager {
private static DatabaseManager instance = new DatabaseManager();
private static DatabaseHelper databaseHelper = null;
private static final String TAG = "DatabaseManager";
public static DatabaseManager getInstance()
{
return instance;
}
private DatabaseManager()
{
}
// Before we can use Database manager we need to first call open() and pass Android context
public void open(Context context)
{
if (databaseHelper == null) {
Log.i(TAG, "Database hasn't been opened; opening now");
// If this turns out to be slow, we might have to put it to background thread (AsyncTask, etc), but I think data are too little to cause us trouble
databaseHelper = new DatabaseHelper(context);
}
else {
Log.w(TAG, "Database is already open");
}
}
// ---- Contacts table
// Retrieve all contact entries from DB and return them
ArrayList<Map<String, String>> retrieveContacts()
{
if (databaseHelper == null) {
throw new RuntimeException("Database hasn't been opened yet, please call open()");
}
//SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
//qb.setTables(DatabaseContract.ContactEntry.TABLE_NAME);
// Define a projection that specifies which columns from the database
// you will actually use after this query.
String[] columns = {
DatabaseContract.ContactEntry.COLUMN_NAME_NAME,
DatabaseContract.ContactEntry.COLUMN_NAME_URI,
};
// How you want the results sorted in the resulting Cursor
//String sortOrder = DatabaseContract.ContactEntry.COLUMN_NAME_NAME + " ASC";
SQLiteDatabase db = databaseHelper.getReadableDatabase();
Cursor cursor = db.query(
DatabaseContract.ContactEntry.TABLE_NAME, // The table to query
columns, // The columns to return
null, // The columns for the WHERE clause
null, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
null // don't sort the results
);
ArrayList<Map<String, String>> contactList = new ArrayList<Map<String, String>>();
// moveToFirst() fails if cursor is empty
if (cursor.moveToFirst()) {
// iterate the rows, read from db and populate contactList
do {
contactList.add(createContactEntry(cursor.getString(cursor.getColumnIndexOrThrow(DatabaseContract.ContactEntry.COLUMN_NAME_NAME)),
cursor.getString(cursor.getColumnIndexOrThrow(DatabaseContract.ContactEntry.COLUMN_NAME_URI))));
} while (cursor.moveToNext());
}
cursor.close();
return contactList;
}
public void addContact(String name, String uri) throws SQLException
{
if (databaseHelper == null) {
throw new RuntimeException("Database hasn't been opened.");
}
// Gets the data repository in write mode
SQLiteDatabase db = databaseHelper.getWritableDatabase();
// Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
values.put(DatabaseContract.ContactEntry.COLUMN_NAME_NAME, name);
values.put(DatabaseContract.ContactEntry.COLUMN_NAME_URI, uri);
db.insertOrThrow(DatabaseContract.ContactEntry.TABLE_NAME, null, values);
}
/*
* Add contact if it doesn't exist already.
* @return true if contact didn't exist (and hence was added), false if it existed
*/
public boolean addContactIfNeded(String uri)
{
if (databaseHelper == null) {
throw new RuntimeException("Database hasn't been opened.");
}
String contactName = uri.replaceAll("^sip:", "").replaceAll("@.*$", "");
Cursor cursor = getContactFromName(contactName);
if (!cursor.moveToFirst()) {
// doesn't exist, need to create it
// Gets the data repository in write mode
SQLiteDatabase db = databaseHelper.getWritableDatabase();
// Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
values.put(DatabaseContract.ContactEntry.COLUMN_NAME_NAME, contactName);
values.put(DatabaseContract.ContactEntry.COLUMN_NAME_URI, contactName);
db.insertOrThrow(DatabaseContract.ContactEntry.TABLE_NAME, null, values);
return true;
}
return false;
}
// Important: currently contactName passed by Application is in reality the user part of the sipuri, so to match a contact entry
// we try with COLUMN_NAME_URI, not COLUMN_NAME_NAME
private int getContactIdFromName(String contactName)
{
Cursor cursor = getContactFromName(contactName);
/*
// Only interested in the ID
String[] columns = {
DatabaseContract.ContactEntry._ID,
};
// Add the WHERE clause
String selection = DatabaseContract.ContactEntry.COLUMN_NAME_URI + " LIKE ?";
String[] selectionArgs = { "%" + contactName + "%"};
SQLiteDatabase db = databaseHelper.getReadableDatabase();
Cursor cursor = db.query(
DatabaseContract.ContactEntry.TABLE_NAME, // The table to query
columns, // The columns to return
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
null, // don't sort the results
"1" // only keep one entry
);
*/
// moveToFirst() fails if cursor is empty
if (cursor.moveToFirst()) {
int contactId = cursor.getInt(cursor.getColumnIndexOrThrow(DatabaseContract.ContactEntry._ID));
return contactId;
}
else {
return -1;
}
}
// Important: currently contactName passed by Application is in reality the user part of the sipuri, so to match a contact entry
// we try with COLUMN_NAME_URI, not COLUMN_NAME_NAME
private Cursor getContactFromName(String contactName)
{
// Only interested in the ID
/*
String[] columns = {
DatabaseContract.ContactEntry._ID,
};
*/
// Add the WHERE clause
String selection = DatabaseContract.ContactEntry.COLUMN_NAME_URI + " LIKE ?";
String[] selectionArgs = { "%" + contactName + "%"};
SQLiteDatabase db = databaseHelper.getReadableDatabase();
Cursor cursor = db.query(
DatabaseContract.ContactEntry.TABLE_NAME, // The table to query
null, // The columns to return (all)
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
null, // don't sort the results
"1" // only keep one entry
);
return cursor;
}
private Cursor getContactFromUri(String uri)
{
// Only interested in the ID
/*
String[] columns = {
DatabaseContract.ContactEntry._ID,
};
*/
// Add the WHERE clause
String selection = DatabaseContract.ContactEntry.COLUMN_NAME_URI + " LIKE ?";
String[] selectionArgs = { uri };
SQLiteDatabase db = databaseHelper.getReadableDatabase();
Cursor cursor = db.query(
DatabaseContract.ContactEntry.TABLE_NAME, // The table to query
null, // The columns to return (all)
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
null, // don't sort the results
"1" // only keep one entry
);
return cursor;
}
// Updates contact in DB. Returns -1 if contact is not found
public int updateContact(String name, String uri)
{
if (databaseHelper == null) {
throw new RuntimeException("Database hasn't been opened.");
}
// Gets the data repository in write mode
SQLiteDatabase db = databaseHelper.getWritableDatabase();
// Update name & uri columns
ContentValues values = new ContentValues();
// Don't allow contact name to be modified
//values.put(DatabaseContract.ContactEntry.COLUMN_NAME_NAME, name);
values.put(DatabaseContract.ContactEntry.COLUMN_NAME_URI, uri);
// Add the WHERE clause
String selection = DatabaseContract.ContactEntry.COLUMN_NAME_NAME + " LIKE ?";
String[] selectionArgs = { name };
int count = db.update(
DatabaseContract.ContactEntry.TABLE_NAME,
values,
selection,
selectionArgs);
if (count > 0) {
int i = 0;
ArrayList<Map<String, String>> allContacts = retrieveContacts();
for (Map<String, String> item: allContacts) {
if (item.get("username").equals(name)) {
return i;
}
i++;
}
}
return -1;
}
// Removes contact from DB. Returns -1 if contact is not found
public int removeContact(String name, String uri)
{
if (databaseHelper == null) {
throw new RuntimeException("Database hasn't been opened.");
}
boolean found = false;
int i = 0;
ArrayList<Map<String, String>> allContacts = retrieveContacts();
for (Map<String, String> item: allContacts) {
if (item.get("username").equals(name)) {
found = true;
break;
}
i++;
}
if (!found) {
return -1;
}
// Gets the data repository in write mode
SQLiteDatabase db = databaseHelper.getWritableDatabase();
// Update name & uri columns
ContentValues values = new ContentValues();
// Add the WHERE clause
String selection = DatabaseContract.ContactEntry.COLUMN_NAME_NAME + " LIKE ?";
String[] selectionArgs = { name };
int count = db.delete(
DatabaseContract.ContactEntry.TABLE_NAME,
selection,
selectionArgs);
if (count > 0) {
return i;
}
return -1;
}
// ---- Message table
// Retrieve all messages for a contact ordered by timestamp
//ArrayList<Map<String, String>> retrieveMessages(String contactName)
Cursor retrieveMessages(String contactName)
{
if (databaseHelper == null) {
throw new RuntimeException("Database hasn't been opened yet, please call open()");
}
SQLiteDatabase db = databaseHelper.getReadableDatabase();
// Add the WHERE clause
String[] selectionArgs = { contactName };
// Here's an example: SELECT * FROM message INNER JOIN contact ON message.contact_id = contact._id WHERE contact.name LIKE ? ORDER BY timestamp ASC
String sqlQuery = "SELECT * FROM " + DatabaseContract.MessageEntry.TABLE_NAME + " INNER JOIN " +
DatabaseContract.ContactEntry.TABLE_NAME + " ON message." + DatabaseContract.MessageEntry.COLUMN_NAME_CONTACT_ID + " = contact." +
DatabaseContract.ContactEntry._ID + " " +
"WHERE " + DatabaseContract.ContactEntry.TABLE_NAME + "." + DatabaseContract.ContactEntry.COLUMN_NAME_NAME + " LIKE ? " +
"ORDER BY " + DatabaseContract.MessageEntry.COLUMN_NAME_TIMESTAMP + " ASC";
Log.i(TAG, "Query String: " + sqlQuery);
Cursor cursor = db.rawQuery(sqlQuery, selectionArgs);
/*
ArrayList<Map<String, String>> messageList = new ArrayList<Map<String, String>>();
// moveToFirst() fails if cursor is empty
if (cursor.moveToFirst()) {
// iterate the rows, read from db and populate contactList
do {
messageList.add(createMessageEntry(
cursor.getString(cursor.getColumnIndexOrThrow(DatabaseContract.MessageEntry.COLUMN_NAME_TYPE)),
cursor.getString(cursor.getColumnIndexOrThrow(DatabaseContract.ContactEntry.COLUMN_NAME_NAME)),
cursor.getString(cursor.getColumnIndexOrThrow(DatabaseContract.MessageEntry.COLUMN_NAME_TEXT))));
} while (cursor.moveToNext());
}
*/
return cursor;
//cursor.close();
//return messageList;
}
public void addMessage(String contactName, String messageText, boolean isLocal, String jobId, DatabaseContract.MessageDeliveryStatus deliveryStatus) throws SQLException
{
if (databaseHelper == null) {
throw new RuntimeException("Database hasn't been opened.");
}
// Gets the data repository in write mode
SQLiteDatabase db = databaseHelper.getWritableDatabase();
// Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
String type = "local";
if (!isLocal) {
type = "remote";
}
int contactId = getContactIdFromName(contactName);
values.put(DatabaseContract.MessageEntry.COLUMN_NAME_CONTACT_ID, contactId);
values.put(DatabaseContract.MessageEntry.COLUMN_NAME_TEXT, messageText);
values.put(DatabaseContract.MessageEntry.COLUMN_NAME_TYPE, type);
values.put(DatabaseContract.MessageEntry.COLUMN_NAME_JOB_ID, jobId);
values.put(DatabaseContract.MessageEntry.COLUMN_NAME_DELIVERY_STATUS, deliveryStatus.ordinal());
db.insertOrThrow(DatabaseContract.MessageEntry.TABLE_NAME, null, values);
}
public void updateMessageStatus(String jobId, DatabaseContract.MessageDeliveryStatus deliveryStatus) throws SQLException
{
if (databaseHelper == null) {
throw new RuntimeException("Database hasn't been opened.");
}
// Gets the data repository in write mode
SQLiteDatabase db = databaseHelper.getWritableDatabase();
// Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
values.put(DatabaseContract.MessageEntry.COLUMN_NAME_DELIVERY_STATUS, deliveryStatus.ordinal());
// Add the WHERE clause
String selection = DatabaseContract.MessageEntry.COLUMN_NAME_JOB_ID + " LIKE ?";
String[] selectionArgs = { jobId };
int count = db.update(
DatabaseContract.MessageEntry.TABLE_NAME,
values,
selection,
selectionArgs);
}
// Helpers for adapters
private HashMap<String, String> createContactEntry(String name, String uri)
{
HashMap<String, String> item = new HashMap<String, String>();
item.put("username", name);
item.put("sipuri", uri);
return item;
}
private HashMap<String, String> createMessageEntry(String type, String name, String message)
{
HashMap<String, String> item = new HashMap<String, String>();
if (type.equals("local")) {
item.put(MessageFragment.MESSAGE_CONTACT_KEY, "Me");
}
else {
item.put(MessageFragment.MESSAGE_CONTACT_KEY, name);
}
item.put(MessageFragment.MESSAGE_TEXT_KEY, message);
return item;
}
}