/*
* 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.identities;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import android.os.Bundle;
import com.vodafone360.people.database.DatabaseHelper;
import com.vodafone360.people.database.tables.MyIdentitiesCacheTable;
import com.vodafone360.people.datatypes.BaseDataType;
import com.vodafone360.people.datatypes.Identity;
import com.vodafone360.people.datatypes.IdentityCapability;
import com.vodafone360.people.datatypes.PushEvent;
import com.vodafone360.people.datatypes.StatusMsg;
import com.vodafone360.people.engine.BaseEngine;
import com.vodafone360.people.engine.IEngineEventCallback;
import com.vodafone360.people.engine.EngineManager.EngineId;
import com.vodafone360.people.service.ServiceStatus;
import com.vodafone360.people.service.ServiceUiRequest;
import com.vodafone360.people.service.agent.UiAgent;
import com.vodafone360.people.service.io.ResponseQueue.DecodedResponse;
import com.vodafone360.people.service.io.api.Identities;
import com.vodafone360.people.service.io.rpg.PushMessageTypes;
import com.vodafone360.people.service.transport.ConnectionManager;
import com.vodafone360.people.service.transport.tcp.ITcpConnectionListener;
import com.vodafone360.people.utils.LogUtils;
import com.vodafone360.people.utils.ThirdPartyAccount;
/**
* Engine responsible for handling retrieval and validation of Identities (e.g.
* 3rd party/web accounts). The Identities engine can fetch a list of available
* accounts, and set required capabilities and validate credentials for
* specified accounts.
*/
public class IdentityEngine extends BaseEngine implements ITcpConnectionListener {
/**
* States for IdentitiesEngine. States are based on the requests that the
* engine needs to handle.
*/
private enum State {
IDLE,
FETCHING_IDENTITIES,
VALIDATING_IDENTITY_CREDENTIALS,
SETTING_IDENTITY_STATUS,
GETTING_MY_IDENTITIES,
GETTING_MY_CHATABLE_IDENTITIES,
DELETE_IDENTITY
}
/**
* Mutex for thread synchronisation
*/
private final Object mMutex = new Object();
/**
* Container class for Identity Capability Status request. Consists of a
* network, identity id and a filter containing the required capabilities.
*/
private static class IdentityStatusRequest {
private String mNetwork;
private String mIdentityId;
private String mIdentityStatus = null;
/**
* Supply filter containing required capabilities.
*
* @param filter Bundle containing capabilities filter.
*/
public void setIdentityStatus(String status) {
mIdentityStatus = status;
}
}
/**
* Container class encapsulating an Identity validation request containing:
* dry-run flag, network, user-name, password, set of required capabilities.
*/
private static class IdentityValidateCredentialsRequest {
/** Performs a dry run if true. */
private boolean mDryRun;
/** Network to sign into. */
private String mNetwork;
/** Username to sign into identity with. */
private String mUserName;
/** Password to sign into identity with. */
private String mPassword;
private Map<String, Boolean> mStatus = null;
/**
* Supply filter containing required capabilities.
*
* @param filter Bundle containing capabilities filter.
*/
public void setCapabilityStatus(Bundle filter) {
mStatus = prepareBoolFilter(filter);
}
}
/**
*
* Container class for Delete Identity request. Consist network and identity id.
*
*/
private static class DeleteIdentityRequest {
/** Network to delete.*/
private String mNetwork;
/** IdentityID which needs to be Deleted.*/
private String mIdentityId;
}
/** The minimum interval between identity requests. */
private static final long MIN_REQUEST_INTERVAL = 60 * 60 * 1000;
/** The timestamp of which my identities were last requested. */
private long mLastMyIdentitiesRequestTimestamp;
/** The timestamp of which available identities were last requested. */
private long mLastAvailableIdentitiesRequestTimestamp;
/** The state of the state machine handling ui requests. */
private State mState = State.IDLE;
/** List array of Identities retrieved from Server. */
private final ArrayList<Identity> mAvailableIdentityList;
/** List array of Identities retrieved from Server. */
private final ArrayList<Identity> mMyIdentityList;
/** Holds the status messages of the setIdentityCapability-request. */
private final ArrayList<StatusMsg> mStatusList = new ArrayList<StatusMsg>();
/** The key for setIdentityCapability data type for the push ui message. */
public static final String KEY_DATA = "data";
/** The key for available identities for the push ui message. */
public static final String KEY_AVAILABLE_IDS = "availableids";
/** The key for my identities for the push ui message. */
public static final String KEY_MY_IDS = "myids";
/**
* Maintaining DeleteIdentityRequest so that it can be later removed from
* maintained cache.
**/
private DeleteIdentityRequest identityToBeDeleted;
/**
* The hard coded list of capabilities we use to getAvailableIdentities(): chat and status.
*/
private final Map<String, List<String>> mGetAvailableIdentitiesFilter;
/**
* The hard coded list of capabilities we use to getMyIdentities(): chat and status.
*/
private final Map<String, List<String>> mGetMyIdentitiesFilter;
/**
* The DatabaseHelper used to access the client database.
*/
private final DatabaseHelper mDatabaseHelper;
/**
* A list containing all the currently pending SNS.
*/
private List<String> mCurrentlyPendingSns;
/**
* Constructor
*
* @param eventCallback IEngineEventCallback allowing engine to report back.
*/
public IdentityEngine(IEngineEventCallback eventCallback, DatabaseHelper databaseHelper) {
super(eventCallback);
mEngineId = EngineId.IDENTITIES_ENGINE;
mDatabaseHelper = databaseHelper;
mMyIdentityList = new ArrayList<Identity>();
// restore cached identities
MyIdentitiesCacheTable.getCachedIdentities(databaseHelper.getReadableDatabase(),
mMyIdentityList);
mAvailableIdentityList = new ArrayList<Identity>();
mLastMyIdentitiesRequestTimestamp = 0;
mLastAvailableIdentitiesRequestTimestamp = 0;
// initialize identity capabilities filter
mGetAvailableIdentitiesFilter = new Hashtable<String, List<String>>();
final List<String> capabilities = new ArrayList<String>();
capabilities.add(IdentityCapability.CapabilityID.chat.name());
capabilities.add(IdentityCapability.CapabilityID.get_own_status.name());
mGetAvailableIdentitiesFilter.put(Identity.CAPABILITY, capabilities);
final List<String> authType = new ArrayList<String>();
authType.add(Identity.AUTH_TYPE_URL);
authType.add(Identity.AUTH_TYPE_CREDENTIALS);
mGetAvailableIdentitiesFilter.put(Identity.AUTH_TYPE, authType);
mGetMyIdentitiesFilter = new Hashtable<String, List<String>>();
mGetMyIdentitiesFilter.put(Identity.CAPABILITY, capabilities);
}
/**
*
* Gets all third party identities and adds the mobile identity
* from 360 to them.
*
* @return A list of all 3rd party identities the user is signed in to plus
* the 360 identity mobile. If the retrieval failed the list will
* be empty.
*
*/
public ArrayList<Identity> getAvailableThirdPartyIdentities() {
final ArrayList<Identity> availableIdentityList;
synchronized(mAvailableIdentityList) {
// make a shallow copy
availableIdentityList = new ArrayList<Identity>(mAvailableIdentityList);
}
if ((availableIdentityList.size() == 0) && (
(System.currentTimeMillis() - mLastAvailableIdentitiesRequestTimestamp)
> MIN_REQUEST_INTERVAL)) {
sendGetAvailableIdentitiesRequest();
}
return availableIdentityList;
}
/**
*
* Gets all third party identities the user is currently signed up for.
*
* @return A list of 3rd party identities the user is signed in to or an
* empty list if something went wrong retrieving the identities.
*
*/
public ArrayList<Identity> getMyThirdPartyIdentities() {
final ArrayList<Identity> myIdentityList;
synchronized(mMyIdentityList) {
// make a shallow copy
myIdentityList = new ArrayList<Identity>(mMyIdentityList);
}
if ((myIdentityList.size() == 0) && (
(System.currentTimeMillis() - mLastMyIdentitiesRequestTimestamp)
> MIN_REQUEST_INTERVAL)) {
sendGetMyIdentitiesRequest();
}
return myIdentityList;
}
/**
*
* Gets the identity with the specified network name.
*
* @param networkName The network name to get the identity for. E.g. "facebook.com".
*
* @return The identity that matches the passed network name or null if the network name was
* null or could not be found.
*
*/
public Identity getIdentityForNetworkName(final String networkName) {
if (networkName == null) {
return null;
}
for (int i = 0; i < mAvailableIdentityList.size(); i++) {
Identity identity = mAvailableIdentityList.get(i);
if (identity != null && networkName.equals(identity.mNetwork)) {
return identity;
}
}
return null;
}
/**
*
* Takes all third party identities that have a chat capability set to true.
*
* @return A list of chattable 3rd party identities the user is signed in to. If the retrieval identities failed the returned list will be empty.
*
*/
public ArrayList<Identity> getMyChattableIdentities() {
final ArrayList<Identity> chattableIdentities = new ArrayList<Identity>();
final ArrayList<Identity> myIdentityList;
final int identityListSize;
synchronized(mMyIdentityList) {
// make a shallow copy
myIdentityList = new ArrayList<Identity>(mMyIdentityList);
}
identityListSize = myIdentityList.size();
// checking each identity for its chat capability and adding it to the
// list if it does
for (int i = 0; i < identityListSize; i++) {
Identity identity = myIdentityList.get(i);
List<IdentityCapability> capabilities = identity.mCapabilities;
if (null == capabilities) {
continue; // if the capabilties are null skip to next identity
}
// run through capabilties and check for chat
for (int j = 0; j < capabilities.size(); j++) {
IdentityCapability capability = capabilities.get(j);
if (null == capability) {
continue; // skip null capabilities
}
if ((capability.mCapability == IdentityCapability.CapabilityID.chat) &&
(capability.mValue)) {
chattableIdentities.add(identity);
break;
}
}
}
return chattableIdentities;
}
/**
* Sends a get my identities request to the server which will be handled
* by onProcessCommsResponse once a response comes in.
*/
private void sendGetMyIdentitiesRequest() {
Identities.getMyIdentities(this, mGetMyIdentitiesFilter);
}
/**
* Send a get available identities request to the backend which will be
* handled by onProcessCommsResponse once a response comes in.
*/
private void sendGetAvailableIdentitiesRequest() {
Identities.getAvailableIdentities(this, mGetAvailableIdentitiesFilter);
}
/**
* Enables or disables the given social network.
*
* @param network Name of the identity,
* @param identityId Id of identity.
* @param identityStatus True if identity should be enabled, false otherwise.
*/
public void addUiSetIdentityStatus(String network, String identityId, boolean identityStatus) {
LogUtils.logD("IdentityEngine.addUiSetIdentityCapabilityStatus()");
IdentityStatusRequest data = new IdentityStatusRequest();
data.mIdentityId = identityId;
data.mNetwork = network;
data.setIdentityStatus(identityStatus ? Identities.ENABLE_IDENTITY
: Identities.DISABLE_IDENTITY);
// do not empty reqQueue here, ui can put many at one time
addUiRequestToQueue(ServiceUiRequest.SET_IDENTITY_CAPABILITY_STATUS, data);
}
/**
* TODO: re-factor the method in the way that the UI doesn't pass the Bundle with capabilities
* list to the Engine, but the Engine makes the list itself (UI/Engine separation).
*
* Add request to validate user credentials for a specified identity.
*
* @param dryRun True if this is a dry-run.
* @param network Name of the network/identity.
* @param username User-name for login for this identity.
* @param password Password for login for this identity.
* @param identityCapabilityStatus Bundle containing capability details for
* this identity.
*/
public void addUiValidateIdentityCredentials(boolean dryRun, String network, String username,
String password, Bundle identityCapabilityStatus) {
LogUtils.logD("IdentityEngine.addUiValidateIdentityCredentials()");
IdentityValidateCredentialsRequest data = new IdentityValidateCredentialsRequest();
data.mDryRun = dryRun;
data.mNetwork = network;
data.mPassword = password;
data.mUserName = username;
data.setCapabilityStatus(identityCapabilityStatus);
emptyUiRequestQueue();
addUiRequestToQueue(ServiceUiRequest.VALIDATE_IDENTITY_CREDENTIALS, data);
}
/**
* Delete the given social network.
*
* @param network Name of the identity,
* @param identityId Id of identity.
*/
public final void addUiDeleteIdentityRequest(final String network, final String identityId) {
LogUtils.logD("IdentityEngine.addUiRemoveIdentity()");
DeleteIdentityRequest data = new DeleteIdentityRequest();
data.mNetwork = network;
data.mIdentityId = identityId;
/**maintaining the sent object*/
setIdentityToBeDeleted(data);
addUiRequestToQueue(ServiceUiRequest.DELETE_IDENTITY, data);
}
/**
* Setting the DeleteIdentityRequest object.
*
* @param data
*/
private void setIdentityToBeDeleted(final DeleteIdentityRequest data) {
identityToBeDeleted = data;
}
/**
* Return the DeleteIdentityRequest object.
*
*/
private DeleteIdentityRequest getIdentityToBeDeleted() {
return identityToBeDeleted;
}
/**
* Issue any outstanding UI request.
*
* @param requestType Request to be issued.
* @param dara Data associated with the request.
*/
@Override
protected void processUiRequest(ServiceUiRequest requestType, Object data) {
LogUtils.logD("IdentityEngine.processUiRequest() - reqID = " + requestType);
switch (requestType) {
case GET_MY_IDENTITIES:
sendGetMyIdentitiesRequest();
completeUiRequest(ServiceStatus.SUCCESS);
break;
case VALIDATE_IDENTITY_CREDENTIALS:
executeValidateIdentityCredentialsRequest(data);
break;
case SET_IDENTITY_CAPABILITY_STATUS:
executeSetIdentityStatusRequest(data);
break;
case DELETE_IDENTITY:
executeDeleteIdentityRequest(data);
break;
default:
completeUiRequest(ServiceStatus.ERROR_NOT_FOUND, null);
break;
}
}
/**
* Issue request to set capabilities for a given Identity. (Request is not
* issued if there is currently no connectivity).
*
* @param data Bundled request data.
*/
private void executeSetIdentityStatusRequest(Object data) {
if (!isConnected()) {
return;
}
newState(State.SETTING_IDENTITY_STATUS);
IdentityStatusRequest reqData = (IdentityStatusRequest)data;
if (!setReqId(Identities.setIdentityStatus(this, reqData.mNetwork, reqData.mIdentityId,
reqData.mIdentityStatus))) {
completeUiRequest(ServiceStatus.ERROR_BAD_SERVER_PARAMETER);
}
}
/**
* Issue request to validate the user credentials for an Identity. (Request
* is not issued if there is currently no connectivity).
*
* @param data Bundled request data.
*/
private void executeValidateIdentityCredentialsRequest(Object data) {
if (!isConnected()) {
return;
}
newState(State.VALIDATING_IDENTITY_CREDENTIALS);
IdentityValidateCredentialsRequest reqData = (IdentityValidateCredentialsRequest)data;
if (!setReqId(Identities
.validateIdentityCredentials(this, reqData.mDryRun, reqData.mNetwork,
reqData.mUserName, reqData.mPassword, null, null, reqData.mStatus))) {
completeUiRequest(ServiceStatus.ERROR_BAD_SERVER_PARAMETER);
}
addPendingIdentity(reqData.mNetwork);
}
/**
* Issue request to delete the identity as specified . (Request is not issued if there
* is currently no connectivity).
*
* @param data bundled request data containing network and identityId.
*/
private void executeDeleteIdentityRequest(final Object data) {
if (!isConnected()) {
completeUiRequest(ServiceStatus.ERROR_NO_INTERNET);
}
newState(State.DELETE_IDENTITY);
DeleteIdentityRequest reqData = (DeleteIdentityRequest) data;
if (!setReqId(Identities.deleteIdentity(this, reqData.mNetwork,
reqData.mIdentityId))) {
completeUiRequest(ServiceStatus.ERROR_BAD_SERVER_PARAMETER);
}
}
/**
* Process a response received from Server. The response is handled
* according to the current IdentityEngine state.
*
* @param resp The decoded response.
*/
@Override
protected void processCommsResponse(DecodedResponse resp) {
LogUtils.logD("IdentityEngine.processCommsResponse() - resp = " + resp);
if ((null == resp) || (null == resp.mDataTypes)) {
LogUtils.logE("Response objects or its contents were null. Aborting...");
return;
}
// TODO replace this whole block with the response type in the DecodedResponse class in the future!
if (resp.mReqId == 0 && resp.mDataTypes.size() > 0) { // push msg
PushEvent evt = (PushEvent)resp.mDataTypes.get(0);
handlePushResponse(evt.mMessageType);
} else if (resp.mDataTypes.size() > 0) { // regular response
switch (resp.mDataTypes.get(0).getType()) {
case BaseDataType.MY_IDENTITY_DATA_TYPE:
handleGetMyIdentitiesResponse(resp.mDataTypes);
break;
case BaseDataType.AVAILABLE_IDENTITY_DATA_TYPE:
handleGetAvailableIdentitiesResponse(resp.mDataTypes);
break;
case BaseDataType.IDENTITY_CAPABILITY_DATA_TYPE:
handleSetIdentityStatus(resp.mDataTypes);
break;
case BaseDataType.STATUS_MSG_DATA_TYPE:
handleValidateIdentityCredentials(resp.mDataTypes);
break;
case BaseDataType.IDENTITY_DELETION_DATA_TYPE:
handleDeleteIdentity(resp.mDataTypes);
break;
default:
LogUtils.logW("IdentityEngine.processCommsResponse DEFAULT should never happened.");
break;
}
} else { // responses data list is 0, that means e.g. no identities in an identities response
LogUtils.logW("IdentityEngine.processCommsResponse List was empty!");
if (resp.getResponseType() == DecodedResponse.ResponseType.GET_MY_IDENTITIES_RESPONSE.ordinal()) {
pushIdentitiesToUi(ServiceUiRequest.GET_MY_IDENTITIES);
} else if (resp.getResponseType() == DecodedResponse.ResponseType.GET_AVAILABLE_IDENTITIES_RESPONSE.ordinal()) {
pushIdentitiesToUi(ServiceUiRequest.GET_AVAILABLE_IDENTITIES);
}
} // end: replace this whole block with the response type in the DecodedResponse class in the future!
}
/**
* Handle Status or Timeline Activity change Push message
*
* @param evt Push message type (Status change or Timeline change).
*/
private void handlePushResponse(PushMessageTypes evt) {
LogUtils.logD("IdentityEngine handlePushRequest");
switch (evt) {
case IDENTITY_NETWORK_CHANGE:
sendGetAvailableIdentitiesRequest();
break;
case IDENTITY_CHANGE:
mMyIdentityList.clear();
sendGetMyIdentitiesRequest();
mEventCallback.kickWorkerThread();
break;
default:
// do nothing
}
}
/**
* Run function called via EngineManager. Should have a UI, Comms response
* or timeout event to handle.
*/
@Override
public void run() {
LogUtils.logD("IdentityEngine.run()");
if (isCommsResponseOutstanding() && processCommsInQueue()) {
LogUtils.logD("IdentityEngine.ResponseOutstanding and processCommsInQueue. mState = "
+ mState.name());
return;
}
if (processTimeout()) {
return;
}
if (isUiRequestOutstanding()) {
processUiQueue();
}
}
/**
* Change current IdentityEngine state.
*
* @param newState new state.
*/
private void newState(State newState) {
State oldState = mState;
synchronized (mMutex) {
if (newState == mState) {
return;
}
mState = newState;
}
LogUtils.logV("IdentityEngine.newState: " + oldState + " -> " + mState);
}
/**
* Handle Server response to request for available Identities. The response
* should be a list of Identity items. The request is completed with
* ServiceStatus.SUCCESS or ERROR_UNEXPECTED_RESPONSE if the data-type
* retrieved are not Identity items.
*
* @param data List of BaseDataTypes generated from Server response.
*/
private void handleGetAvailableIdentitiesResponse(List<BaseDataType> data) {
LogUtils.logD("IdentityEngine: handleServerGetAvailableIdentitiesResponse");
ServiceStatus errorStatus = getResponseStatus(BaseDataType.AVAILABLE_IDENTITY_DATA_TYPE, data);
if (errorStatus == ServiceStatus.SUCCESS) {
synchronized (mAvailableIdentityList) {
mAvailableIdentityList.clear();
for (BaseDataType item : data) {
Identity identity = (Identity) item;
if (!identity.isIdentityFieldBlankorNull()) {
mAvailableIdentityList.add(identity);
}
}
}
}
pushIdentitiesToUi(ServiceUiRequest.GET_AVAILABLE_IDENTITIES);
LogUtils.logD("IdentityEngine: handleGetAvailableIdentitiesResponse complete request.");
}
/**
* Handle Server response to request for available Identities. The response
* should be a list of Identity items. The request is completed with
* ServiceStatus.SUCCESS or ERROR_UNEXPECTED_RESPONSE if the data-type
* retrieved are not Identity items.
*
* @param data List of BaseDataTypes generated from Server response.
*/
private void handleGetMyIdentitiesResponse(List<BaseDataType> data) {
LogUtils.logD("IdentityEngine: handleGetMyIdentitiesResponse");
ServiceStatus errorStatus = getResponseStatus(BaseDataType.MY_IDENTITY_DATA_TYPE, data);
if (errorStatus == ServiceStatus.SUCCESS) {
synchronized (mMyIdentityList) {
mMyIdentityList.clear();
for (BaseDataType item : data) {
Identity identity = (Identity) item;
if (!identity.isIdentityFieldBlankorNull()) {
mMyIdentityList.add(identity);
}
}
// cache the identities
MyIdentitiesCacheTable.setCachedIdentities(mDatabaseHelper.getWritableDatabase(),
mMyIdentityList);
clearPendingIdentities();
}
} else if (errorStatus == ServiceStatus.ERROR_COMMS_TIMEOUT) {
// reset the pending list in case of a timeout
clearPendingIdentities();
}
pushIdentitiesToUi(ServiceUiRequest.GET_MY_IDENTITIES);
// remove any identites returned from the pending list as they are validated by now!
removePendingIdentities(mMyIdentityList);
LogUtils.logD("IdentityEngine: handleGetMyIdentitiesResponse complete request.");
}
/**
* Handle Server response to set validate credentials request. The response
* should be a Status-msg indicating whether the request has succeeded or
* failed. The request is completed with the status result (or
* ERROR_UNEXPECTED_RESPONSE if the data-type retrieved is not a
* Status-msg).
*
* @param data List of BaseDataTypes generated from Server response.
*/
private void handleValidateIdentityCredentials(List<BaseDataType> data) {
Bundle bu = null;
ServiceStatus errorStatus = getResponseStatus(BaseDataType.STATUS_MSG_DATA_TYPE, data);
if (errorStatus == ServiceStatus.SUCCESS) {
mStatusList.clear();
for (BaseDataType item : data) {
if (item.getType() == BaseDataType.STATUS_MSG_DATA_TYPE) {
mStatusList.add((StatusMsg)item);
} else {
completeUiRequest(ServiceStatus.ERROR_UNEXPECTED_RESPONSE);
return;
}
}
bu = new Bundle();
if (mStatusList.size() == 1) {
bu.putBoolean("status", mStatusList.get(0).mStatus);
} else {
LogUtils.logW("Status list sould have one item. It has " + mStatusList.size());
bu.putParcelableArrayList(KEY_DATA, mStatusList);
}
}
completeUiRequest(errorStatus, bu);
newState(State.IDLE);
if (errorStatus == ServiceStatus.SUCCESS) {
addUiRequestToQueue(ServiceUiRequest.GET_MY_IDENTITIES, null);
} else if (errorStatus == ServiceStatus.ERROR_COMMS_TIMEOUT){
clearPendingIdentities(); // if we timeout we need to clear our pending identities
}
}
/**
* Handle Server response to set capability status request. The response
* should be a Status-msg indicating whether the request has succeeded or
* failed. The request is completed with the status result (or
* ERROR_UNEXPECTED_RESPONSE if the data-type retrieved is not a
* Status-msg).
*
* @param data List of BaseDataTypes generated from Server response.
*/
private void handleSetIdentityStatus(List<BaseDataType> data) {
Bundle bu = null;
ServiceStatus errorStatus = getResponseStatus(BaseDataType.STATUS_MSG_DATA_TYPE, data);
if (errorStatus == ServiceStatus.SUCCESS) {
mStatusList.clear();
for (BaseDataType item : data) {
if (item.getType() == BaseDataType.STATUS_MSG_DATA_TYPE) {
mStatusList.add((StatusMsg)item);
} else {
completeUiRequest(ServiceStatus.ERROR_UNEXPECTED_RESPONSE);
return;
}
}
bu = new Bundle();
bu.putParcelableArrayList(KEY_DATA, mStatusList);
}
completeUiRequest(errorStatus, bu);
newState(State.IDLE);
}
/**
* Handle Server response of request to delete the identity. The response
* should be a status that whether the operation is succeeded or not. The
* response will be a status result otherwise ERROR_UNEXPECTED_RESPONSE if
* the response is not as expected.
*
* @param data
* List of BaseDataTypes generated from Server response.
*/
private void handleDeleteIdentity(final List<BaseDataType> data) {
Bundle bu = null;
ServiceStatus errorStatus = getResponseStatus(
BaseDataType.IDENTITY_DELETION_DATA_TYPE, data);
if (errorStatus == ServiceStatus.SUCCESS) {
for (BaseDataType item : data) {
if (item.getType() == BaseDataType.IDENTITY_DELETION_DATA_TYPE) {
synchronized(mMyIdentityList) {
// iterating through the subscribed identities
for (Identity identity : mMyIdentityList) {
if (identity.mIdentityId
.equals(getIdentityToBeDeleted().mIdentityId)) {
mMyIdentityList.remove(identity);
break;
}
}
// cache the new set of identities
MyIdentitiesCacheTable.setCachedIdentities(mDatabaseHelper.getWritableDatabase(),
mMyIdentityList);
}
completeUiRequest(ServiceStatus.SUCCESS);
return;
} else {
completeUiRequest(ServiceStatus.ERROR_UNEXPECTED_RESPONSE);
return;
}
}
}
completeUiRequest(errorStatus, bu);
}
/**
*
* Pushes the identities retrieved by get my identities or by get available identities
* to the ui.
*
* @param request The request type: either get my identities, or get available identities.
*/
private void pushIdentitiesToUi(ServiceUiRequest request) {
String requestKey = null;
ArrayList<Identity> idBundle = null;
if (request == ServiceUiRequest.GET_AVAILABLE_IDENTITIES) {
requestKey = KEY_AVAILABLE_IDS;
synchronized (mAvailableIdentityList) {
// provide a shallow copy
idBundle = new ArrayList<Identity>(mAvailableIdentityList);
}
} else {
requestKey = KEY_MY_IDS;
synchronized (mMyIdentityList) {
// provide a shallow copy
idBundle = new ArrayList<Identity>(mMyIdentityList);
}
}
// send update to 3rd party identities ui if it is up
Bundle b = new Bundle();
b.putParcelableArrayList(requestKey, idBundle);
UiAgent uiAgent = mEventCallback.getUiAgent();
if (uiAgent != null && uiAgent.isSubscribed()) {
uiAgent.sendUnsolicitedUiEvent(request, b);
} // end: send update to 3rd party identities ui if it is up
}
/**
* Get Connectivity status from the connection manager.
*
* @return true True if the connection is active, false otherwise.
*
*/
private boolean isConnected() {
int connState = ConnectionManager.getInstance().getConnectionState();
return (connState == ITcpConnectionListener.STATE_CONNECTED);
}
@Override
public void onConnectionStateChanged(int state) {
if (state == ITcpConnectionListener.STATE_CONNECTED) {
emptyUiRequestQueue();
sendGetAvailableIdentitiesRequest();
sendGetMyIdentitiesRequest();
}
}
/**
* Return the next run-time for the IdentitiesEngine. Will run as soon as
* possible if we need to issue a request, or we have a resonse waiting.
*
* @return next run-time.
*/
@Override
public long getNextRunTime() {
if (isUiRequestOutstanding()) {
return 0;
}
if (isCommsResponseOutstanding()) {
return 0;
}
return getCurrentTimeout();
}
/** {@inheritDoc} */
@Override
public void onCreate() {
}
/** {@inheritDoc} */
@Override
public void onDestroy() {
}
/** {@inheritDoc} */
@Override
protected void onRequestComplete() {
}
/** {@inheritDoc} */
@Override
protected void onTimeoutEvent() {
}
/**
* Generate Map containing boolean capability filters for supplied Bundle.
*
* @param filter Bundle containing filter.
* @return Map containing set of capabilities.
*/
private static Map<String, Boolean> prepareBoolFilter(Bundle filter) {
Map<String, Boolean> objectFilter = null;
if (filter != null && (filter.keySet().size() > 0)) {
objectFilter = new Hashtable<String, Boolean>();
for (String key : filter.keySet()) {
objectFilter.put(key, filter.getBoolean(key));
}
} else {
objectFilter = null;
}
return objectFilter;
}
/**
* This method needs to be called as part of removeAllData()/changeUser()
* routine.
*/
/** {@inheritDoc} */
@Override
public final void onReset() {
super.onReset();
mMyIdentityList.clear();
mAvailableIdentityList.clear();
mStatusList.clear();
mState = State.IDLE;
}
/***
* Return TRUE if the given ThirdPartyAccount contains a Facebook account.
*
* @param list List of Identity objects, can be NULL.
* @return TRUE if the given Identity contains a Facebook account.
*/
public boolean isFacebookInThirdPartyAccountList() {
if (mMyIdentityList != null) {
synchronized(mMyIdentityList) {
for (Identity identity : mMyIdentityList) {
if (identity.mName.toLowerCase().contains(ThirdPartyAccount.SNS_TYPE_FACEBOOK)) {
return true;
}
}
}
}
LogUtils.logV("ApplicationCache."
+ "isFacebookInThirdPartyAccountList() Facebook not found in list");
return false;
}
/***
* Return TRUE if the given Identity contains a Hyves account.
*
* @param list List of ThirdPartyAccount objects, can be NULL.
* @return TRUE if the given Identity contains a Hyves account.
*/
public boolean isHyvesInThirdPartyAccountList() {
if (mMyIdentityList != null) {
synchronized(mMyIdentityList) {
for (Identity identity : mMyIdentityList) {
if (identity.mName.toLowerCase().contains(ThirdPartyAccount.SNS_TYPE_HYVES)) {
return true;
}
}
}
}
LogUtils.logV("ApplicationCache."
+ "isFacebookInThirdPartyAccountList() Hyves not found in list");
return false;
}
/**
*
* Adds a social network to the "to be validated" hash map. The map is used for checking
* which social network is currently being validated with the backend.
*
* @param socialNetwork The social network (Identity.mNetwork) to add to the pending list.
*
*/
private synchronized void addPendingIdentity(final String socialNetwork) {
if (socialNetwork == null) {
return;
}
if (mCurrentlyPendingSns == null) {
mCurrentlyPendingSns = new ArrayList<String>();
}
synchronized (mCurrentlyPendingSns) {
mCurrentlyPendingSns.add(socialNetwork);
}
}
/**
*
* Returns the currently pending identities as part of a list.
*
* @return The currently pending identities in a list.
*
*/
public List<Identity> getPendingIdentities() {
List<Identity> pendingIdentities = new ArrayList<Identity>();
if (mCurrentlyPendingSns == null) {
return pendingIdentities;
}
for (int i = 0; i < mCurrentlyPendingSns.size(); i++) {
String pendingSns = mCurrentlyPendingSns.get(i);
if (pendingSns == null) {
continue;
}
for (int j = 0; j < mAvailableIdentityList.size(); j++) {
Identity availableIdentity = mAvailableIdentityList.get(j);
if (pendingSns.equals(availableIdentity.mNetwork)) {
pendingIdentities.add(availableIdentity);
}
}
}
return pendingIdentities;
}
/**
*
* Deletes a social network that has been validated on the backend from the map.
*
* @param socialNetwork A list of social networks to remove from the pending list.
*
*/
private void removePendingIdentities(final List<Identity> socialNetworks) {
if (socialNetworks == null || mCurrentlyPendingSns == null) {
return;
}
synchronized (mCurrentlyPendingSns) {
Iterator<String> iter = mCurrentlyPendingSns.iterator();
while (iter.hasNext()) { // remove social networks that match the passed network
Iterator<Identity> iterMyIdentities = socialNetworks.iterator();
while (iterMyIdentities.hasNext()) {
if (iter.next().equals(iterMyIdentities.next().mNetwork)) {
iter.remove();
}
}
}
}
}
/**
* Clears the currently pending identities e.g. can be used in case of a validate identity
* request to the backend times out.
*/
private void clearPendingIdentities() {
if (mCurrentlyPendingSns == null) {
return;
}
synchronized (mCurrentlyPendingSns) {
mCurrentlyPendingSns.clear();
}
}
/**
*
* Checks whether the third party account/identity is being added already by the user. If so it
* should not be possible to add the account again. If the account is currently being validated
* this method returns true.
*
* @param networkName The network to check for. E.g. facebook.com.
*
* @return True if the Identity is being validated on the backend currently.
*/
public boolean isIdentityPending(final String networkName) {
if (networkName == null || mCurrentlyPendingSns == null) {
return false;
}
for (int i = 0; i < mCurrentlyPendingSns.size(); i++) {
if (networkName.equals(mCurrentlyPendingSns.get(i))) {
return true;
}
}
return false;
}
}