/* * 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 android.content.ContentValues; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; import com.vodafone360.people.Settings; import com.vodafone360.people.database.DatabaseHelper; import com.vodafone360.people.database.utils.EncryptionUtils; import com.vodafone360.people.database.utils.SqlUtils; import com.vodafone360.people.datatypes.AuthSessionHolder; import com.vodafone360.people.datatypes.LoginDetails; import com.vodafone360.people.datatypes.PublicKeyDetails; import com.vodafone360.people.service.PersistSettings; import com.vodafone360.people.service.ServiceStatus; import com.vodafone360.people.utils.CloseUtils; import com.vodafone360.people.utils.LogUtils; /** * Contains all the functionality related to the state database table. This * table is used to persist individual setting data. The table always has only * one record. This class is never instantiated hence all methods must be * static. * * @version %I%, %G% */ public abstract class StateTable { /** * Name of the table as it appears in the database. */ public static final String TABLE_NAME = "State"; /** * The state table only has one record with the primary key set to the * following value. */ private static final int PRIMARY_STATE_KEY_VALUE = 1; /** * An enumeration of all the field names in the database. */ private static enum Field { /** * primary key. */ STATEID("StateId"), /** * 360 user name. */ USERNAME("Username"), /** * 360 user password. */ PASSWORD("Password"), /** * 360 user mobile phone number. */ MOBILENO("MobileNo"), /** * @see LoginDetails. */ SUBSCIBERID("SubscriberId"), /** * @see LoginDetails. */ REMEMBERME("RememberMe"), /** * @see LoginDetails. */ AUTOCONNECT("AutoConnect"), /** * Contacts revision, @see CAPI contacts/getcontactchanges(). */ CONTACTSREVISION("ContactsRevision"), /** * TRUE if the registration/signing in process is successfully complete. */ REGISTRATIONCOMPLETE("RegistrationComplete"), /** * 360 session id. */ SESSIONID("sessionid"), /** * Secret number. */ SESSIONSECRET("sessionsecret"), /** * Me profile 360 session user id. */ SESSIONUSERID("sessionuserid"), /** * Me profile 360 session user name. */ SESSIONUSERNAME("sessionusername"), /** * Me profile user local contact id. */ MYCONTACTID("mycontactid"), /** * Security certificate public key exponential. */ PUBLICKEYEXPONENTIAL("exponential"), /** * Security certificate public key modulus. */ PUBLICKEYMODULO("modulo"), /** * Security certificate public key string. */ PUBLICKEYBASE64("keyBase64"), /** * Security certificate public key X509 format. */ PUBLICKEYX509("keyX509"), /** * Database state change flags. */ MYCONTACTCHANGED("mycontactchanged"), /** * Contact picture needs updating flag. */ MYCONTACTPICTURECHANGED("mycontactpicturechanged"), /** * Native database changes flag. */ NATIVEDBCHANGED("NativeDbChanged"), /** * Newest status timestamp, @see ActivitiesEngine. */ LASTSTATUSUPDATE("StatusTableUpdated"), /** * Oldest status timestamp, @see ActivitiesEngine. */ OLDESTSTATUSUPDATE("OldestStatusUpdated"), /** * Newest phone call timestamp, @see FetchCallLogEvents. */ LASTPHONECALLUPDATE("PhoneCallTableUpdated"), /** * Oldest phone call timestamp, @see FetchCallLogEvents. */ OLDESTPHONECALL("OldestPhoneCall"), /** * Newest SMS timestamp, @see FetchSmsLogEvents. */ LASTSMSUPDATE("SMSTableUpdated"), /** * Oldest SMS timestamp, @see FetchSMSLogEvents. */ OLDESTSMS("OldestSMS"), /** * Newest MMS timestamp, @see FetchSMSLogEvents. */ LASTMMSUPDATE("LastMMSUpdated"), /** * Oldest MMS timestamp, @see FetchSMSLogEvents. */ OLDESTMMS("OldestMMS"), /** * Me profile revision number, used to call for "Me Profile" update. */ MEPROFILEREVISION("MeProfileRevision"), /** * A flag to indicate the user avatar change. */ MEPROFILEAVATARCHANGED("MeProfileAvatarChanged"); // See PersistSettings.Options for more fields /** * 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(final String field) { mField = field; } /** * @return the name of the field as it appears in the database. */ public String toString() { return mField; } } /** * Create Settings Table and add a record with default setting values. * * @param writableDb A writable SQLite database. */ public static void create(final SQLiteDatabase writableDb) { DatabaseHelper.trace(true, "StateTable.create()"); String createSql = "CREATE TABLE " + TABLE_NAME + " (" + Field.STATEID + " INTEGER PRIMARY KEY, " + Field.USERNAME + " TEXT, " + Field.PASSWORD + " BINARY, " + Field.MOBILENO + " TEXT, " + Field.SUBSCIBERID + " TEXT, " + Field.REMEMBERME + " BOOLEAN, " + Field.AUTOCONNECT + " BOOLEAN, " + Field.REGISTRATIONCOMPLETE + " BOOLEAN," + Field.SESSIONID + " TEXT," + Field.SESSIONSECRET + " TEXT," + Field.SESSIONUSERID + " LONG," + Field.SESSIONUSERNAME + " TEXT," + Field.CONTACTSREVISION + " LONG," + Field.MYCONTACTID + " LONG," /** AA added fields to store the public key. **/ + Field.PUBLICKEYEXPONENTIAL + " BINARY," + Field.PUBLICKEYMODULO + " BINARY," + Field.PUBLICKEYBASE64 + " TEXT," + Field.PUBLICKEYX509 + " BINARY," /** End added fields to store the public key. **/ + Field.MYCONTACTCHANGED + " BOOLEAN," + Field.MYCONTACTPICTURECHANGED + " BOOLEAN," + Field.NATIVEDBCHANGED + " BOOLEAN," + Field.LASTSTATUSUPDATE + " LONG," + Field.OLDESTSTATUSUPDATE + " LONG," + Field.LASTPHONECALLUPDATE + " LONG," + Field.OLDESTPHONECALL + " LONG," + Field.LASTSMSUPDATE + " LONG," + Field.OLDESTSMS + " LONG," + Field.LASTMMSUPDATE + " LONG," + Field.OLDESTMMS + " LONG," + Field.MEPROFILEREVISION + " LONG," + Field.MEPROFILEAVATARCHANGED + " BOOLEAN,"; // Add additional settings from the PersistSettings object for (PersistSettings.Option option : PersistSettings.Option.values()) { createSql += option.tableFieldName() + " " + option.getType().getDbType() + ","; } createSql = createSql.substring(0, createSql.length() - 1); createSql += ");"; writableDb.execSQL(createSql); /* * Insert a setting record with default values into the table */ final ContentValues values = new ContentValues(); values.put(Field.STATEID.toString(), PRIMARY_STATE_KEY_VALUE); final PersistSettings setting = new PersistSettings(); for (PersistSettings.Option option : PersistSettings.Option.values()) { setting.putDefaultOptionData(option); PersistSettings.addToContentValues(values, setting); } writableDb.insertOrThrow(TABLE_NAME, null, values); } /*** * Private constructor to prevent instantiation. */ private StateTable() { // Do nothing. } /** * Fetches cached user login credentials (without encryption information). * * @param details An empty LoginDetails object to be filled * @param readableDb Readable SQLite database for fetching the information * @return SUCCESS or a suitable error code */ public static ServiceStatus fetchLogonCredentials( final LoginDetails details, final SQLiteDatabase readableDb) { Cursor cursor = null; try { cursor = readableDb.rawQuery("SELECT " + Field.USERNAME + "," + Field.PASSWORD + "," + Field.MOBILENO + "," + Field.SUBSCIBERID + "," + Field.REMEMBERME + "," + Field.AUTOCONNECT + " FROM " + TABLE_NAME + " WHERE " + Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null); if (!cursor.moveToFirst()) { LogUtils.logE("StateTable.fetchLogonCredentials() Unable to " + "fetch logon credentials: State record not found"); return ServiceStatus.ERROR_DATABASE_CORRUPT; } details.mUsername = SqlUtils.setString(cursor, Field.USERNAME.toString()); details.mPassword = EncryptionUtils.decryptPassword( SqlUtils.setBlob(cursor, Field.PASSWORD.toString())); details.mMobileNo = SqlUtils.setString(cursor, Field.MOBILENO.toString()); details.mSubscriberId = SqlUtils.setString(cursor, Field.SUBSCIBERID.toString()); details.mRememberMe = SqlUtils.setBoolean(cursor, Field.REMEMBERME.toString(), details.mRememberMe); details.mAutoConnect = SqlUtils.setBoolean(cursor, Field.AUTOCONNECT.toString(), details.mRememberMe); } catch (SQLiteException e) { LogUtils.logE("StateTable.fetchLogonCredentials() Exception - " + "Unable to fetch logon credentials", e); return ServiceStatus.ERROR_DATABASE_CORRUPT; } finally { CloseUtils.close(cursor); } if (Settings.ENABLED_DATABASE_TRACE) { DatabaseHelper.trace(false, "StateTable.fetchLogonCredentials() " + "username[" + details.mUsername + "] " + "mobileNo[" + details.mMobileNo + "] " + "subscriberId[" + details.mSubscriberId + "]"); } return ServiceStatus.SUCCESS; } /** * Fetches cached user login credentials (with encryption information). * * @param details An empty LoginDetails object to be filled * @param pubKeyDetails An empty PublicKeyDetails object to be filled * @param readableDb Readable SQLite database for fetching the information * @return SUCCESS or a suitable error code */ public static ServiceStatus fetchLogonCredentialsAndPublicKey( final LoginDetails details, final PublicKeyDetails pubKeyDetails, final SQLiteDatabase readableDb) { if (Settings.ENABLED_DATABASE_TRACE) { DatabaseHelper.trace(false, "StateTable.fetchLogonCredentials() " + "username[" + details.mUsername + "]"); } Cursor cursor = null; try { cursor = readableDb.rawQuery("SELECT " + Field.USERNAME + "," + Field.PASSWORD + "," + Field.MOBILENO + "," + Field.SUBSCIBERID + "," + Field.REMEMBERME + "," + Field.AUTOCONNECT + "," + Field.PUBLICKEYEXPONENTIAL + "," + Field.PUBLICKEYMODULO + "," + Field.PUBLICKEYBASE64 + "," + Field.PUBLICKEYX509 + " FROM " + TABLE_NAME + " WHERE " + Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null); if (!cursor.moveToFirst()) { LogUtils.logE("StateTable.fetchLogonCredentials() Unable to " + "fetch logon credentials: State record not found"); return ServiceStatus.ERROR_DATABASE_CORRUPT; } details.mUsername = SqlUtils.setString(cursor, Field.USERNAME.toString()); details.mPassword = EncryptionUtils.decryptPassword( SqlUtils.setBlob(cursor, Field.PASSWORD.toString())); details.mMobileNo = SqlUtils.setString(cursor, Field.MOBILENO.toString()); details.mSubscriberId = SqlUtils.setString(cursor, Field.SUBSCIBERID.toString()); details.mRememberMe = SqlUtils.setBoolean(cursor, Field.REMEMBERME.toString(), details.mRememberMe); details.mAutoConnect = SqlUtils.setBoolean(cursor, Field.AUTOCONNECT.toString(), details.mAutoConnect); /** Add the public key data here. **/ if (pubKeyDetails != null) { // check what if it's null pubKeyDetails.mExponential = SqlUtils.setBlob(cursor, Field.PUBLICKEYEXPONENTIAL.toString()); pubKeyDetails.mModulus = SqlUtils.setBlob(cursor, Field.PUBLICKEYMODULO.toString()); pubKeyDetails.mKeyBase64 = SqlUtils.setString(cursor, Field.PUBLICKEYBASE64.toString()); pubKeyDetails.mKeyX509 = SqlUtils.setBlob(cursor, Field.PUBLICKEYX509.toString()); } } catch (SQLiteException e) { LogUtils.logE("StateTable.fetchLogonCredentials() Exception - " + "Unable to fetch logon credentials", e); return ServiceStatus.ERROR_DATABASE_CORRUPT; } finally { CloseUtils.close(cursor); } return ServiceStatus.SUCCESS; } /** * Modify cached user credentials settings (without encryption information). * * @param details The new credentials. * @param writableDb Writable SQLite database * @return SUCCESS or a suitable error code */ public static ServiceStatus modifyCredentials(final LoginDetails details, final SQLiteDatabase writableDb) { if (Settings.ENABLED_DATABASE_TRACE) { DatabaseHelper.trace(true, "StateTable.modifyCredentials() " + "username[" + details.mUsername + "]"); } ContentValues values = new ContentValues(); values.put(Field.USERNAME.toString(), details.mUsername); if (!details.mRememberMe) { values.put(Field.PASSWORD.toString(), (String) null); } else { values.put(Field.PASSWORD.toString(), EncryptionUtils .encryptPassword(details.mPassword)); } values.put(Field.MOBILENO.toString(), details.mMobileNo); values.put(Field.SUBSCIBERID.toString(), details.mSubscriberId); values.put(Field.REMEMBERME.toString(), details.mRememberMe); values.put(Field.AUTOCONNECT.toString(), details.mAutoConnect); try { if (writableDb.update(TABLE_NAME, values, Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null) <= 0) { LogUtils.logE("StateTable.modifyCredentials() " + "Unable to modify login credentials"); return ServiceStatus.ERROR_DATABASE_CORRUPT; } } catch (SQLiteException e) { LogUtils.logE( "StateTable.modifyCredentials() Exception - " + "Unable to modify credentials", e); return ServiceStatus.ERROR_DATABASE_CORRUPT; } return ServiceStatus.SUCCESS; } /** * Modify cached user credentials settings (without encryption information). * * @param details The new credentials. * @param pubKeyDetails The new key details. * @param writableDb Writable SQLite database * @return SUCCESS or a suitable error code */ public static ServiceStatus modifyCredentialsAndPublicKey( final LoginDetails details, final PublicKeyDetails pubKeyDetails, final SQLiteDatabase writableDb) { if (Settings.ENABLED_DATABASE_TRACE) { DatabaseHelper.trace(true, "StateTable." + "modifyCredentialsAndPublicKey() username[" + details.mUsername + "]"); } ContentValues values = new ContentValues(); values.put(Field.USERNAME.toString(), details.mUsername); if (!details.mRememberMe) { values.put(Field.PASSWORD.toString(), (String) null); } else { values.put(Field.PASSWORD.toString(), EncryptionUtils .encryptPassword(details.mPassword)); } values.put(Field.MOBILENO.toString(), details.mMobileNo); values.put(Field.SUBSCIBERID.toString(), details.mSubscriberId); values.put(Field.REMEMBERME.toString(), details.mRememberMe); values.put(Field.AUTOCONNECT.toString(), details.mAutoConnect); // add the public key data here if (pubKeyDetails != null) { // check what if it's null values.put(Field.PUBLICKEYEXPONENTIAL.toString(), pubKeyDetails.mExponential); values.put(Field.PUBLICKEYMODULO.toString(), pubKeyDetails.mModulus); values.put(Field.PUBLICKEYBASE64.toString(), pubKeyDetails.mKeyBase64); values.put(Field.PUBLICKEYX509.toString(), pubKeyDetails.mKeyX509); } try { if (writableDb.update(TABLE_NAME, values, Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null) <= 0) { LogUtils.logE("StateTable.modifyCredentialsAndPublicKey() " + "Unable to modify login credentials"); return ServiceStatus.ERROR_DATABASE_CORRUPT; } } catch (SQLiteException e) { LogUtils.logE("StateTable.modifyCredentialsAndPublicKey() " + "Exception. Unable to modify credentials and public key", e); return ServiceStatus.ERROR_DATABASE_CORRUPT; } return ServiceStatus.SUCCESS; } /** * Set registration complete flag. * * @param complete The flag value (true or false) * @param writableDb Writable SQLite database * @return true if successful, false otherwise */ public static boolean setRegistrationComplete(final boolean complete, final SQLiteDatabase writableDb) { DatabaseHelper.trace(true, "StateTable.setRegistrationComplete() " + "complete[" + complete + "]"); ContentValues values = new ContentValues(); if (complete) { values.put(Field.REGISTRATIONCOMPLETE.toString(), 1); } else { values.put(Field.REGISTRATIONCOMPLETE.toString(), 0); } try { if (writableDb.update(TABLE_NAME, values, Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null) <= 0) { LogUtils.logE("StateTable.setRegistrationComplete()" + "Unable to modify registration complete flag"); return false; } } catch (SQLException e) { LogUtils.logE("StateTable.setRegistrationComplete() Exception - " + "Unable to set registration complete", e); return false; } return true; } /** * Fetch value of registration complete flag from database. * * @param readableDb Readable SQLite database for fetching the information * @return true if registration is complete, false if registration is not * complete or a database error has occurred. */ public static boolean isRegistrationComplete( final SQLiteDatabase readableDb) { boolean mResult = false; Cursor mCursor = null; try { mCursor = readableDb.rawQuery("SELECT " + Field.REGISTRATIONCOMPLETE + " FROM " + TABLE_NAME + " WHERE " + Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null); if (mCursor.moveToFirst() && !mCursor.isNull(0)) { mResult = (mCursor.getInt(0) != 0); } } catch (SQLiteException e) { LogUtils.logE("StateTable.isRegistrationComplete() Exception - " + "Unable to select registration complete", e); return false; } finally { CloseUtils.close(mCursor); mCursor = null; } LogUtils.logE("StateTable.isRegistrationComplete() is " + mResult); DatabaseHelper.trace(false, "StateTable.isRegistrationComplete() " + "Return[" + mResult + "]"); return mResult; } /** * Fetches the current contact revision for the server sync. * * @param readableDb Readable SQLite database for fetching the information * @return The revision number or null if an error occurs. */ public static Integer fetchContactRevision( final SQLiteDatabase readableDb) { DatabaseHelper.trace(false, "StateTable.fetchContactRevision()"); Integer value = null; Cursor c = null; try { c = readableDb.rawQuery("SELECT " + Field.CONTACTSREVISION + " FROM " + TABLE_NAME + " WHERE " + Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null); if (!c.moveToFirst() || c.isNull(0)) { return null; } value = c.getInt(0); return value; } catch (SQLiteException e) { LogUtils.logE("StateTable.fetchContactRevision() Exception -" + " Unable to fetch contact revision", e); return null; } finally { CloseUtils.close(c); c = null; } } /** * Stores a new server contact revision in the database. * * @param revision New revision number * @param writableDb Writable SQLite database for storing the information * @return true if successful, false otherwise */ public static boolean modifyContactRevision(final Integer revision, final SQLiteDatabase writableDb) { if (Settings.ENABLED_DATABASE_TRACE) { DatabaseHelper.trace(true, "StateTable.modifyContactRevision() " + "revision[" + revision + "]"); } ContentValues values = new ContentValues(); values.put(Field.CONTACTSREVISION.toString(), revision); try { if (writableDb.update(TABLE_NAME, values, Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null) <= 0) { LogUtils.logE("StateTable.modifyContactRevision() " + "Unable to modify contact revision state"); return false; } } catch (SQLException e) { LogUtils.logE("StateTable.modifyContactRevision() " + "Exception - Unable to modify contact revision", e); return false; } return true; } /** * Fetches an option from the settings table. * * @param option Specifies which option is required * @param readableDb Readable SQLite database for fetching the information * @return A PersistSettings object containing the option data if * successful, null otherwise. */ public static PersistSettings fetchOption( final PersistSettings.Option option, final SQLiteDatabase readableDb) { if (Settings.ENABLED_DATABASE_TRACE) { DatabaseHelper.trace(false, "StateTable.fetchOption() name[" + option.tableFieldName() + "] value[" + option.defaultValue() + "] type[" + option.getType() + "]"); } Cursor c = null; try { c = readableDb.rawQuery("SELECT " + option.tableFieldName() + " FROM " + TABLE_NAME + " WHERE " + Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null); if (!c.moveToFirst()) { LogUtils.logE("StateTable.fetchOption() Unable to find option " + "in the database, option[" + option + "]"); return null; } final PersistSettings setting = new PersistSettings(); Object data = null; if (!c.isNull(0)) { data = PersistSettings.fetchValueFromCursor(c, 0, c.getColumnName(0)); } setting.putOptionData(option, data); LogUtils.logD("StateTable.fetchOption() Fetched option[" + option + "]"); return setting; } catch (Exception e) { LogUtils.logE("StateTable.fetchOption() Exception - Unable to " + "fetch options from database", e); return null; } finally { CloseUtils.close(c); c = null; } } /** * Stores a persist setting option in the database. * * @param setting The setting to store. Must have an option set with data. * @param writableDb Writable SQLite database for storing the information * @return SUCCESS or a suitable error code */ public static ServiceStatus setOption(final PersistSettings setting, final SQLiteDatabase writableDb) { DatabaseHelper.trace(true, "StateTable.setOption()"); try { ContentValues values = new ContentValues(); if (!PersistSettings.addToContentValues(values, setting)) { LogUtils.logE("StateTable.setOption() Unknown option[" + setting.getOption() + "]"); return ServiceStatus.ERROR_NOT_FOUND; } if (writableDb.update(TABLE_NAME, values, Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null) <= 0) { LogUtils.logE("StateTable.setOption() Unable to modify fields " + "in settings table, values[" + values + "]"); return ServiceStatus.ERROR_DATABASE_CORRUPT; } return ServiceStatus.SUCCESS; } catch (SQLException e) { LogUtils.logE("StateTable.setOption() SQLException - " + "Unable to set options in database", e); return null; } } /** * Fetches the current session from the database. * * @param readableDb Readable SQLite database for fetching the information * @return The session object or null if the session was not available. */ public static AuthSessionHolder fetchSession( final SQLiteDatabase readableDb) { Cursor cursor = null; try { cursor = readableDb.rawQuery("SELECT " + Field.SESSIONID + "," + Field.SESSIONSECRET + "," + Field.SESSIONUSERID + "," + Field.SESSIONUSERNAME + " FROM " + TABLE_NAME + " WHERE " + Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null); if (!cursor.moveToFirst()) { LogUtils.logE("StateTable.fetchSession() " + "Unable to find session info in the database"); return null; } if (cursor.isNull(cursor.getColumnIndex(Field.SESSIONID.toString())) || cursor.isNull(cursor.getColumnIndex( Field.SESSIONSECRET.toString())) || cursor.isNull(cursor.getColumnIndex( Field.SESSIONUSERID.toString())) || cursor.isNull(cursor.getColumnIndex( Field.SESSIONUSERNAME.toString()))) { LogUtils.logE("StateTable.fetchSession() " + "Unable to find session data in the database"); return null; } final AuthSessionHolder session = new AuthSessionHolder(); session.sessionID = SqlUtils.setString(cursor, Field.SESSIONID.toString()); session.sessionSecret = SqlUtils.setString(cursor, Field.SESSIONSECRET.toString()); session.userID = SqlUtils.setLong(cursor, Field.SESSIONUSERID.toString(), -1L); session.userName = SqlUtils.setString(cursor, Field.SESSIONUSERNAME.toString()); DatabaseHelper.trace(false, "StateTable.fetchSession() " + "Fetched session[" + session.sessionID + "]"); return session; } catch (Exception e) { LogUtils.logE("StateTable.fetchSession() Exception - " + "Unable to fetch session from database", e); return null; } finally { CloseUtils.close(cursor); } } /** * Stores the latest session in the database. * * @param session The session object to store. * @param writableDb Writable SQLite database for storing the information * @return SUCCESS or a suitable error code. */ public static ServiceStatus setSession(final AuthSessionHolder session, final SQLiteDatabase writableDb) { DatabaseHelper.trace(true, "StateTable.setSession()"); try { ContentValues values = new ContentValues(); if (session != null) { values.put(Field.SESSIONID.toString(), session.sessionID); values.put(Field.SESSIONSECRET.toString(), session.sessionSecret); values.put(Field.SESSIONUSERID.toString(), session.userID); values.put(Field.SESSIONUSERNAME.toString(), session.userName); } else { values.putNull(Field.SESSIONID.toString()); values.putNull(Field.SESSIONSECRET.toString()); values.putNull(Field.SESSIONUSERID.toString()); values.putNull(Field.SESSIONUSERNAME.toString()); } if (writableDb.update(TABLE_NAME, values, Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null) <= 0) { LogUtils.logE("StateTable.setSession() Unable to modify " + "fields in settings table, values[" + values + "]"); return ServiceStatus.ERROR_DATABASE_CORRUPT; } return ServiceStatus.SUCCESS; } catch (SQLException e) { LogUtils.logE("StateTable.setSession() SQLException - " + "Unable to set session in database", e); return null; } } /** * Fetches the local contact ID for the me profile (which is stored in the * contacts table with the other contacts). * * @param readableDb Readable SQLite database for fetching the information * @return The local contact ID value or null if the user profile has not * yet been synced from the server. */ public static Long fetchMeProfileId(final SQLiteDatabase readableDb) { Long mValue = null; Cursor mCursor = null; try { mCursor = readableDb.rawQuery("SELECT " + Field.MYCONTACTID + " FROM " + TABLE_NAME + " WHERE " + Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null); if (!mCursor.moveToFirst() || mCursor.isNull(0)) { DatabaseHelper.trace(false, "StateTable.fetchMeProfileId() " + "Return NULL"); return null; } if (!mCursor.isNull(0)) { mValue = mCursor.getLong(0); } DatabaseHelper.trace(false, "StateTable.fetchMeProfileId() " + "Return[" + mValue + "]"); return mValue; } catch (Exception e) { LogUtils.logE( "StateTable.fetchMeProfileId() Exception - " + "Unable to fetch my contact ID", e); return null; } finally { CloseUtils.close(mCursor); mCursor = null; } } /** * Sets the me profile ID. This should only be called once when the me * profile is first synced from the server. * * @param myContactID The local contact ID of the me profile, or null if the * me profile is deleted (the latter is currently possibly by the * UI). * @param writableDb Writable SQLite database for storing the information * @return SUCCESS or a suitable error code. */ public static ServiceStatus modifyMeProfileID(final Long myContactID, final SQLiteDatabase writableDb) { if (Settings.ENABLED_DATABASE_TRACE) { DatabaseHelper.trace(true, "StateTable.modifyMeProfileID() " + "myContactID[" + myContactID + "]"); } ContentValues values = new ContentValues(); values.put(Field.MYCONTACTID.toString(), myContactID); try { if (writableDb.update(TABLE_NAME, values, Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null) <= 0) { LogUtils.logE("StateTable.modifyMeProfileID() " + "Unable to modify my contact ID"); return ServiceStatus.ERROR_DATABASE_CORRUPT; } } catch (SQLException e) { LogUtils.logE("StateTable.modifyMeProfileID() SQLException - " + "Unable to modifyMeProfileID in database", e); return ServiceStatus.ERROR_DATABASE_CORRUPT; } return ServiceStatus.SUCCESS; } /** * Fetches the "me profile changed" flag from the database. This flag is * used to trigger a contact sync with the server. * * @param readableDb Readable SQLite database for fetching the information * @return true if the me profile has changed, false if the me profile * hasn't changed or a database error has occurred. */ public static boolean fetchMeProfileChangedFlag( final SQLiteDatabase readableDb) { boolean mValue = false; Cursor mCursor = null; try { mCursor = readableDb.rawQuery("SELECT " + Field.MYCONTACTCHANGED + " FROM " + TABLE_NAME + " WHERE " + Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null); if (!mCursor.moveToFirst() || mCursor.isNull(0)) { DatabaseHelper.trace(false, "StateTable." + "fetchMeProfileChangedFlag() Return FALSE"); return false; } if (!mCursor.isNull(0)) { mValue = (mCursor.getInt(0) != 0); } DatabaseHelper.trace(false, "StateTable." + "fetchMeProfileChangedFlag() Return[" + mValue + "]"); return mValue; } catch (SQLiteException e) { LogUtils.logE("StateTable.fetchMeProfileChangedFlag() " + "Exception - Unable to fetch my contact changed", e); return false; } finally { CloseUtils.close(mCursor); mCursor = null; } } /** * Sets the "me profile changed" flag in the database to the given value. * * @param myContactChanged The new value for the flag * @param writableDb Writable SQLite database for storing the information * @return SUCCESS or a suitable error code. */ public static ServiceStatus modifyMeProfileChangedFlag( final boolean myContactChanged, final SQLiteDatabase writableDb) { if (Settings.ENABLED_DATABASE_TRACE) { DatabaseHelper.trace(true, "StateTable." + "modifyMeProfileChangedFlag() myContactChanged[" + myContactChanged + "]"); } ContentValues values = new ContentValues(); values.put(Field.MYCONTACTCHANGED.toString(), myContactChanged); try { if (writableDb.update(TABLE_NAME, values, Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null) <= 0) { LogUtils.logE("StateTable.modifyMeProfileChangedFlag() " + "Unable to modify my contact changed flag"); return ServiceStatus.ERROR_DATABASE_CORRUPT; } } catch (SQLException e) { LogUtils.logE("StateTable.modifyMeProfileChangedFlag " + "SQLException - Unable to modifyMeProfileChangedFlag in " + "database", e); return ServiceStatus.ERROR_DATABASE_CORRUPT; } return ServiceStatus.SUCCESS; } /** * Fetches the timestamp of the latest status activity that was synced. Used * to keep track of which activities have already been added. * * @param readableDb Readable SQLite database for fetching the information. * @return The timestamp in milliseconds, or 0 if the is a problem. */ public static long fetchLatestStatusUpdateTime( final SQLiteDatabase readableDb) { Cursor cursor = null; long value = 0; try { cursor = readableDb.rawQuery("SELECT " + Field.LASTSTATUSUPDATE + " FROM " + TABLE_NAME + " WHERE " + Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null); if (cursor.moveToFirst() && !cursor.isNull(0)) { value = (cursor.getLong(0)); } DatabaseHelper.trace(false, "StateTable.fetchLatestStatusUpdate() " + "Returning value[" + value + "]"); } finally { CloseUtils.close(cursor); } return value; } /** * Fetches the timestamp of the oldest status activity that was synced. Used * to keep track of which activities have already been added. * * @param readableDb Readable SQLite database for fetching the information * @return The timestamp in milliseconds */ public static long fetchOldestStatusUpdate( final SQLiteDatabase readableDb) { Cursor cursor = null; long value = 0; try { cursor = readableDb.rawQuery("SELECT " + Field.OLDESTSTATUSUPDATE + " FROM " + TABLE_NAME + " WHERE " + Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null); if (cursor.moveToFirst() && !cursor.isNull(0)) { value = (cursor.getLong(0)); } DatabaseHelper.trace(false, "StateTable.fetchOldestStatusUpdate()" + " [" + value + "]"); } finally { CloseUtils.close(cursor); cursor = null; } return value; } /** * Fetches the timestamp of the oldest SMS that was synced. Used to keep * track of which activities have already been added. * * @param readableDb Readable SQLite database for fetching the information * @return The timestamp in milliseconds */ public static long fetchOldestSmsTime(final SQLiteDatabase readableDb) { Cursor cursor = null; long value = 0; try { cursor = readableDb.rawQuery("SELECT " + Field.OLDESTSMS + " FROM " + TABLE_NAME + " WHERE " + Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null); if (cursor.moveToFirst() && !cursor.isNull(0)) { value = (cursor.getLong(0)); } DatabaseHelper.trace(false, "StateTable.fetchOldestSMS [" + value + "]"); } finally { CloseUtils.close(cursor); cursor = null; } return value; } /** * Fetches the timestamp of the oldest MMS status activity that was synced. * Used to keep track of which activities have already been added. * * @param readableDb Readable SQLite database for fetching the information * @return The timestamp in milliseconds */ public static long fetchOldestMmsTime(final SQLiteDatabase readableDb) { Cursor cursor = null; long value = 0; try { cursor = readableDb.rawQuery("SELECT " + Field.OLDESTMMS + " FROM " + TABLE_NAME + " WHERE " + Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null); if (cursor.moveToFirst() && !cursor.isNull(0)) { value = (cursor.getLong(0)); } DatabaseHelper.trace(false, "StateTable.fetchOldestMMS() Return [" + value + "]"); } finally { CloseUtils.close(cursor); cursor = null; } return value; } /** * Fetches the timestamp of the latest phone call timeline activity that was * synced. Used to keep track of which activities have already been added. * * @param readableDb Readable SQLite database for fetching the information * @return The timestamp in milliseconds, or 0 if there was a problem. */ public static long fetchLatestPhoneCallTime( final SQLiteDatabase readableDb) { long value = 0; Cursor cursor = null; try { cursor = readableDb.rawQuery("SELECT " + Field.LASTPHONECALLUPDATE + " FROM " + TABLE_NAME + " WHERE " + Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null); if (cursor.moveToFirst() && !cursor.isNull(0)) { value = (cursor.getLong(0)); } DatabaseHelper.trace(false, "StateTable.fetchLatestPhoneCallTime()" + " [" + value + "]"); return value; } finally { CloseUtils.close(cursor); } } /** * Fetches the timestamp of the latest SMS timeline activity that was * synced. Used to keep track of which activities have already been added. * * @param readableDb Readable SQLite database for fetching the information * @return The timestamp in milliseconds */ public static long fetchLatestSmsTime(final SQLiteDatabase readableDb) { long value = 0; Cursor cursor = null; try { cursor = readableDb.rawQuery("SELECT " + Field.LASTSMSUPDATE + " FROM " + TABLE_NAME + " WHERE " + Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null); if (cursor.moveToFirst() && !cursor.isNull(0)) { value = (cursor.getLong(0)); } DatabaseHelper.trace(false, "StateTable.fetchLatestSMSTime() " + "mValue[" + value + "]"); return value; } finally { CloseUtils.close(cursor); cursor = null; } } /** * Fetches the timestamp of the latest MMS timeline activity that was * synced. Used to keep track of which activities have already been added. * * @param readableDb Readable SQLite database for fetching the information * @return The timestamp in milliseconds */ public static long fetchLatestMmsTime(final SQLiteDatabase readableDb) { long value = 0; Cursor cursor = null; try { cursor = readableDb.rawQuery("SELECT " + Field.LASTMMSUPDATE + " FROM " + TABLE_NAME + " WHERE " + Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null); if (cursor.moveToFirst() && !cursor.isNull(0)) { value = (cursor.getLong(0)); } DatabaseHelper.trace(false, "StateTable.fetchLastMMSUpdate() " + "mValue[" + value + "]"); } finally { CloseUtils.close(cursor); cursor = null; } return value; } /** * Fetches the timestamp of the oldest phone call timeline activity that was * synced. Used to keep track of which activities have already been added. * * @param readableDb Readable SQLite database for fetching the information * @return The timestamp in milliseconds */ public static long fetchOldestPhoneCallTime( final SQLiteDatabase readableDb) { long value = 0; Cursor cursor = null; try { cursor = readableDb.rawQuery("SELECT " + Field.OLDESTPHONECALL + " FROM " + TABLE_NAME + " WHERE " + Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null); if (cursor.moveToFirst() && !cursor.isNull(0)) { value = (cursor.getLong(0)); } DatabaseHelper.trace(false, "StateTable.fetchOldestPhoneCallTime()" + " [" + value + "]"); } finally { CloseUtils.close(cursor); cursor = null; } return value; } /** * Modifies the timestamp for the last status activity that has been synced. * * @param value The new timestamp value (in milliseconds) * @param writableDb Writable SQLite database for storing the information * @return SUCCESS or a suitable error code. */ public static ServiceStatus modifyLatestStatusUpdateTime(final long value, final SQLiteDatabase writableDb) { if (Settings.ENABLED_DATABASE_TRACE) { DatabaseHelper.trace(true, "StateTable.modifyLatestStatusUpdate() " + "[" + value + "]"); } ContentValues values = new ContentValues(); values.put(Field.LASTSTATUSUPDATE.toString(), value); if (writableDb.update(TABLE_NAME, values, null, null) <= 0) { LogUtils.logE("StateTable.modifyLatestStatusUpdate() " + "Unable to modify last status update"); return ServiceStatus.ERROR_DATABASE_CORRUPT; } return ServiceStatus.SUCCESS; } /** * Modifies the timestamp for the oldest status activity that has been * synced. * * @param value The new timestamp value (in milliseconds) * @param writableDb Writable SQLite database for storing the information * @return SUCCESS or a suitable error code. */ public static ServiceStatus modifyOldestStatusTime(final long value, final SQLiteDatabase writableDb) { if (Settings.ENABLED_DATABASE_TRACE) { DatabaseHelper.trace(true, "StateTable.modifyOldestStatusUpdate()" + " [" + value + "]"); } ContentValues values = new ContentValues(); values.put(Field.OLDESTSTATUSUPDATE.toString(), value); if (writableDb.update(TABLE_NAME, values, null, null) <= 0) { LogUtils.logE("StateTable.modifyOldestStatusUpdate() " + "Unable to modify oldest status update"); return ServiceStatus.ERROR_DATABASE_CORRUPT; } return ServiceStatus.SUCCESS; } /** * Modifies the timestamp for the oldest SMS activity that has been synced. * * @param value The new timestamp value (in milliseconds) * @param writableDb Writable SQLite database for storing the information * @return SUCCESS or a suitable error code. */ public static ServiceStatus modifyOldestSmsTime(final long value, final SQLiteDatabase writableDb) { if (Settings.ENABLED_DATABASE_TRACE) { DatabaseHelper.trace(true, "StateTable.modifyOldestSMSTime() " + "value[" + value + "]"); } ContentValues values = new ContentValues(); values.put(Field.OLDESTSMS.toString(), value); if (writableDb.update(TABLE_NAME, values, null, null) <= 0) { LogUtils.logE("StateTable.modifyOldestSMSTime() " + "Unable to modify oldest sms update"); return ServiceStatus.ERROR_DATABASE_CORRUPT; } return ServiceStatus.SUCCESS; } /** * Modifies the timestamp for the oldest MMS activity that has been synced. * * @param value The new timestamp value (in milliseconds) * @param writableDb Writable SQLite database for storing the information * @return SUCCESS or a suitable error code. */ public static ServiceStatus modifyOldestMmsTime(final long value, final SQLiteDatabase writableDb) { if (Settings.ENABLED_DATABASE_TRACE) { DatabaseHelper.trace(true, "StateTable.modifyOldestMMSTime() " + "value[" + value + "]"); } ContentValues values = new ContentValues(); values.put(Field.OLDESTMMS.toString(), value); if (writableDb.update(TABLE_NAME, values, null, null) <= 0) { LogUtils.logE("StateTable.modifyOldestMMSTime() " + "Unable to modify oldest mms update"); return ServiceStatus.ERROR_DATABASE_CORRUPT; } return ServiceStatus.SUCCESS; } /** * Modifies the timestamp for the last phone call activity that has been * synced. * * @param value The new timestamp value (in milliseconds) * @param writableDb Writable SQLite database for storing the information * @return SUCCESS or a suitable error code. */ public static ServiceStatus modifyLatestPhoneCallTime(final long value, final SQLiteDatabase writableDb) { if (Settings.ENABLED_DATABASE_TRACE) { DatabaseHelper.trace(true, "StateTable." + "modifyLatestPhoneCallTime() [" + value + "]"); } ContentValues values = new ContentValues(); values.put(Field.LASTPHONECALLUPDATE.toString(), value); if (writableDb.update(TABLE_NAME, values, null, null) <= 0) { LogUtils.logE("StateTable.modifyLatestPhoneCallTime() " + "Unable to modify last timeline update"); return ServiceStatus.ERROR_DATABASE_CORRUPT; } return ServiceStatus.SUCCESS; } /** * Modifies the timestamp for the last SMS timeline activity that has been * synced. * * @param value The new timestamp value (in milliseconds) * @param writableDb Writable SQLite database for storing the information * @return SUCCESS or a suitable error code. */ public static ServiceStatus modifyLatestSmsTime(final long value, final SQLiteDatabase writableDb) { if (Settings.ENABLED_DATABASE_TRACE) { DatabaseHelper.trace(true, "StateTable.modifyLatestSMSUpdate() [" + value + "]"); } ContentValues values = new ContentValues(); values.put(Field.LASTSMSUPDATE.toString(), value); if (writableDb.update(TABLE_NAME, values, null, null) <= 0) { LogUtils.logE("StateTable.modifyLatestSMSUpdate() " + "Unable to modify last sms update"); return ServiceStatus.ERROR_DATABASE_CORRUPT; } return ServiceStatus.SUCCESS; } /** * Modifies the timestamp for the last MMS timeline activity that has been * synced. * * @param value The new timestamp value (in milliseconds) * @param writableDb Writable SQLite database for storing the information * @return SUCCESS or a suitable error code. */ public static ServiceStatus modifyLatestMmsTime(final long value, final SQLiteDatabase writableDb) { if (Settings.ENABLED_DATABASE_TRACE) { DatabaseHelper.trace(true, "StateTable.modifyLatestMMSTime() " + "value[" + value + "]"); } ContentValues values = new ContentValues(); values.put(Field.LASTMMSUPDATE.toString(), value); if (writableDb.update(TABLE_NAME, values, null, null) <= 0) { LogUtils.logE("StateTable.modifyLatestMMSTime() " + "Unable to modify last mms update"); return ServiceStatus.ERROR_DATABASE_CORRUPT; } return ServiceStatus.SUCCESS; } /** * Modifies the timestamp for the oldest phone call timeline activity that * has been synced. * * @param value The new timestamp value (in milliseconds) * @param writableDb Writable SQLite database for storing the information * @return SUCCESS or a suitable error code. */ public static ServiceStatus modifyOldestPhoneCallTime(final long value, final SQLiteDatabase writableDb) { if (Settings.ENABLED_DATABASE_TRACE) { DatabaseHelper.trace(true, "StateTable.modifyLastTimelineUpdate()" + " [" + value + "]"); } ContentValues values = new ContentValues(); values.put(Field.OLDESTPHONECALL.toString(), value); if (writableDb.update(TABLE_NAME, values, null, null) <= 0) { LogUtils.logE("StateTable.modifyOldestPhoneCallTime() " + "Unable to modify last timeline update"); return ServiceStatus.ERROR_DATABASE_CORRUPT; } return ServiceStatus.SUCCESS; } /** * Fetches the current me profile revision for the server sync. * * @param readableDb Readable SQLite database for fetching the information * @return The revision number or null if an error occurs. */ public static long fetchMeProfileRevision( final SQLiteDatabase readableDb) { DatabaseHelper.trace(false, "StateTable.fetchMeProfileRevision()"); Cursor c = null; try { c = readableDb.rawQuery("SELECT " + Field.MEPROFILEREVISION + " FROM " + TABLE_NAME + " WHERE " + Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null); if (!c.moveToFirst() || c.isNull(0)) { return 0; } return c.getLong(0); } catch (SQLiteException e) { LogUtils.logE("StateTable.fetchMeProfileRevision Exception - " + "Unable to fetch me profile revision", e); } finally { CloseUtils.close(c); c = null; } return 0; } /** * Stores a new server me profile revision in the database. * * @param revision New revision number * @param writableDb Writable SQLite database for storing the information * @return true if successful, false otherwise */ public static boolean modifyMeProfileRevision(final long revision, final SQLiteDatabase writableDb) { if (Settings.ENABLED_DATABASE_TRACE) { DatabaseHelper.trace(true, "StateTable.modifyMeProfileRevision() " + "revision[" + revision + "]"); } ContentValues values = new ContentValues(); values.put(Field.MEPROFILEREVISION.toString(), revision); try { if (writableDb.update(TABLE_NAME, values, Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null) <= 0) { LogUtils.logE("StateTable.modifyMeProfileRevision() " + "Unable to modify me profile revision state"); return false; } } catch (SQLException e) { LogUtils.logE("StateTable.modifyMeProfileRevision Exception - " + "Unable to modify profile revision", e); return false; } return true; } /** * Fetches the "me profile avatar changed flag" from the state table. * * @param readableDb The SQLite database with read access * @return true if the avatar has changed, false otherwise */ public static boolean fetchMeProfileAvatarChangedFlag( final SQLiteDatabase readableDb) { boolean mValue = false; Cursor mCursor = null; try { mCursor = readableDb.rawQuery("SELECT " + Field.MEPROFILEAVATARCHANGED + " FROM " + TABLE_NAME + " WHERE " + Field.STATEID + " = " + PRIMARY_STATE_KEY_VALUE, null); if (!mCursor.moveToFirst() || mCursor.isNull(0)) { DatabaseHelper.trace(false, "StateTable." + "fetchMeProfileAvatarChangedFlag() Return FALSE"); return false; } mValue = (mCursor.getInt(0) != 0); DatabaseHelper.trace(false, "StateTable." + "fetchMeProfileAvatarChangedFlag() Return[" + mValue + "]"); return mValue; } catch (SQLException e) { LogUtils.logE("StateTable.fetchMeProfileAvatarChangedFlag() " + "Exception", e); return false; } finally { CloseUtils.close(mCursor); mCursor = null; } } }