/* * 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.Enumeration; import java.util.Hashtable; import java.util.Iterator; import android.os.Parcel; import android.os.Parcelable; import com.vodafone360.people.Settings; import com.vodafone360.people.datatypes.ContactSummary; import com.vodafone360.people.datatypes.ContactSummary.OnlineStatus; import com.vodafone360.people.engine.presence.NetworkPresence.SocialNetwork; import com.vodafone360.people.utils.LogUtils; /** * User is a class encapsulating the information about a user's presence state. */ public class User implements Parcelable { /** * This constant is to identify the key for the {@link SocialNetwork} name * in the Bundle of UiEvent generated by presence status change. */ public static final String NETWORK = "network"; /** * This constant is to identify the key for the {@link OnlineStatus} name * in the Bundle of UiEvent generated by presence status change. */ public static final String STATUS = "status"; /** * This constant is to identify the key for the source of status change delivered * in the Bundle of UiEvent generated by presence status change. */ public static final String SOURCE = "source"; /** * This constant is to identify the source of status change delivered * in the Bundle of UiEvent generated by presence status change as "requested by client". */ public static final int SOURCE_REQUESTED = 0; /** * This constant is to identify the source of status change delivered * in the Bundle of UiEvent generated by presence status change as "received by client". */ public static final int SOURCE_RECEIVED = 1; /** * This constant is to identify the source of status change delivered * in the Bundle of UiEvent generated by presence status change as "timed out". */ public static final int SOURCE_TIMED_OUT = 2; private static final String COLUMNS = "::"; private static final String PRESENCE_PC = "pc", PRESENCE_MOBILE = "mobile"; /** Database ID of the contact (e.g. "userid@gmail.com"). **/ private long mLocalContactId; /** Overall presence state displayed in the common contact list. **/ private int mOverallOnline; /** * Communities presence status: * {google:online, pc:online, mobile:online}. */ private ArrayList<NetworkPresence> mPayload; /** * Default Constructor. */ public User() { } /** * Constructor. * * @param userId - user id in the contact list, e.g. * "google::userid@gmail.com" or "882339" * @param payload - communities presence status {google:online, pc:online, * mobile:online} */ public User(String userId, Hashtable<String, String> payload) { if (payload != null) { if (Settings.LOG_PRESENCE_PUSH_ON_LOGCAT) { LogUtils.logWithName(LogUtils.PRESENCE_INFO_TAG, "user id:"+ userId + ", " + payload); } if (payload.containsKey(PRESENCE_PC)) { if (Settings.LOG_PRESENCE_PUSH_ON_LOGCAT) { LogUtils.logWithName(LogUtils.PRESENCE_INFO_TAG, "removed 360PC presence for " + userId); } payload.remove(PRESENCE_PC); } if (payload.containsKey(PRESENCE_MOBILE)) { if (Settings.LOG_PRESENCE_PUSH_ON_LOGCAT) { LogUtils.logWithName(LogUtils.PRESENCE_INFO_TAG, "removed 360MOBILE presence for " + userId); } payload.remove(PRESENCE_MOBILE); } mOverallOnline = isOverallOnline(payload); mPayload = createPayload(userId, payload); } } /** * This method returns the localContactId for this contact in DB across the * application . * * @return the localContactId for this contact in DB */ public long getLocalContactId() { return mLocalContactId; } /** * This method sets localContactId for this User. The id comes from DB. * @param mLocalContactId long id. */ public void setLocalContactId(long mLocalContactId) { this.mLocalContactId = mLocalContactId; } /** * Returns communities presence status * * @return communities presence status, e.g. {google:online, pc:online, * mobile:online} */ public ArrayList<NetworkPresence> getPayload() { return mPayload; } /** * The method returns the OnlineStatus of this user on the provided network * @param network SocialNetwork. * @return NULL if network is null, OnlineStatus.OFFLINE if the information * about presence state on this network is not available, and actual status in other cases. */ public OnlineStatus getStatusForNetwork(SocialNetwork network) { if (network == null) { return null; } OnlineStatus os = OnlineStatus.OFFLINE; if (mPayload != null) { for (NetworkPresence np : mPayload) { if (np.getNetworkId() == network.ordinal()) { os = OnlineStatus.getValue(np.getOnlineStatusId()); break; } } } return os; } /** * Returns communities presence status * * @return communities presence status, e.g. {google:online, pc:online, * mobile:online} */ public void setPayload(ArrayList<NetworkPresence> payload) { mPayload = payload; } /** * Returns the overall user presence status * * @return true if user is online at least at one community, e.g. true if * {google:offline, pc:offline, mobile:online} */ private int isOverallOnline(Hashtable<String, String> payload) { if (payload != null) { if (payload.values().contains(ContactSummary.OnlineStatus.ONLINE.toString())) return ContactSummary.OnlineStatus.ONLINE.ordinal(); if (payload.values().contains(ContactSummary.OnlineStatus.INVISIBLE.toString())) return ContactSummary.OnlineStatus.INVISIBLE.ordinal(); if (payload.values().contains(ContactSummary.OnlineStatus.IDLE.toString())) return ContactSummary.OnlineStatus.IDLE.ordinal(); } return ContactSummary.OnlineStatus.OFFLINE.ordinal(); } /** * Returns the overall user presence status: in fact the one from the below * status states first encountered for all known user accounts next: * INVISIBLE, ONLINE, IDLE, OFFLINE * * @return presence state */ public int isOnline() { return mOverallOnline; } /** * @param payload * @return */ private ArrayList<NetworkPresence> createPayload(String userId, Hashtable<String, String> payload) { ArrayList<NetworkPresence> presenceList = new ArrayList<NetworkPresence>(payload.size()); String parsedUserId = parseUserName(userId); String key = null; SocialNetwork network = null; String value = null; OnlineStatus status = null; for (Enumeration<String> en = payload.keys(); en.hasMoreElements();) { key = en.nextElement(); network = SocialNetwork.getValue(key); if (network != null) { int keyIdx = network.ordinal(); value = payload.get(key); if (value != null) { status = OnlineStatus.getValue(value); if (status != null) { int valueIdx = status.ordinal(); presenceList.add(new NetworkPresence(parsedUserId, keyIdx, valueIdx)); } } } } return presenceList; } /** * @param user * @return */ private static String parseUserName(String userId) { if (userId != null) { int columnsIndex = userId.indexOf(COLUMNS); if (columnsIndex > -1) { return userId.substring(columnsIndex + COLUMNS.length()); } else { return userId; } } return null; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + mOverallOnline; result = prime * result + ((mPayload == null) ? 0 : mPayload.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; User other = (User)obj; if (mOverallOnline != other.mOverallOnline) return false; if (mPayload == null) { if (other.mPayload != null) return false; } else if (!mPayload.equals(other.mPayload)) return false; return true; } @Override public String toString() { final StringBuffer sb = new StringBuffer("User [mLocalContactId="); sb.append(mLocalContactId); sb.append(", mOverallOnline="); sb.append(mOverallOnline); sb.append(", mPayload="); sb.append(mPayload); sb.append("]"); return sb.toString(); } /** * This method sets the overall user presence status, * @parameter the online status id - the ordinal, see @OnlineStatus */ public void setOverallOnline(int overallOnline) { this.mOverallOnline = overallOnline; } /** * This method removes the network presence information with the given presence id from the User. * @param ordinal - the network id, ordinal in @see SocialNetworks */ public void removeNetwork(int ordinal) { Iterator<NetworkPresence> itr = mPayload.iterator(); NetworkPresence presence = null; while (itr.hasNext()) { presence = itr.next(); if (presence.getNetworkId() == ordinal) { itr.remove(); break; } } } @Override public final int describeContents() { return 0; } @Override public final void writeToParcel(final Parcel dest, final int flags) { dest.writeLong(mLocalContactId); dest.writeInt(mOverallOnline); writePayloadToParcel(dest, flags); } /*** * Parcelable constructor for User. * * @param source User Parcel. */ private void readFromParcel(final Parcel source) { mLocalContactId = source.readLong(); mOverallOnline = source.readInt(); readPayloadFromParcel(source); } /** * Helper function to get the payload into & out of a parcel. * Keeping this code in a helper function should help maintenance. * Doing it this way seems to be the only way to avoid constant * ClassNotFoundExceptions even with proper classloaders in place. * * @param dest User Parcel. * @param flags Flags. */ public final void writePayloadToParcel(final Parcel dest, final int flags) { // Locals more efficient than members on Dalvik VM ArrayList<NetworkPresence> payload = mPayload; dest.writeInt(payload.size()); for (NetworkPresence netPres : payload) { netPres.writeToParcel(dest, flags); } } /** * Helper function to get the payload into & out of a parcel. * Keeping this code in a helper function should help maintenance. * Doing it this way seems to be the only way to avoid constant * ClassNotFoundExceptions even with proper classloaders in place. * * @param source User Parcel. */ private void readPayloadFromParcel(final Parcel source) { // Could do this directly into mPayload but locals are more efficient ArrayList<NetworkPresence> payload = new ArrayList<NetworkPresence>(); for (int i = 0; i < source.readInt(); i++) { payload.add(new NetworkPresence(source)); } mPayload = payload; } /*** * Parcelable.Creator for User. */ public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>() { @Override public User createFromParcel(final Parcel source) { User newUser = new User(); newUser.readFromParcel(source); return newUser; } @Override public User[] newArray(final int size) { return new User[size]; } }; }