/*
* 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.engine.presence;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import android.database.sqlite.SQLiteDatabase;
import android.text.TextUtils;
import com.vodafone360.people.database.DatabaseHelper;
import com.vodafone360.people.database.tables.ContactDetailsTable;
import com.vodafone360.people.database.tables.ContactSummaryTable;
import com.vodafone360.people.database.tables.PresenceTable;
import com.vodafone360.people.datatypes.Contact;
import com.vodafone360.people.datatypes.ContactDetail;
import com.vodafone360.people.datatypes.Identity;
import com.vodafone360.people.datatypes.ContactSummary.OnlineStatus;
import com.vodafone360.people.engine.EngineManager;
import com.vodafone360.people.engine.meprofile.SyncMeDbUtils;
import com.vodafone360.people.engine.presence.NetworkPresence.SocialNetwork;
import com.vodafone360.people.service.ServiceStatus;
import com.vodafone360.people.service.agent.UiAgent;
import com.vodafone360.people.utils.LogUtils;
public class PresenceDbUtils {
/**
* Invalid general purpose id
* TODO: Move this and all other values like this to a common place
*/
private static final long INVALID_ID = -1L;
/**
* the user id of the me profile contact
*/
private static long sMeProfileUserId = INVALID_ID;
/**
* the local contact id of the me profile contact
*/
private static long sMeProfileLocalContactId = INVALID_ID;
public static void resetMeProfileIds() {
sMeProfileUserId = INVALID_ID;
sMeProfileLocalContactId = INVALID_ID;
}
/**
* This method returns true if the provided user id matches the one of me profile.
* @return TRUE if the provided user id matches the one of me profile.
*/
private static boolean isMeProfile(String userId, DatabaseHelper databaseHelper) {
return userId.equals(String.valueOf(getMeProfileUserId(databaseHelper)));
}
/**
* @param databaseHelper
* @return
*/
protected static Long getMeProfileUserId(DatabaseHelper databaseHelper) {
if (sMeProfileUserId == INVALID_ID) {
Contact meProfile = new Contact();
if (SyncMeDbUtils.fetchMeProfile(databaseHelper, meProfile) != ServiceStatus.ERROR_NOT_FOUND) {
sMeProfileUserId = meProfile.userID;
sMeProfileLocalContactId = meProfile.localContactID;
}
}
return sMeProfileUserId;
}
/**
* @param databaseHelper
* @return
*/
protected static User getMeProfilePresenceStatus(DatabaseHelper databaseHelper) {
// if
// (!sMeProfileLocalContactId.equals(databaseHelper.getMeProfileId())) {
Long meProfileId = SyncMeDbUtils.getMeProfileLocalContactId(databaseHelper);
sMeProfileLocalContactId =
(meProfileId == null || meProfileId.intValue() == INVALID_ID) ? INVALID_ID
: meProfileId;
// LogUtils.logE("The DB Helper and Utils IDs are not synchronized");
// }
if(meProfileId == INVALID_ID) {
LogUtils.logW(
"PresenceDbUtils.getMeProfilePresenceStatus() No local me contact id!");
}
User user = PresenceTable.getUserPresenceByLocalContactId(
meProfileId, databaseHelper.getWritableDatabase());
if (user == null || (user.getPayload() == null)) { // the table is
/* empty, need to set the status for the 1st time
* Get presence list constructed from identities
*/
Hashtable<String, String> status =
EngineManager.getInstance().getPresenceEngine().
getPresencesForStatus(OnlineStatus.ONLINE);
user = new User(String.valueOf(getMeProfileUserId(databaseHelper)), status);
}
return user;
}
/**
* This method returns wrapper with the presence information for all user
* networks
*
* @param localContactId - the localContactId of the contact we want to get
* presence states information for.
* @param databaseHelper
* @return User wrapper with the presence information for all user networks.
* If no information is on the database the payload is NULL
*/
public static User getUserPresenceStatusByLocalContactId(long localContactId,
DatabaseHelper databaseHelper) {
User user = PresenceTable.getUserPresenceByLocalContactId(localContactId, databaseHelper
.getWritableDatabase());
LogUtils.logW("UI called getUserPresenceStatusByLocalContactId: " + user);
return user;
}
/**
* Here we update the PresenceTable, and the ContactSummaryTable afterwards
* the HandlerAgent receives the notification of presence states changes.
*
* @param users List<User> - the list of user presence states
* @param idListeningTo long - local contact id which this UI is watching, -1 is all contacts
* @param dbHelper DatabaseHelper - the database.
* @return TRUE if database has changed in result of the update.
*/
protected static boolean updateDatabase(List<User> users, long idListeningTo,
DatabaseHelper dbHelper) {
boolean presenceChanged = false;
boolean deleteNetworks = false;
// list of network presence information we ignore - the networks where the user is offline.
ArrayList<Integer> ignoredNetworks = new ArrayList<Integer>();
SQLiteDatabase writableDb = dbHelper.getWritableDatabase();
for (User user : users) {
if (!user.getPayload().isEmpty()) {
long localContactId = -1;
ArrayList<NetworkPresence> payload = user.getPayload();
// if it is the me profile User
boolean meProfile = false;
String userId = null;
int networkId = 0;
for (NetworkPresence presence : payload) {
userId = presence.getUserId();
if (!TextUtils.isEmpty(userId)) {
networkId = presence.getNetworkId();
// if this is me profile contact
if (isMeProfile(userId, dbHelper)) {
localContactId = sMeProfileLocalContactId;
meProfile = true;
} else { // 3rd party accounts
localContactId = ContactDetailsTable.findLocalContactIdByKey(
SocialNetwork.getSocialNetworkValue(networkId).toString(), userId,
ContactDetail.DetailKeys.VCARD_IMADDRESS, writableDb);
if (localContactId != -1) {
break;
}
}
}
}
// set the local contact id
user.setLocalContactId(localContactId);
if (meProfile) {
if (deleteNetworks = processMeProfile(presenceChanged, user, ignoredNetworks)) {
// delete the information about offline networks from PresenceTable
PresenceTable.setTPCNetworksOffline(ignoredNetworks, writableDb);
}
}
if (user.getLocalContactId() > -1) {
// will not save infos from the ignored networks
updateUserRecord(user, ignoredNetworks, writableDb);
if (user.getLocalContactId() == idListeningTo) {
presenceChanged = true;
}
}
}
}
// if contact summary table needs extra refresh, to make sure no statuses are displayed for offline TPC networks users
if (deleteNetworks) {
ArrayList<Long> userIds = PresenceTable.getLocalContactIds(dbHelper.getWritableDatabase());
ContactSummaryTable.setUsersOffline(userIds);
presenceChanged = true;
}
if (idListeningTo == UiAgent.ALL_USERS) {
presenceChanged = true;
}
return presenceChanged;
}
/**
* This method writes the user presence status change from the passed User object
* to the database and then fills the same User object with updated information.
* @param user - the User presence change.
* @param ignoredNetworks - the networks information from which must be ignored.
* @param writableDb - database.
*/
private static void updateUserRecord(User user , ArrayList<Integer> ignoredNetworks, SQLiteDatabase writableDb) {
// write the user presence update into the database and read the complete wrapper
PresenceTable.updateUser(user, ignoredNetworks, writableDb);
PresenceTable.getUserPresence(user, writableDb);
// update the user aggregated presence state in the ContactSummaryTable
ContactSummaryTable.updateOnlineStatus(user);
}
/**
* This method alters the User wrapper of me profile,
* and returns true if me profile information contains the ignored TPC networks information.
* Based on the result this information may be deleted.
* @param removePCPresence - if TRUE the PC network will be removed from the network list.
* @param user - the me profile wrapper.
* @param ignoredNetworks - the list if ignored integer network ids.
* @return
*/
private static boolean processMeProfile(boolean removePCPresence, User user, ArrayList<Integer> ignoredNetworks){
if (removePCPresence) {
int max = OnlineStatus.OFFLINE.ordinal();
// calculate the new aggregated presence status
for (NetworkPresence presence : user.getPayload()) {
if (presence.getOnlineStatusId() > max) {
max = presence.getOnlineStatusId();
}
}
user.setOverallOnline(max);
}
// the list of chat network ids in this User wrapper
ArrayList<Integer> userNetworks = new ArrayList<Integer>();
ArrayList<NetworkPresence> payload = user.getPayload();
for (NetworkPresence presence : payload) {
int networkId = presence.getNetworkId();
userNetworks.add(networkId);
// 1. ignore offline TPC networks
if (presence.getOnlineStatusId() == OnlineStatus.OFFLINE.ordinal()) {
ignoredNetworks.add(networkId);
}
}
// 2. ignore the TPC networks presence state for which is unknown
ArrayList<Identity> identities = EngineManager.getInstance().getIdentityEngine().getMyChattableIdentities();
SocialNetwork network = null;
for (Identity identity : identities) {
network = SocialNetwork.getValue(identity.mNetwork);
if (network != null) {
if (!userNetworks.contains(network.ordinal())) {
ignoredNetworks.add(network.ordinal());
}
}
}
return !ignoredNetworks.isEmpty();
}
protected static boolean updateMyPresence(User user, DatabaseHelper dbHelper) {
boolean contactsChanged = false;
if (PresenceTable.updateUser(
user, null, dbHelper.getWritableDatabase()) != PresenceTable.USER_NOTADDED) {
contactsChanged = (ContactSummaryTable.updateOnlineStatus(user) == ServiceStatus.SUCCESS);
}
return contactsChanged;
}
/**
* Set all users to offline state
*
* @param dbHelper
*/
protected static void setPresenceOfflineInDatabase(DatabaseHelper dbHelper) {
SQLiteDatabase writableDatabase = dbHelper.getWritableDatabase();
PresenceTable.setAllUsersOffline(writableDatabase);
ContactSummaryTable.setOfflineStatus();
}
/**
* Removes all presence infos besides those related to MeProfile
*
* @param dbHelper
*/
protected static void resetPresenceStatesAcceptForMe(long localContactIdOfMe,
DatabaseHelper dbHelper) {
SQLiteDatabase writableDb = dbHelper.getWritableDatabase();
if (writableDb != null) {
LogUtils.logW(" PresenceDBUtils.resetPresenceStatesAcceptForMe: "
+ "#rows affected by delete method "
+ PresenceTable.setAllUsersOfflineExceptForMe(localContactIdOfMe, writableDb));
ContactSummaryTable.setOfflineStatusExceptForMe(localContactIdOfMe);
}
}
}