import com.android.im.engine.Presence;
import com.android.im.imps.ImpsConnectionConfig.CirMethod;
import com.android.im.imps.ImpsConnectionConfig.TransportType;
+import com.android.im.imps.Primitive.TransactionMode;
/**
* An implementation of ImConnection of Wireless Village IMPS protocol.
if (!checkAndSetState(SUSPENDED)) {
return;
}
-
- mReestablishing = true;
- try {
- mSession = new ImpsSession(this, cookie);
- } catch (ImException e) {
- setState(DISCONNECTED, e.getImError());
- return;
+ // If we can resume from the data channel, which means the
+ // session is still valid, we can just re-use the existing
+ // session and don't need to re-establish it.
+ if (mDataChannel.resume()) {
+ try {
+ setupCIRChannel();
+ } catch(ImException e) {}
+ setState(LOGGED_IN, null);
+ } else {
+ // Failed to resume the data channel which means the
+ // session might have expired, we need to re-establish
+ // the session by signing in again.
+ mReestablishing = true;
+ try {
+ mSession = new ImpsSession(this, cookie);
+ } catch (ImException e) {
+ setState(DISCONNECTED, e.getImError());
+ return;
+ }
+ doLogin();
}
- doLogin();
}
@Override
private void doLogin() {
try {
- initDataChannel();
+ if (mConfig.useSmsAuth()) {
+ mDataChannel = new SmsDataChannel(this);
+ } else {
+ mDataChannel = createDataChannel();
+ }
mDataChannel.connect();
} catch (ImException e) {
ImErrorInfo error = e.getImError();
}
private void onAuthenticated() {
+ // The user has chosen logout before the session established, just
+ // send the Logout-Request in this case.
+ if (mState == LOGGING_OUT) {
+ sendLogoutRequest();
+ return;
+ }
+
+ if (mConfig.useSmsAuth()
+ && mConfig.getDataChannelBinding() != TransportType.SMS) {
+ // SMS data channel was used if it's set to send authentication
+ // over SMS. Switch to the config data channel after authentication
+ // completed.
+ try {
+ DataChannel dataChannel = createDataChannel();
+ dataChannel.connect();
+
+ mDataChannel.shutdown();
+ mDataChannel = dataChannel;
+ mDispatcherThread.changeDataChannel(dataChannel);
+ } catch (ImException e) {
+ // This should not happen since only http data channel which
+ // does not do the real network connection in connect() is
+ // valid here now.
+ logoutAsync();
+ return;
+ }
+ }
+
if(mSession.isCapablityRequestRequired()) {
mSession.negotiateCapabilityAsync(new AsyncCompletion(){
public void onComplete() {
mCirChannel = null;
}
- LogoutCompletion logoutCompletion = new LogoutCompletion();
- AsyncTransaction tx = new SimpleAsyncTransaction(mTransactionManager,
- logoutCompletion);
- Primitive logoutPrimitive = new Primitive(ImpsTags.Logout_Request);
- tx.sendRequest(logoutPrimitive);
+ // Only send the Logout-Request if the session has been established.
+ if (mSession.getID() != null) {
+ sendLogoutRequest();
+ }
}
- // We cannot shut down our connections in ImpsAsyncTransaction.onResponse()
- // because at that time the logout transaction itself hasn't ended yet. So
- // we have to do this in this completion object.
- class LogoutCompletion implements AsyncCompletion {
- public void onComplete() {
- shutdown();
- }
+ void sendLogoutRequest() {
+ // We cannot shut down our connections in ImpsAsyncTransaction.onResponse()
+ // because at that time the logout transaction itself hasn't ended yet. So
+ // we have to do this in this completion object.
+ AsyncCompletion completion = new AsyncCompletion() {
+ public void onComplete() {
+ shutdown();
+ }
- public void onError(ImErrorInfo error) {
- // We simply ignore all errors when logging out.
- // NowIMP responds a <Disconnect> instead of <Status> on logout request.
- shutdown();
- }
+ public void onError(ImErrorInfo error) {
+ // We simply ignore all errors when logging out.
+ // NowIMP responds a <Disconnect> instead of <Status> on logout request.
+ shutdown();
+ }
+ };
+ AsyncTransaction tx = new SimpleAsyncTransaction(mTransactionManager,
+ completion);
+ Primitive logoutPrimitive = new Primitive(ImpsTags.Logout_Request);
+ tx.sendRequest(logoutPrimitive);
}
public ImpsSession getSession() {
mDataChannel.sendPrimitive(pollingRequest);
}
- private void initDataChannel() throws ImException {
+ private DataChannel createDataChannel() throws ImException {
TransportType dataChannelBinding = mConfig.getDataChannelBinding();
if (dataChannelBinding == TransportType.HTTP) {
- mDataChannel = new HttpDataChannel(this);
+ return new HttpDataChannel(this);
+ } else if (dataChannelBinding == TransportType.SMS) {
+ return new SmsDataChannel(this);
} else {
throw new ImException("Unsupported data channel binding");
}
mCirChannel = new HttpCirChannel(this, mDataChannel);
} else if (cirMethod == CirMethod.STCP) {
mCirChannel = new TcpCirChannel(this);
+ } else if (cirMethod == CirMethod.SSMS) {
+ mCirChannel = new SmsCirChannel(this);
} else if (cirMethod == CirMethod.NONE) {
//Do nothing
} else {
mChannel = channel;
}
+ public void changeDataChannel(DataChannel channel) {
+ mChannel = channel;
+ interrupt();
+ }
+
@Override
public void run() {
Primitive primitive = null;
}
}
+ if (primitive.getTransactionMode() == TransactionMode.Response) {
+ ImpsErrorInfo error = ImpsUtils.checkResultError(primitive);
+ if (error != null) {
+ int code = error.getCode();
+ if (code == ImpsErrorInfo.SESSION_EXPIRED
+ || code == ImpsErrorInfo.FORCED_LOGOUT
+ || code == ImpsErrorInfo.INVALID_SESSION) {
+ shutdownOnError(error);
+ return;
+ }
+ }
+ }
+
// According to the IMPS spec, only VersionDiscoveryResponse which
// are not supported now doesn't have a transaction ID.
if (primitive.getTransactionID() != null) {
if (mCirChannel != null) {
mCirChannel.shutdown();
}
- if (mDispatcherThread != null) {
- mDispatcherThread.shutdown();
- }
+
if (mDataChannel != null) {
- mDataChannel.shutdown();
+ mDataChannel.suspend();
}
setState(SUSPENDED, null);