package org.yaxim.androidclient.data;
import java.util.ArrayList;
import org.yaxim.androidclient.util.LogConstants;
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.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.provider.BaseColumns;
import android.text.TextUtils;
import android.util.Log;
public class ChatProvider extends ContentProvider {
public static final String AUTHORITY = "org.yaxim.androidclient.provider.Chats";
public static final String TABLE_NAME = "chats";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
+ "/" + TABLE_NAME);
private static final UriMatcher URI_MATCHER = new UriMatcher(
UriMatcher.NO_MATCH);
private static final int MESSAGES = 1;
private static final int MESSAGE_ID = 2;
static {
URI_MATCHER.addURI(AUTHORITY, "chats", MESSAGES);
URI_MATCHER.addURI(AUTHORITY, "chats/#", MESSAGE_ID);
}
private static final String TAG = "yaxim.ChatProvider";
private SQLiteOpenHelper mOpenHelper;
public ChatProvider() {
}
@Override
public int delete(Uri url, String where, String[] whereArgs) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count;
switch (URI_MATCHER.match(url)) {
case MESSAGES:
count = db.delete(TABLE_NAME, where, whereArgs);
break;
case MESSAGE_ID:
String segment = url.getPathSegments().get(1);
if (TextUtils.isEmpty(where)) {
where = "_id=" + segment;
} else {
where = "_id=" + segment + " AND (" + where + ")";
}
count = db.delete(TABLE_NAME, where, whereArgs);
break;
default:
throw new IllegalArgumentException("Cannot delete from URL: " + url);
}
getContext().getContentResolver().notifyChange(url, null);
return count;
}
@Override
public String getType(Uri url) {
int match = URI_MATCHER.match(url);
switch (match) {
case MESSAGES:
return ChatConstants.CONTENT_TYPE;
case MESSAGE_ID:
return ChatConstants.CONTENT_ITEM_TYPE;
default:
throw new IllegalArgumentException("Unknown URL");
}
}
@Override
public Uri insert(Uri url, ContentValues initialValues) {
if (URI_MATCHER.match(url) != MESSAGES) {
throw new IllegalArgumentException("Cannot insert into URL: " + url);
}
ContentValues values = (initialValues != null) ? new ContentValues(
initialValues) : new ContentValues();
for (String colName : ChatConstants.getRequiredColumns()) {
if (values.containsKey(colName) == false) {
throw new IllegalArgumentException("Missing column: " + colName);
}
}
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
long rowId = db.insert(TABLE_NAME, ChatConstants.DATE, values);
if (rowId < 0) {
throw new SQLException("Failed to insert row into " + url);
}
Uri noteUri = ContentUris.withAppendedId(CONTENT_URI, rowId);
getContext().getContentResolver().notifyChange(noteUri, null);
return noteUri;
}
@Override
public boolean onCreate() {
mOpenHelper = new ChatDatabaseHelper(getContext());
return true;
}
@Override
public Cursor query(Uri url, String[] projectionIn, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();
int match = URI_MATCHER.match(url);
switch (match) {
case MESSAGES:
qBuilder.setTables(TABLE_NAME);
break;
case MESSAGE_ID:
qBuilder.setTables(TABLE_NAME);
qBuilder.appendWhere("_id=");
qBuilder.appendWhere(url.getPathSegments().get(1));
break;
default:
throw new IllegalArgumentException("Unknown URL " + url);
}
String orderBy;
if (TextUtils.isEmpty(sortOrder)) {
orderBy = ChatConstants.DEFAULT_SORT_ORDER;
} else {
orderBy = sortOrder;
}
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
Cursor ret = qBuilder.query(db, projectionIn, selection, selectionArgs,
null, null, orderBy);
if (ret == null) {
infoLog("ChatProvider.query: failed");
} else {
ret.setNotificationUri(getContext().getContentResolver(), url);
}
return ret;
}
@Override
public int update(Uri url, ContentValues values, String where,
String[] whereArgs) {
int count;
long rowId = 0;
int match = URI_MATCHER.match(url);
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
switch (match) {
case MESSAGES:
count = db.update(TABLE_NAME, values, where, whereArgs);
break;
case MESSAGE_ID:
String segment = url.getPathSegments().get(1);
rowId = Long.parseLong(segment);
count = db.update(TABLE_NAME, values, "_id=" + rowId, null);
break;
default:
throw new UnsupportedOperationException("Cannot update URL: " + url);
}
infoLog("*** notifyChange() rowId: " + rowId + " url " + url);
getContext().getContentResolver().notifyChange(url, null);
return count;
}
private static void infoLog(String data) {
if (LogConstants.LOG_INFO) {
Log.i(TAG, data);
}
}
private static class ChatDatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "yaxim.db";
private static final int DATABASE_VERSION = 5;
public ChatDatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
if (LogConstants.LOG_DEBUG) {
infoLog("creating new chat table");
}
db.execSQL("CREATE TABLE " + TABLE_NAME + " (" + ChatConstants._ID
+ " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ ChatConstants.DATE + " INTEGER,"
+ ChatConstants.DIRECTION + " INTEGER,"
+ ChatConstants.JID + " TEXT,"
+ ChatConstants.MESSAGE + " TEXT,"
+ ChatConstants.DELIVERY_STATUS + " INTEGER,"
+ ChatConstants.PACKET_ID + " TEXT);");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
infoLog("onUpgrade: from " + oldVersion + " to " + newVersion);
switch (oldVersion) {
case 3:
db.execSQL("UPDATE " + TABLE_NAME + " SET READ=1");
case 4:
db.execSQL("ALTER TABLE " + TABLE_NAME + " ADD " + ChatConstants.PACKET_ID + " TEXT");
break;
default:
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(db);
}
}
}
public static final class ChatConstants implements BaseColumns {
private ChatConstants() {
}
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.yaxim.chat";
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.yaxim.chat";
public static final String DEFAULT_SORT_ORDER = "_id ASC"; // sort by auto-id
public static final String DATE = "date";
public static final String DIRECTION = "from_me";
public static final String JID = "jid";
public static final String MESSAGE = "message";
public static final String DELIVERY_STATUS = "read"; // SQLite can not rename columns, reuse old name
public static final String PACKET_ID = "pid";
// boolean mappings
public static final int INCOMING = 0;
public static final int OUTGOING = 1;
public static final int DS_NEW = 0; //< this message has not been sent/displayed yet
public static final int DS_SENT_OR_READ = 1; //< this message was sent but not yet acked, or it was received and read
public static final int DS_ACKED = 2; //< this message was XEP-0184 acknowledged
public static final int DS_FAILED = 3; //< this message was returned as failed
public static ArrayList<String> getRequiredColumns() {
ArrayList<String> tmpList = new ArrayList<String>();
tmpList.add(DATE);
tmpList.add(DIRECTION);
tmpList.add(JID);
tmpList.add(MESSAGE);
return tmpList;
}
}
}