/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the Common Development
* and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at
* src/com/vodafone360/people/VODAFONE.LICENSE.txt or
* http://github.com/360/360-Engine-for-Android
* See the License for the specific language governing permissions and
* limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each file and
* include the License file at src/com/vodafone360/people/VODAFONE.LICENSE.txt.
* If applicable, add the following below this CDDL HEADER, with the fields
* enclosed by brackets "[]" replaced with your own identifying information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
* Copyright 2010 Vodafone Sales & Services Ltd. All rights reserved.
* Use is subject to license terms.
*/
package com.vodafone360.people.database.tables;
import java.util.List;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.text.format.Time;
import com.vodafone360.people.Settings;
import com.vodafone360.people.database.DatabaseHelper;
import com.vodafone360.people.datatypes.ContactDetail;
import com.vodafone360.people.utils.CloseUtils;
import com.vodafone360.people.utils.LogUtils;
/**
* Contains all the functionality related to the contact change log database
* table. This table is used to persist database changes that have not yet been
* synced to the server. This class is never instantiated hence all methods must
* be static.
*
* @version %I%, %G%
*/
public abstract class ContactChangeLogTable {
/**
* Name of the table as it appears in the database
*/
public static final String TABLE_NAME = "ContactChangeLog";
/**
* Name of a temporary table created and used to batch the deletion of sync
* data from the change log table.
*/
private static final String TEMP_CONTACT_CHANGE_TABLE = "SyncContactInfo";
/**
* Primary key for the temporary table
*/
private static final String TEMP_CONTACT_CHANGE_TABLE_ID = "Id";
/**
* Secondary key which links to the primary key of the change log table
*/
private static final String TEMP_CONTACT_CHANGE_LOG_ID = "LogId";
/**
* An enumeration of all the field names in the database.
*/
private static enum Field {
CONTACTCHANGEID("ContactChangeId"),
CHANGETYPE("ChangeType"),
LOCALCHANGECONTACTID("LocalChangeContactId"),
SERVERCHANGECONTACTID("ServerChangeContactId"),
LOCALCHANGEDETAILID("LocalChangeDetailId"),
SERVERDETAILKEY("ServerDetailKey"),
SERVERDETAILID("ServerDetailId"),
ZYBGROUPORRELID("ZybGroupOrRelId"),
TIMESTAMP("Timestamp");
/**
* The name of the field as it appears in the database
*/
private String mField;
/**
* Constructor
*
* @param field - The name of the field (see list above)
*/
private Field(String field) {
mField = field;
}
/**
* @return the name of the field as it appears in the database.
*/
public String toString() {
return mField;
}
}
/**
* Enumerates the type of changes supported by this table, including:
* <ul>
* <li>DELETE_CONTACT: A contact has been deleted from the database and
* needs to be deleted on the server. The local Contact ID, server Contact
* ID fields are required</li>
* <li>DELETE_DETAIL: A contact detail has been deleted from the database
* and needs to be deleted on the server. The local Contact ID, server
* Contact ID, local Detail ID, server Detail ID (if the detail has one) and
* detail key are required</li> </li>
* <li>ADD_GROUP_REL: A contact has been associated with a group on the
* client and needs to be synced on the server. The local Contact ID, server
* Contact ID and group ID are required</li>
* <li>DELETE_GROUP_REL: A contact has been disassociated with a group on
* the client and needs to be synced on the server. The local Contact ID,
* server Contact ID and group ID are required</li>
* </ul>
*/
public static enum ContactChangeType {
DELETE_CONTACT,
DELETE_DETAIL,
ADD_GROUP_REL,
DELETE_GROUP_REL
}
/**
* Wraps up the data present in the change log table
*/
public static class ContactChangeInfo {
public Long mContactChangeId = null;
public ContactChangeType mType = null;
public Long mLocalContactId = null;
public Long mServerContactId = null;
public Long mLocalDetailId = null;
public ContactDetail.DetailKeys mServerDetailKey = null;
public Long mServerDetailId = null;
public Long mGroupOrRelId = null;
/**
* Converts the encapsulated data into a string that can be displayed
* for debug purposes.
*/
@Override
public String toString() {
return "Contact Change ID: " + mContactChangeId + "\n" + "Contact Change Type: "
+ mType + "\n" + "Local Contact ID: " + mLocalContactId + "\n"
+ "Server Contact ID: " + mServerContactId + "\n" + "Local Detail ID: "
+ mLocalDetailId + "\n" + "Detail Key: " + mServerDetailKey + "\n"
+ "Server Detail ID: " + mServerDetailId + "\n" + "Group/Relation ID: "
+ mGroupOrRelId;
}
}
/**
* Create Server Change Log Table.
*
* @param writeableDb A writable SQLite database
* @throws SQLException If an SQL compilation error occurs
*/
public static void create(SQLiteDatabase writableDb) throws SQLException {
DatabaseHelper.trace(true, "ContactChangeLogTable.create()");
writableDb.execSQL("CREATE TABLE " + TABLE_NAME + " (" + Field.CONTACTCHANGEID
+ " INTEGER PRIMARY KEY, " + Field.CHANGETYPE + " INTEGER NOT NULL, "
+ Field.LOCALCHANGECONTACTID + " LONG NOT NULL, " + Field.SERVERCHANGECONTACTID
+ " LONG, " + Field.LOCALCHANGEDETAILID + " LONG, " + Field.SERVERDETAILID
+ " LONG, " + Field.SERVERDETAILKEY + " INTEGER, " + Field.ZYBGROUPORRELID
+ " LONG, " + Field.TIMESTAMP + " DATE);");
}
/**
* Fetches a comma separated list of table fields which can be used in an
* SQL SELECT statement as the query projection. The
* {@link #getQueryData(Cursor)} method can used to fetch data from the
* cursor.
*
* @param whereClause A where clause (without the where) to filter the
* result. Cannot be null.
* @return SQL string
*/
private static String getQueryStringSql(String whereClause) {
DatabaseHelper.trace(false, "ContactChangeLogTable.getQueryStringSql()");
return "SELECT " + Field.CONTACTCHANGEID + ", " + Field.CHANGETYPE + ", "
+ Field.LOCALCHANGECONTACTID + ", " + Field.SERVERCHANGECONTACTID + ", "
+ Field.LOCALCHANGEDETAILID + ", " + Field.SERVERDETAILID + ", "
+ Field.SERVERDETAILKEY + ", " + Field.ZYBGROUPORRELID + ", " + Field.TIMESTAMP
+ " FROM " + TABLE_NAME + " WHERE " + whereClause;
}
/**
* Column indices for database queries
*/
private static final int CONTACTCHANGEID = 0;
private static final int TYPE = 1;
private static final int LOCALCONTACTID = 2;
private static final int SERVERCONTACTID = 3;
private static final int LOCALDETAILID = 4;
private static final int SERVERDETAILID = 5;
private static final int SERVERDETAILKEY = 6;
private static final int GROUPORRELID = 7;
/**
* Fetches change log information from a cursor at the current position. The
* {@link #getQueryStringSql(String)} method should be used to make the
* query.
*
* @param c The cursor from the query
* @return A filled in ContactChangeInfo object
*/
private static ContactChangeInfo getQueryData(Cursor c) {
DatabaseHelper.trace(false, "ContactChangeLogTable.getQueryData()");
ContactChangeInfo info = new ContactChangeInfo();
if (!c.isNull(CONTACTCHANGEID)) {
info.mContactChangeId = c.getLong(CONTACTCHANGEID);
}
if (!c.isNull(TYPE)) {
final int typeIdx = c.getInt(TYPE);
if (typeIdx < ContactChangeType.values().length) {
info.mType = ContactChangeType.values()[typeIdx];
}
}
if (!c.isNull(LOCALCONTACTID)) {
info.mLocalContactId = c.getLong(LOCALCONTACTID);
}
if (!c.isNull(SERVERCONTACTID)) {
info.mServerContactId = c.getLong(SERVERCONTACTID);
}
if (!c.isNull(LOCALDETAILID)) {
info.mLocalDetailId = c.getLong(LOCALDETAILID);
}
if (!c.isNull(SERVERDETAILID)) {
info.mServerDetailId = c.getLong(SERVERDETAILID);
}
if (!c.isNull(SERVERDETAILKEY)) {
final int keyIdx = c.getInt(SERVERDETAILKEY);
if (keyIdx < ContactDetail.DetailKeys.values().length) {
info.mServerDetailKey = ContactDetail.DetailKeys.values()[keyIdx];
}
}
if (!c.isNull(GROUPORRELID)) {
info.mGroupOrRelId = c.getLong(GROUPORRELID);
}
// Ignore timestamp
return info;
}
/**
* Inserts "Add contact to group" operation into the change log.
*
* @param localContactId Local contact ID from the Contacts table
* @param serverContactId Server contact ID or null if the contact has not
* yet been synced.
* @param groupId server group ID
* @param writableDb Writable SQLite database
* @return true if successful, false otherwise
*/
public static boolean addGroupRel(long localContactId, Long serverContactId, Long groupId,
SQLiteDatabase writableDb) {
if (Settings.ENABLED_DATABASE_TRACE)
DatabaseHelper.trace(false, "ContactChangeLogTable.addZybGroupRel() localContactId["
+ localContactId + "] serverContactId[" + serverContactId + "] groupId["
+ groupId + "]");
if (groupId == null) {
LogUtils.logE("ContactChangeLogTable.addGroupRel() Invalid parameter");
return false;
}
if (isContactChangeInList(localContactId, ContactChangeType.DELETE_CONTACT, writableDb)) {
LogUtils
.logE("ContactChangeLogTable.addGroupRel() Associated contact has already been deleted");
return false;
}
ContactChangeInfo info = new ContactChangeInfo();
info.mType = ContactChangeType.ADD_GROUP_REL;
info.mLocalContactId = localContactId;
info.mServerContactId = serverContactId;
info.mGroupOrRelId = groupId;
if (!addContactChange(info, writableDb)) {
return false;
}
return true;
}
/**
* Inserts "Remove contact from group" operation into the change log.
*
* @param localContactId Local contact ID from the Contacts table
* @param serverContactId Server contact ID or null if the contact has not
* yet been synced.
* @param groupId server group ID
* @param writableDb Writable SQLite database
* @return true if successful, false otherwise
*/
public static boolean deleteGroupRel(long localContactId, Long serverContactId, Long groupId,
SQLiteDatabase writableDb) {
if (Settings.ENABLED_DATABASE_TRACE)
DatabaseHelper.trace(false, "ContactChangeLogTable.deleteGroupRel() localContactId["
+ localContactId + "] serverContactId[" + serverContactId + "] groupId["
+ groupId + "]");
if (groupId == null) {
LogUtils.logE("ContactChangeLogTable.deleteGroupRel() Invalid parameter");
return false;
}
if (isContactChangeInList(localContactId, ContactChangeType.DELETE_CONTACT, writableDb)) {
LogUtils
.logE("ContactChangeLogTable.deleteGroupRel() Associated contact has already been deleted");
return false;
}
Long addGroupId = findContactGroup(localContactId, groupId, writableDb);
if (addGroupId != null) {
return removeContactChange(addGroupId, writableDb);
}
if (isContactChangeInList(localContactId, ContactChangeType.ADD_GROUP_REL, writableDb)) {
removeContactChanges(localContactId, writableDb);
return true;
}
ContactChangeInfo info = new ContactChangeInfo();
info.mType = ContactChangeType.DELETE_GROUP_REL;
info.mLocalContactId = localContactId;
info.mServerContactId = serverContactId;
info.mGroupOrRelId = groupId;
if (!addContactChange(info, writableDb)) {
return false;
}
return true;
}
/**
* Inserts "Delete Contact" operation into the change log.
*
* @param localContactId Local contact ID from the Contacts table
* @param serverContactId Server contact ID. If this is null it is assumed
* that the contact hasn't yet been synced with the server, so
* the new contact change is removed from the log and the
* function returns.
* @param addToLog False - removes all changes associated with the contact
* from the change log True - to also insert deletion in change
* log.
* @param writableDb Writable SQLite database
* @return true if successful, false otherwise
*/
public static boolean addDeletedContactChange(Long localContactId, Long serverContactId,
boolean addToLog, SQLiteDatabase writableDb) {
if (Settings.ENABLED_DATABASE_TRACE)
DatabaseHelper.trace(false,
"ContactChangeLogTable.addDeletedContactChange() localContactId["
+ localContactId + "] serverContactId[" + serverContactId
+ "] addToLog[" + addToLog + "]");
if (localContactId == null) {
LogUtils.logE("ContactChangeLogTable.addDeletedContactChange() Invalid parameter");
return false;
}
if (addToLog) {
if (serverContactId == null) {
addToLog = false;
}
}
removeContactChanges(localContactId, writableDb);
if (!addToLog) {
return true;
}
ContactChangeInfo info = new ContactChangeInfo();
info.mType = ContactChangeType.DELETE_CONTACT;
info.mLocalContactId = localContactId;
info.mServerContactId = serverContactId;
if (!addContactChange(info, writableDb)) {
return false;
}
return true;
}
/**
* Inserts "Delete Contact Detail" operation into the change log.
*
* @param detail Must have a valid local contact ID, local detail ID and
* key. Will not be added to the change log if the contact server
* ID is null.
* @param addToLog False - removes all changes associated with the detail
* from the change log True - to also insert deletion in change
* log.
* @param writableDb Writable SQLite database
* @return true if successful, false otherwise
*/
public static boolean addDeletedContactDetailChange(ContactDetail detail, boolean addToLog,
SQLiteDatabase writableDb) {
if (Settings.ENABLED_DATABASE_TRACE)
DatabaseHelper.trace(false,
"ContactChangeLogTable.addDeletedContactDetailChange() addToLog[" + addToLog
+ "]");
if (detail.localContactID == null || detail.localDetailID == null || detail.key == null) {
LogUtils
.logE("ContactChangeLogTable.addDeletedContactDetailChange() Invalid parameter");
return false;
}
if (addToLog) {
if (isContactChangeInList(detail.localContactID, ContactChangeType.DELETE_CONTACT,
writableDb)) {
LogUtils
.logE("ContactChangeLogTable.addDeletedContactDetailChange() Associated contact has already been deleted");
return false;
}
if (isContactDetailChangeInList(detail.localDetailID, ContactChangeType.DELETE_DETAIL,
writableDb)) {
LogUtils
.logE("ContactChangeLogTable.addDeletedContactDetailChange() Associated contact detail has already been deleted");
return false;
}
}
removeContactDetailChanges(detail.localDetailID, writableDb);
if (!addToLog || detail.serverContactId == null) {
return true;
}
ContactChangeInfo info = new ContactChangeInfo();
info.mLocalContactId = detail.localContactID;
info.mServerContactId = detail.serverContactId;
info.mLocalDetailId = detail.localDetailID;
info.mServerDetailKey = detail.key;
info.mServerDetailId = detail.unique_id;
info.mType = ContactChangeType.DELETE_DETAIL;
if (!addContactChange(info, writableDb)) {
return false;
}
return true;
}
/**
* Inserts a contact change into the table.
*
* @param info contact change info. This must have a valid type field and
* depending on type other fields may also be required (see
* {@link ContactChangeType}).
* @param writableDb Writable SQLite database
* @return true if successful, false otherwise
*/
private static boolean addContactChange(ContactChangeInfo info, SQLiteDatabase writableDb) {
if (Settings.ENABLED_DATABASE_TRACE)
DatabaseHelper.trace(true, "ContactChangeLogTable.addContactChange()");
try {
ContentValues changeValues = new ContentValues();
changeValues.put(Field.CHANGETYPE.toString(), info.mType.ordinal());
changeValues.put(Field.LOCALCHANGECONTACTID.toString(), info.mLocalContactId);
if (info.mServerContactId != null) {
changeValues.put(Field.SERVERCHANGECONTACTID.toString(), info.mServerContactId);
}
if (info.mLocalDetailId != null) {
changeValues.put(Field.LOCALCHANGEDETAILID.toString(), info.mLocalDetailId);
}
if (info.mGroupOrRelId != null) {
changeValues.put(Field.ZYBGROUPORRELID.toString(), info.mGroupOrRelId);
}
if (info.mServerDetailKey != null) {
changeValues.put(Field.SERVERDETAILKEY.toString(), info.mServerDetailKey.ordinal());
}
if (info.mServerDetailId != null) {
changeValues.put(Field.SERVERDETAILID.toString(), info.mServerDetailId);
}
Time time = new Time();
time.setToNow();
changeValues.put(Field.TIMESTAMP.toString(), time.format2445());
long id = writableDb.insertOrThrow(TABLE_NAME, null, changeValues);
if (id < 0) {
LogUtils
.logE("ContactChangeLogTable.addContactChange() Unable to add contact change to log table - a database error has occurred");
return false;
}
info.mContactChangeId = id;
return true;
} catch (SQLException e) {
LogUtils.logE("ContactChangeLogTable.addContactChange() SQLException"
+ "- Unable to add contact change to log table", e);
return false;
}
}
/**
* Determines if a specific contact and change type exists in the change
* log.
*
* @param localContactId Local contact ID from the Contacts table
* @param type The change type to find
* @param readableDb Readable SQLite database
* @return true if the change is found, false otherwise
*/
private static boolean isContactChangeInList(Long localContactId, ContactChangeType type,
SQLiteDatabase readableDb) {
if (Settings.ENABLED_DATABASE_TRACE)
DatabaseHelper.trace(false,
"ContactChangeLogTable.isContactChangeInList() localContactId["
+ localContactId + "]");
Cursor c = null;
try {
c = readableDb.rawQuery("SELECT " + Field.LOCALCHANGECONTACTID + " FROM " + TABLE_NAME
+ " WHERE " + Field.LOCALCHANGECONTACTID + "=" + localContactId + " AND "
+ Field.CHANGETYPE + "=" + type.ordinal(), null);
if (c.moveToFirst()) {
return true;
}
return false;
} catch (SQLException e) {
return false;
} finally {
CloseUtils.close(c);
}
}
/**
* Determines if a specific contact detail and change type exists in the
* change log.
*
* @param localDetailId Local contact detail ID from ContactDetail table
* @param type The change type to find
* @param readableDb Readable SQLite database
* @return true if the change is found, false otherwise
*/
private static boolean isContactDetailChangeInList(Long localDetailId, ContactChangeType type,
SQLiteDatabase readableDb) {
if (Settings.ENABLED_DATABASE_TRACE)
DatabaseHelper.trace(false,
"ContactChangeLogTable.isContactDetailChangeInList() localDetailId["
+ localDetailId + "]");
Cursor c = null;
try {
c = readableDb.rawQuery("SELECT " + Field.LOCALCHANGEDETAILID + " FROM " + TABLE_NAME
+ " WHERE " + Field.LOCALCHANGEDETAILID + "=" + localDetailId + " AND "
+ Field.CHANGETYPE + "=" + type.ordinal(), null);
if (c.moveToFirst()) {
return true;
}
return false;
} catch (SQLException e) {
return false;
} finally {
CloseUtils.close(c);
}
}
/**
* Searches the change log for an association between contact and group
*
* @param localContactId Local contact ID from the Contacts table
* @param groupId Server group ID
* @param readableDb Readable SQLite database
* @return Contact Change ID (primary key) of the record found, or NULL if
* no such logs exist in the table.
*/
private static Long findContactGroup(long localContactId, long groupId,
SQLiteDatabase readableDb) {
if (Settings.ENABLED_DATABASE_TRACE)
DatabaseHelper.trace(false, "ContactChangeLogTable.findAddGroup() localContactId["
+ localContactId + "] groupId[" + groupId + "]");
Cursor c = null;
try {
Long id = null;
c = readableDb.rawQuery("SELECT " + Field.CONTACTCHANGEID + " FROM " + TABLE_NAME
+ " WHERE " + Field.LOCALCHANGECONTACTID + "=" + localContactId + " AND "
+ Field.ZYBGROUPORRELID + "=" + groupId + " AND " + Field.CHANGETYPE + "="
+ ContactChangeType.ADD_GROUP_REL.ordinal(), null);
if (c.moveToFirst()) {
id = c.getLong(0);
}
return id;
} catch (SQLException e) {
return null;
} finally {
CloseUtils.close(c);
c = null;
}
}
/**
* Removes all changes from the change log associated with a particular
* contact.
*
* @param localContactId Local contact ID from the Contacts table
* @param writableDb Writable SQLite database
* @return true if successful, false otherwise
*/
private static boolean removeContactChanges(Long localContactId, SQLiteDatabase writableDb) {
if (Settings.ENABLED_DATABASE_TRACE)
DatabaseHelper.trace(true,
"ContactChangeLogTable.removeContactChanges() localContactId[" + localContactId
+ "]");
try {
int result = writableDb.delete(TABLE_NAME, Field.LOCALCHANGECONTACTID + "="
+ localContactId, null);
if (result <= 0) {
return false;
}
} catch (SQLException e) {
return false;
}
return true;
}
/**
* Deletes a specific contact change record from the table
*
* @param ContactChangeId The primary ID identifying the record
* @param writableDb Writable SQLite database
* @return true if successful, false otherwise
*/
private static boolean removeContactChange(long ContactChangeId, SQLiteDatabase writableDb) {
if (Settings.ENABLED_DATABASE_TRACE)
DatabaseHelper.trace(true,
"ContactChangeLogTable.removeContactChange() ContactChangeId["
+ ContactChangeId + "]");
try {
int result = writableDb.delete(TABLE_NAME, Field.CONTACTCHANGEID + "="
+ ContactChangeId, null);
if (result <= 0) {
return false;
}
} catch (SQLException e) {
return false;
}
return true;
}
/**
* Removes all changes from the change log associated with a particular
* contact detail.
*
* @param localDetailId Local contact detail ID from the Contact details
* table
* @param writableDb Writable SQLite database
* @return true if successful, false otherwise
*/
private static boolean removeContactDetailChanges(Long localDetailId, SQLiteDatabase writableDb) {
if (Settings.ENABLED_DATABASE_TRACE)
DatabaseHelper.trace(true,
"ContactChangeLogTable.removeContactDetailChanges() localDetailId["
+ localDetailId + "]");
try {
if (writableDb
.delete(TABLE_NAME, Field.LOCALCHANGEDETAILID + "=" + localDetailId, null) < 0) {
return false;
}
// We 0 rows are deleted we still should return success
} catch (SQLException e) {
return false;
}
return true;
}
/**
* Fetches the number of changes listed in the table.
*
* @param type The ContactChangeType to count, if NULL then all change types
* are included.
* @param readableDb Readable SQLite database
* @return Total number of records
*/
public static int fetchNoOfContactDetailChanges(
final ContactChangeType type, final SQLiteDatabase readableDb) {
if (Settings.ENABLED_DATABASE_TRACE) {
DatabaseHelper.trace(false, "ContactChangeLogTable."
+ "fetchNoOfContactDetailChanges()");
}
Cursor cursor = null;
try {
String query = "SELECT COUNT(*) FROM " + TABLE_NAME;
if (type != null) {
query += " WHERE " + Field.CHANGETYPE.toString() + "="
+ type.ordinal();
}
cursor = readableDb.rawQuery(query, null);
if (cursor.moveToFirst()) {
return cursor.getInt(0);
} else {
LogUtils.logE("ContactChangeLogTable."
+ "fetchNoOfContactDetailChanges() COUNT(*) "
+ "should not return an empty cursor, returning 0");
return 0;
}
} finally {
CloseUtils.close(cursor);
}
}
/**
* Removes a list of changes from the change log table. This method is used
* once the server has been successfully synced with the client.
*
* @param changeInfoList A list of {@link ContactChangeInfo} objects. Note
* that only the mContactChangeId field of this object is
* actually used. The object is passed in as a convenience.
* @param writableDb Writable SQLite database
* @return true if successful, false otherwise
*/
public static boolean deleteContactChanges(List<ContactChangeInfo> changeInfoList,
SQLiteDatabase writableDb) {
if (Settings.ENABLED_DATABASE_TRACE) {
DatabaseHelper.trace(false,
"ContactChangeLogTable.deleteContactChanges() Change Log List for deletion:");
for (ContactChangeLogTable.ContactChangeInfo info : changeInfoList) {
DatabaseHelper.trace(false,
"ContactChangeLogTable.deleteContactChanges() mContactChangeId["
+ info.mContactChangeId + "]");
}
}
try {
writableDb.beginTransaction();
writableDb.execSQL("DROP TABLE IF EXISTS " + TEMP_CONTACT_CHANGE_TABLE);
writableDb.execSQL("CREATE TEMPORARY TABLE " + TEMP_CONTACT_CHANGE_TABLE + "("
+ TEMP_CONTACT_CHANGE_TABLE_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ TEMP_CONTACT_CHANGE_LOG_ID + " LONG);");
ContentValues values = new ContentValues();
for (ContactChangeInfo info : changeInfoList) {
values.put(TEMP_CONTACT_CHANGE_LOG_ID, info.mContactChangeId);
if (writableDb.insertOrThrow(TEMP_CONTACT_CHANGE_TABLE, null, values) < 0) {
return false;
}
}
writableDb.execSQL("DELETE FROM " + TABLE_NAME + " WHERE " + Field.CONTACTCHANGEID
+ " IN (SELECT " + TEMP_CONTACT_CHANGE_LOG_ID + " FROM "
+ TEMP_CONTACT_CHANGE_TABLE + ");");
writableDb.setTransactionSuccessful();
return true;
} catch (SQLException e) {
LogUtils
.logE(
"ContactChangeLogTable.deleteContactChanges() SQLException - Unable to remove contact detail change from log",
e);
return false;
} finally {
writableDb.endTransaction();
}
}
/**
* Fetches a list of changes from the table for a specific type. The list is
* ordered by local contact ID.
*
* @param contactChangeList The list to be populated
* @param type The type of change to return
* @param firstIndex An index of the first record to return (0 based)
* @param count The number of records to return (or -1 to return all)
* @param readableDb Readable SQLite database
* @return true if successful, false otherwise
*/
public static boolean fetchContactChangeLog(List<ContactChangeInfo> contactChangeList,
ContactChangeType type, long firstIndex, long count, SQLiteDatabase readableDb) {
if (Settings.ENABLED_DATABASE_TRACE)
DatabaseHelper.trace(false, "ContactChangeLogTable.fetchContactChangeLog() "
+ "firstIndex[" + firstIndex + "] count[" + count + "]");
Cursor c1 = null;
try {
c1 = readableDb.rawQuery(getQueryStringSql(Field.CHANGETYPE + "=" + type.ordinal()
+ " ORDER BY " + Field.LOCALCHANGECONTACTID + " LIMIT " + firstIndex + ","
+ count), null);
contactChangeList.clear();
while (c1.moveToNext()) {
contactChangeList.add(getQueryData(c1));
}
} catch (SQLiteException e) {
LogUtils
.logE(
"ContactChangeLogTable.fetchContactChangeLog() throw e; - Unable to fetch main contact change log",
e);
return false;
} finally {
CloseUtils.close(c1);
}
return true;
}
/**
* Fetches a list of changes on the contact details for the me-profile.
*
* @param changeList The list to populate with contact changes.
* @param type The type of change to fetch from the contact.
* @param readableDb The database to read from.
* @param meProfileServerId The server id of the me-profile.
* @return True if fetching succeeded, false otherwise.
*/
public static boolean fetchMeProfileChangeLog(List<ContactChangeInfo> changeList,
ContactChangeType type, SQLiteDatabase readableDb, Long meProfileServerId) {
if (Settings.ENABLED_DATABASE_TRACE)
DatabaseHelper.trace(false, "ContactChangeLogTable.fetchMeProfileChangeLog()");
Cursor c1 = null;
try {
c1 = readableDb.rawQuery(getQueryStringSql(Field.CHANGETYPE + "=" + type.ordinal()
+ " AND " + Field.SERVERCHANGECONTACTID + "=" + meProfileServerId.longValue()),
null);
while (c1.moveToNext()) {
changeList.add(getQueryData(c1));
}
} catch (SQLiteException e) {
LogUtils.logE("ContactChangeLogTable.fetchMeProfileChangeLog() throw e; - "
+ "Unable to fetch main contact change log", e);
return false;
} finally {
CloseUtils.close(c1);
}
return true;
}
}