/*
* 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.service.transport;
import java.util.ArrayList;
import android.content.Context;
import android.os.AsyncTask;
import android.widget.Toast;
import com.vodafone360.people.engine.EngineManager;
import com.vodafone360.people.engine.login.LoginEngine.ILoginEventsListener;
import com.vodafone360.people.service.RemoteService;
import com.vodafone360.people.service.io.QueueManager;
import com.vodafone360.people.service.transport.http.HttpConnectionThread;
import com.vodafone360.people.service.transport.http.authentication.AuthenticationManager;
import com.vodafone360.people.service.transport.tcp.ITcpConnectionListener;
import com.vodafone360.people.service.transport.tcp.TcpConnectionThread;
/**
* ConnectionManager - responsible for controlling the current connection
* Connects and disconnects based on network availability etc and start or stops
* RPG polling. Currently handles HTTP connections - this will be extended to
* support TCP sockets.
*/
public class ConnectionManager implements ILoginEventsListener, IQueueListener {
private static ConnectionManager mInstance;
private IConnection mConnection;
private RemoteService mService;
private DecoderThread mDecoder;
/**
* ApplicationContext
*/
private Context mContext;
/**
* the class member variable to keep the connection state.
*
* @see ITcpConnectionListener
*/
private int mConnectionState;
/**
* the list of connection state change listeners, e.g. PresenceEngine.
*/
private ArrayList<ITcpConnectionListener> mListeners = new ArrayList<ITcpConnectionListener>();
public static synchronized ConnectionManager getInstance() {
if (mInstance == null) {
mInstance = new ConnectionManager();
}
return mInstance;
}
/**
* Shows a Toast ruinning on a UI Thread. There can be a crash if the
* connectionmanager is called outside of an UI Thread and then treis to
* show a toast. Using this approach with the AsyncTask Toasts will allways
* be shown inside an UI Thread.
*
* @param messageResId
*/
private void showToast(int messageResId) {
new AsyncTask<Integer, Void, Boolean>() {
protected Boolean doInBackground(Integer... messageResId) {
try {
Toast toast = Toast.makeText(mContext, messageResId[0], Toast.LENGTH_LONG);
toast.show();
} catch (Exception exc) {
return false;
}
return true;
}
}.execute(messageResId);
}
private ConnectionManager() {
EngineManager.getInstance().getLoginEngine().addListener(this);
}
public void connect(RemoteService service) {
HttpConnectionThread.logI("ConnectionManager.connect()", "CONNECT CALLED BY NETWORKAGENT");
mService = service;
mContext = mService.getApplicationContext();
// start decoder
if (mDecoder == null) {
mDecoder = new DecoderThread();
}
if (!mDecoder.getIsRunning()) {
mDecoder.startThread();
}
boolean isCurrentlyLoggedIn = EngineManager.getInstance().getLoginEngine().isLoggedIn();
onLoginStateChanged(isCurrentlyLoggedIn);
HttpConnectionThread.logI("ConnectionManager.connect()",
(isCurrentlyLoggedIn) ? "We are logged in!" : "We are not logged in!");
}
/**
* Returns an autodetected connection. Where available, TCP will be used.
* HTTP is used as a fallback alternative.
*
* @return Returns the correct implmentation of the connection. If TCP is
* available it will be used preferably. Otherwise, HTTP is used as
* a fallback.
*/
private IConnection getAutodetectedConnection(RemoteService service) {
return new TcpConnectionThread(mDecoder, service);
}
public void disconnect() {
HttpConnectionThread.logI("ConnectionManager.disconnect()",
"DISCONNECT CALLED BY NETWORKAGENT");
if (null != mDecoder) {
mDecoder.stopThread();
}
stopActiveConnection();
}
@Override
public synchronized void onLoginStateChanged(boolean loggedIn) {
HttpConnectionThread.logI("ConnectionManager.onLoginStateChanged()", "Is logged in: "
+ loggedIn);
stopActiveConnection();
if (loggedIn) {
mConnection = getAutodetectedConnection(mService);
} else {
mConnection = new AuthenticationManager(mDecoder);
}
QueueManager.getInstance().addQueueListener(mConnection);
mConnection.startThread();
}
/**
*
* Stops the connection if it was currently running.
*
*/
private void stopActiveConnection() {
if (null != mConnection) {
synchronized (mConnection) {
mConnection.stopThread();
mConnection = null;
unsubscribeFromQueueEvents();
}
}
}
@Override
public synchronized void notifyOfItemInRequestQueue() {
mConnection.notifyOfItemInRequestQueue();
}
public void notifyOfUiActivity() {
if (null != mConnection) {
mConnection.notifyOfUiActivity();
}
}
private void unsubscribeFromQueueEvents() {
QueueManager queue = QueueManager.getInstance();
queue.removeQueueListener(mConnection);
queue.clearRequestTimeouts();
}
/**
* Enable test connection (for Unit testing purposes)
*
* @param testConn handle to test connection
*/
public void setTestConnection(IConnection testConn) {
mConnection = testConn;
QueueManager.getInstance().addQueueListener(mConnection);
}
/**
* This method is called by the protocol to signal the connection state change.
*
* @param state The new connection state, @see ITcpConnectionListener.
*/
public void onConnectionStateChanged(int state) {
HttpConnectionThread.logI("ConnectionManager.onConnectionStateChanged()",
"State is " + state);
if (state == ITcpConnectionListener.STATE_DISCONNECTED) {
// TODO show toast only if activity in foreground
// showToast(R.string.ContactProfile_no_connection);
}
mConnectionState = state;
for (ITcpConnectionListener listener : mListeners) {
listener.onConnectionStateChanged(state);
}
}
/**
* This method adds a listener for the connection state changes to the list,
* if it is not there yet.
*
* @param listener ITcpConnectionListener - listener.
*/
public void addConnectionListener(ITcpConnectionListener listener) {
if (!mListeners.contains(listener)) {
mListeners.add(listener);
}
}
/**
* This method removes a listener from the connection state changes
* listeners list.
*
* @param listener ITcpConnectionListener - listener.
*/
public void removeConnectionListener(ITcpConnectionListener listener) {
mListeners.remove(listener);
}
/**
* This method returns the current connection state of the application.
*
* @see ITcpConnectionListener
* @return int - the connection state @see ITcpConnectionListener.
*/
public int getConnectionState() {
return mConnectionState;
}
}