/* * 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.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; import com.vodafone360.people.R; import com.vodafone360.people.Settings; import com.vodafone360.people.database.DatabaseHelper; import com.vodafone360.people.datatypes.GroupItem; 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 Groups database table. The * groups table stores the information about each group from the server. This * class is never instantiated hence all methods must be static. * * @version %I%, %G% */ public abstract class GroupsTable { /** * The name of the table as it appears in the database. */ public static final String TABLE_NAME = "ZybGroups"; /** * Special ID for the ALL group */ public static final long GROUP_ALL = -1000; /** * Special ID for the ONLINE contacts group (to be added later) */ public static final long GROUP_ONLINE = -1001; /** * Special ID for the phonebook contacts group */ public static final long GROUP_PHONEBOOK = -1002; /** * Special ID for the connected friends group */ public static final long GROUP_CONNECTED_FRIENDS = 2; /** * An enumeration of all the field names in the database. */ public static enum Field { LOCALGROUPID("LocalGroupId"), SERVERGROUPID("ServerGroupId"), GROUPTYPE("GroupType"), ISREADONLY("IsReadOnly"), REQUIRESLOCALISATION("RequiresLocalisation"), ISSYSTEMGROUP("IsSystemGroup"), ISSMARTGROUP("IsSmartGroup"), USERID("UserId"), NAME("Name"), IMAGEMIMETYPE("ImageMimeType"), IMAGEBYTES("ImageBytes"), COLOR("Color"); /** * The name of the field as it appears in the database */ private final 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; } } /** * Creates Groups Table and populate it with system groups. * * @param context A context for reading strings from the resources * @param writeableDb A writable SQLite database * @throws SQLException If an SQL compilation error occurs */ public static void create(Context context, SQLiteDatabase writableDb) throws SQLException { DatabaseHelper.trace(true, "GroupsTable.create()"); writableDb.execSQL("CREATE TABLE " + TABLE_NAME + " (" + Field.LOCALGROUPID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + Field.SERVERGROUPID + " LONG, " + Field.GROUPTYPE + " INTEGER, " + Field.ISREADONLY + " BOOLEAN, " + Field.REQUIRESLOCALISATION + " BOOLEAN, " + Field.ISSYSTEMGROUP + " BOOLEAN, " + Field.ISSMARTGROUP + " BOOLEAN, " + Field.USERID + " LONG, " + Field.NAME + " TEXT, " + Field.IMAGEMIMETYPE + " TEXT, " + Field.IMAGEBYTES + " BINARY, " + Field.COLOR + " TEXT);"); populateSystemGroups(context, writableDb); } /** * Fetches the list of table fields that can be injected into an SQL query * statement. The {@link #getQueryData(Cursor)} method can be used to obtain * the data from the query. * * @return The query string * @see #getQueryData(Cursor). */ private static String getFullQueryList() { return Field.LOCALGROUPID + ", " + Field.SERVERGROUPID + ", " + Field.GROUPTYPE + ", " + Field.ISREADONLY + ", " + Field.REQUIRESLOCALISATION + ", " + Field.ISSYSTEMGROUP + ", " + Field.ISSMARTGROUP + ", " + Field.USERID + ", " + Field.NAME + ", " + Field.IMAGEMIMETYPE + ", " + Field.IMAGEBYTES + ", " + Field.COLOR; } /** * Returns a full SQL query statement to fetch a set of groups from the * table. The {@link #getQueryData(Cursor)} method can be used to obtain the * data from the query. * * @param whereClause An SQL where clause (without the "WHERE"). Cannot be * null. * @return The query string * @see #getQueryData(Cursor). */ private static String getQueryStringSql(String whereClause) { String whereString = ""; if (whereClause != null) { whereString = " WHERE " + whereClause; } return "SELECT " + getFullQueryList() + " FROM " + TABLE_NAME + whereString; } /** * Column indices which match the query string returned by * {@link #getFullQueryList()}. */ private static final int LOCALGROUPID = 0; private static final int SERVERGROUPID = 1; private static final int GROUPTYPE = 2; private static final int ISREADONLY = 3; private static final int REQUIRESLOCALISATION = 4; private static final int ISSYSTEMGROUP = 5; private static final int ISSMARTGROUP = 6; private static final int USERID = 7; private static final int NAME = 8; private static final int IMAGEMIMETYPE = 9; private static final int IMAGEBYTES = 10; private static final int COLOR = 11; /** * Fetches the group data from the current record of the given cursor. * * @param c Cursor returned by one of the {@link #getFullQueryList()} based * query methods. * @return Filled in GroupItem object */ public static GroupItem getQueryData(Cursor c) { GroupItem group = new GroupItem(); if (!c.isNull(LOCALGROUPID)) { group.mLocalGroupId = c.getLong(LOCALGROUPID); } if (!c.isNull(SERVERGROUPID)) { group.mId = c.getLong(SERVERGROUPID); } if (!c.isNull(GROUPTYPE)) { group.mGroupType = c.getInt(GROUPTYPE); } if (!c.isNull(ISREADONLY)) { group.mIsReadOnly = (c.getShort(ISREADONLY) == 0 ? false : true); } if (!c.isNull(REQUIRESLOCALISATION)) { group.mRequiresLocalisation = (c.getShort(REQUIRESLOCALISATION) == 0 ? false : true); } if (!c.isNull(ISSYSTEMGROUP)) { group.mIsSystemGroup = (c.getShort(ISSYSTEMGROUP) == 0 ? false : true); } if (!c.isNull(ISSMARTGROUP)) { group.mIsSmartGroup = (c.getShort(ISSMARTGROUP) == 0 ? false : true); } if (!c.isNull(USERID)) { group.mUserId = c.getLong(USERID); } if (!c.isNull(NAME)) { group.mName = c.getString(NAME); } if (!c.isNull(IMAGEMIMETYPE)) { group.mImageMimeType = c.getString(IMAGEMIMETYPE); } if (!c.isNull(IMAGEBYTES)) { group.mImageBytes = ByteBuffer.wrap(c.getBlob(IMAGEBYTES)); } if (!c.isNull(COLOR)) { group.mColor = c.getString(COLOR); } return group; } /** * Returns a ContentValues object that can be used to insert or modify a * group in the table. * * @param group The source GroupItem object * @return The ContentValues object containing the data. * @note NULL fields in the given group will not be included in the * ContentValues */ private static ContentValues fillUpdateData(GroupItem group) { ContentValues contactDetailValues = new ContentValues(); if (group.mLocalGroupId != null) { contactDetailValues.put(Field.LOCALGROUPID.toString(), group.mLocalGroupId); } if (group.mId != null) { contactDetailValues.put(Field.SERVERGROUPID.toString(), group.mId); } if (group.mGroupType != null) { contactDetailValues.put(Field.GROUPTYPE.toString(), group.mGroupType); } if (group.mIsReadOnly != null) { contactDetailValues.put(Field.ISREADONLY.toString(), group.mIsReadOnly); } if (group.mRequiresLocalisation != null) { contactDetailValues.put(Field.REQUIRESLOCALISATION.toString(), group.mRequiresLocalisation); } if (group.mIsSystemGroup != null) { contactDetailValues.put(Field.ISSYSTEMGROUP.toString(), group.mIsSystemGroup); } if (group.mIsSmartGroup != null) { contactDetailValues.put(Field.ISSMARTGROUP.toString(), group.mIsSmartGroup); } if (group.mUserId != null) { contactDetailValues.put(Field.USERID.toString(), group.mUserId); } if (group.mName != null) { contactDetailValues.put(Field.NAME.toString(), group.mName); } if (group.mImageMimeType != null) { contactDetailValues.put(Field.IMAGEMIMETYPE.toString(), group.mImageMimeType); } if (group.mImageBytes != null) { contactDetailValues.put(Field.IMAGEBYTES.toString(), group.mImageBytes.array()); } if (group.mColor != null) { contactDetailValues.put(Field.COLOR.toString(), group.mColor); } return contactDetailValues; } /** * Fetches a list of all the available groups. * * @param groupList A list that will be populated with the result. * @param readableDb Readable SQLite database * @return SUCCESS or a suitable error */ public static ServiceStatus fetchGroupList(ArrayList<GroupItem> groupList, SQLiteDatabase readableDb) { DatabaseHelper.trace(false, "GroupsTable.fetchGroupList()"); groupList.clear(); Cursor c = null; try { String query = "SELECT " + getFullQueryList() + " FROM " + TABLE_NAME; c = readableDb.rawQuery(query, null); while (c.moveToNext()) { groupList.add(getQueryData(c)); } } catch (SQLiteException e) { LogUtils.logE("GroupsTable.fetchGroupList() Exception - Unable to fetch group list", e); return ServiceStatus.ERROR_DATABASE_CORRUPT; } finally { CloseUtils.close(c); c = null; } return ServiceStatus.SUCCESS; } /** * Adds list of groups to the table * * @param groupList The list to add * @param writableDb Writable SQLite database * @return SUCCESS or a suitable error code */ public static ServiceStatus addGroupList(List<GroupItem> groupList, SQLiteDatabase writableDb) { try { writableDb.beginTransaction(); for (GroupItem mGroupItem : groupList) { if (Settings.ENABLED_DATABASE_TRACE) { DatabaseHelper.trace(true, "GroupsTable.addGroupList() mName[" + mGroupItem.mName + "]"); } mGroupItem.mLocalGroupId = writableDb.insertOrThrow(TABLE_NAME, null, fillUpdateData(mGroupItem)); if (mGroupItem.mLocalGroupId < 0) { LogUtils.logE("GroupsTable.addGroupList() Unable to add group - mName[" + mGroupItem.mName + ""); writableDb.endTransaction(); return ServiceStatus.ERROR_DATABASE_CORRUPT; } } writableDb.setTransactionSuccessful(); } catch (SQLException e) { LogUtils.logE("GroupsTable.addGroupList() SQLException - Unable to add group", e); return ServiceStatus.ERROR_DATABASE_CORRUPT; } finally { if (writableDb != null) { writableDb.endTransaction(); } } return ServiceStatus.SUCCESS; } /** * Removes all groups from the table. The * {@link #populateSystemGroups(Context, SQLiteDatabase)} function should be * called afterwards to ensure the system groups are restored. * * @param writableDb Writable SQLite database * @return SUCCESS or a suitable error code */ public static ServiceStatus deleteAllGroups(SQLiteDatabase writableDb) { DatabaseHelper.trace(true, "GroupsTable.deleteAllGroups()"); try { if (writableDb.delete(TABLE_NAME, null, null) < 0) { LogUtils.logE("GroupsTable.deleteAllGroups() Unable to delete all groups"); return ServiceStatus.ERROR_DATABASE_CORRUPT; } } catch (SQLException e) { LogUtils.logE( "GroupsTable.deleteAllGroups() SQLException - Unable to delete all groups", e); return ServiceStatus.ERROR_DATABASE_CORRUPT; } return ServiceStatus.SUCCESS; } /** * Fetches a cursor that can be used for browsing the groups. The * {@link #getQueryData(Cursor)} method can be used to fetch the data of a * particular record in the cursor. * * @param readableDb Readable SQLite database * @return The cursor, or null if an error occurs */ public static Cursor getGroupCursor(SQLiteDatabase readableDb) { DatabaseHelper.trace(false, "GroupsTable.getGroupCursor()"); try { return readableDb.rawQuery(getQueryStringSql("NAME != 'Private'"), null); } catch (SQLiteException e) { LogUtils.logE("GroupsTable.getGroupCursor() Exception - Unable to fetch group cursor", e); return null; } } /** * Fetches a cursor that can be used for browsing the groups exluding the * Connected friends item. The {@link #getQueryData(Cursor)} method can be * used to fetch the data of a particular record in the cursor. * * @param readableDb Readable SQLite database * @return The cursor, or null if an error occurs */ public static Cursor getGroupCursorExcludeConnectedFriends( final SQLiteDatabase readableDb) { DatabaseHelper.trace(false, "GroupsTable.getGroupCursorExcludeConnectedFriends()"); try { return readableDb.rawQuery( getQueryStringSql("NAME != 'Private' AND " + Field.SERVERGROUPID + " != " + GROUP_CONNECTED_FRIENDS), null); } catch (SQLiteException e) { LogUtils .logE( "GroupsTable.getGroupCursorExcludeConnectedFriends()" + " Exception - Unable to fetch group" + " cursor", e); return null; } } /** * Populates the table if system groups that are specified in the resources. * * @param context The context for reading the app resources * @param writableDb Writable SQLite database for updating the table * @return SUCCESS or a suitable error code */ public static ServiceStatus populateSystemGroups(Context context, SQLiteDatabase writableDb) { final List<GroupItem> groupList = new ArrayList<GroupItem>(); GroupItem all = new GroupItem(); all.mName = context.getString(R.string.ContactListActivity_group_all); all.mIsReadOnly = true; all.mId = GROUP_ALL; groupList.add(all); GroupItem online = new GroupItem(); online.mName = context.getString(R.string.ContactListActivity_group_online); online.mIsReadOnly = true; online.mId = GROUP_ONLINE; groupList.add(online); GroupItem phonebook = new GroupItem(); phonebook.mName = context.getString(R.string.ContactListActivity_group_phonebook); phonebook.mIsReadOnly = true; phonebook.mId = GROUP_PHONEBOOK; groupList.add(phonebook); return addGroupList(groupList, writableDb); } }