ImpsConnection.java
上传用户:szyujian
上传日期:2016-09-20
资源大小:320k
文件大小:24k
源码类别:

android开发

开发平台:

C/C++

  1. /*
  2.  * Copyright (C) 2007-2008 Esmertec AG.
  3.  * Copyright (C) 2007-2008 The Android Open Source Project
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package com.android.im.imps;
  18. import java.util.ArrayList;
  19. import java.util.HashMap;
  20. import java.util.Map;
  21. import com.android.im.engine.ChatGroupManager;
  22. import com.android.im.engine.ChatSessionManager;
  23. import com.android.im.engine.Contact;
  24. import com.android.im.engine.ContactListManager;
  25. import com.android.im.engine.ImConnection;
  26. import com.android.im.engine.ImErrorInfo;
  27. import com.android.im.engine.ImException;
  28. import com.android.im.engine.LoginInfo;
  29. import com.android.im.engine.Presence;
  30. import com.android.im.imps.ImpsConnectionConfig.CirMethod;
  31. import com.android.im.imps.ImpsConnectionConfig.TransportType;
  32. /**
  33.  * An implementation of ImConnection of Wireless Village IMPS protocol.
  34.  */
  35. public class ImpsConnection extends ImConnection {
  36.     ImpsConnectionConfig mConfig;
  37.     DataChannel mDataChannel;
  38.     private CirChannel mCirChannel;
  39.     private PrimitiveDispatcherThread mDispatcherThread;
  40.     ImpsSession mSession;
  41.     ImpsTransactionManager mTransactionManager;
  42.     private ImpsChatSessionManager mChatSessionManager;
  43.     private ImpsContactListManager mContactListManager;
  44.     private ImpsChatGroupManager   mChatGroupManager;
  45.     private boolean mReestablishing;
  46.     /**
  47.      * Constructs a new WVConnection with a WVConnectionConfig object.
  48.      *
  49.      * @param config the configuration.
  50.      * @throws ImException if there's an error in the configuration.
  51.      */
  52.     public ImpsConnection(ImpsConnectionConfig config) {
  53.         super();
  54.         mConfig = config;
  55.         mTransactionManager = new ImpsTransactionManager(this);
  56.         mChatSessionManager = new ImpsChatSessionManager(this);
  57.         mContactListManager = new ImpsContactListManager(this);
  58.         mChatGroupManager   = new ImpsChatGroupManager(this);
  59.     }
  60.     /**
  61.      * Gets the configuration of this connection.
  62.      *
  63.      * @return the configuration.
  64.      */
  65.     ImpsConnectionConfig getConfig() {
  66.         return mConfig;
  67.     }
  68.     synchronized void shutdownOnError(ImErrorInfo error) {
  69.         if(mState == DISCONNECTED) {
  70.             return;
  71.         }
  72.         if (mCirChannel != null) {
  73.             mCirChannel.shutdown();
  74.         }
  75.         if (mDispatcherThread != null) {
  76.             mDispatcherThread.shutdown();
  77.         }
  78.         if (mDataChannel != null) {
  79.             mDataChannel.shutdown();
  80.         }
  81.         if (mContactListManager != null && !mReestablishing) {
  82.             mContactListManager.reset();
  83.         }
  84.         setState(mReestablishing ? SUSPENDED: DISCONNECTED, error);
  85.         mReestablishing = false;
  86.     }
  87.     void shutdown(){
  88.         shutdownOnError(null);
  89.     }
  90.     @Override
  91.     public int getCapability() {
  92.         return CAPABILITY_GROUP_CHAT | CAPABILITY_SESSION_REESTABLISHMENT;
  93.     }
  94.     @Override
  95.     public void loginAsync(LoginInfo loginInfo) {
  96.         if (!checkAndSetState(DISCONNECTED)) {
  97.             return;
  98.         }
  99.         try {
  100.             mSession = new ImpsSession(this, loginInfo);
  101.         } catch (ImException e) {
  102.             setState(DISCONNECTED, e.getImError());
  103.             return;
  104.         }
  105.         doLogin();
  106.     }
  107.     @Override
  108.     public void reestablishSessionAsync(
  109.             HashMap<String, String> cookie) {
  110.         if (!checkAndSetState(SUSPENDED)) {
  111.             return;
  112.         }
  113.         mReestablishing = true;
  114.         try {
  115.             mSession = new ImpsSession(this, cookie);
  116.         } catch (ImException e) {
  117.             setState(DISCONNECTED, e.getImError());
  118.             return;
  119.         }
  120.         doLogin();
  121.     }
  122.     @Override
  123.     public void networkTypeChanged() {
  124.         if (mCirChannel != null) {
  125.             mCirChannel.reconnect();
  126.         }
  127.     }
  128.     private synchronized boolean checkAndSetState(int state) {
  129.         if(mState != state){
  130.             return false;
  131.         }
  132.         setState(LOGGING_IN, null);
  133.         return true;
  134.     }
  135.     private void doLogin() {
  136.         try {
  137.             initDataChannel();
  138.             mDataChannel.connect();
  139.         } catch (ImException e) {
  140.             ImErrorInfo error = e.getImError();
  141.             if(error == null){
  142.                 error = new ImErrorInfo(ImErrorInfo.UNKNOWN_LOGIN_ERROR,
  143.                         e.getMessage());
  144.             }
  145.             shutdownOnError(error);
  146.             return;
  147.         }
  148.         mDispatcherThread = new PrimitiveDispatcherThread(mDataChannel);
  149.         mDispatcherThread.start();
  150.         LoginTransaction login = new LoginTransaction();
  151.         login.startAuthenticate();
  152.     }
  153.     @Override
  154.     public HashMap<String, String> getSessionContext() {
  155.         if(mState != LOGGED_IN) {
  156.             return null;
  157.         } else {
  158.             return mSession.getContext();
  159.         }
  160.     }
  161.     class LoginTransaction extends MultiPhaseTransaction {
  162.         LoginTransaction() {
  163.             // We're not passing completion to ImpsAsyncTransaction. Instead
  164.             // we'll handle the notification in LoginTransaction.
  165.             super(mTransactionManager);
  166.         }
  167.         public void startAuthenticate() {
  168.             Primitive login = buildBasicLoginReq();
  169.             if (mConfig.use4wayLogin()) {
  170.                 // first login request of 4 way login
  171.                 String[] supportedDigestSchema = mConfig.getPasswordDigest().getSupportedDigestSchema();
  172.                 for (String element : supportedDigestSchema) {
  173.                     login.addElement(ImpsTags.DigestSchema, element);
  174.                 }
  175.             } else {
  176.                 // 2 way login
  177.                 login.addElement(ImpsTags.Password, mSession.getPassword());
  178.             }
  179.             sendRequest(login);
  180.         }
  181.         @Override
  182.         public TransactionStatus processResponse(Primitive response) {
  183.             if (response.getElement(ImpsTags.SessionID) != null) {
  184.                 // If server chooses authentication based on network, we might
  185.                 // got the final Login-Response before the 2nd Login-Request.
  186.                 String sessionId = response.getElementContents(ImpsTags.SessionID);
  187.                 String keepAliveTime = response.getElementContents(ImpsTags.KeepAliveTime);
  188.                 String capablityReqeust = response.getElementContents(ImpsTags.CapabilityRequest);
  189.                 long keepAlive = ImpsUtils.parseLong(keepAliveTime,
  190.                         mConfig.getDefaultKeepAliveInterval());
  191.                 // make sure we always have time to send keep-alive requests.
  192.                 // see buildBasicLoginReq().
  193.                 keepAlive -= 5;
  194.                 mSession.setId(sessionId);
  195.                 mSession.setKeepAliveTime(keepAlive);
  196.                 mSession.setCapablityRequestRequired(ImpsUtils.isTrue(capablityReqeust));
  197.                 onAuthenticated();
  198.                 return TransactionStatus.TRANSACTION_COMPLETED;
  199.             } else {
  200.                 return sendSecondLogin(response);
  201.             }
  202.         }
  203.         @Override
  204.         public TransactionStatus processResponseError(ImpsErrorInfo error) {
  205.             if (error.getCode() == ImpsConstants.STATUS_UNAUTHORIZED
  206.                     && error.getPrimitive() != null) {
  207.                 if (mConfig.use4wayLogin()) {
  208.                     // Not really an error. Send the 2nd Login-Request.
  209.                     return sendSecondLogin(error.getPrimitive());
  210.                 } else {
  211.                     // We have already sent password in 2way login, while OZ's
  212.                     // yahoo gateway server returns "401 - Further authorization
  213.                     // required" instead of "409 - Invalid password" if the
  214.                     // password only contains spaces.
  215.                     shutdownOnError(new ImErrorInfo(409, "Invalid password"));
  216.                     return TransactionStatus.TRANSACTION_COMPLETED;
  217.                 }
  218.             } else if(error.getCode() == ImpsConstants.STATUS_COULD_NOT_RECOVER_SESSION) {
  219.                 // The server could not recover the session, create a new
  220.                 // session and try to login again.
  221.                 LoginInfo loginInfo = mSession.getLoginInfo();
  222.                 try {
  223.                     mSession = new ImpsSession(ImpsConnection.this, loginInfo);
  224.                 } catch (ImException ignore) {
  225.                     // This shouldn't happen since we have tried to login with
  226.                     // the loginInfo
  227.                 }
  228.                 startAuthenticate();
  229.                 return TransactionStatus.TRANSACTION_COMPLETED;
  230.             } else {
  231.                 shutdownOnError(error);
  232.                 return TransactionStatus.TRANSACTION_COMPLETED;
  233.             }
  234.         }
  235.         private TransactionStatus sendSecondLogin(Primitive res) {
  236.             try {
  237.                 Primitive secondLogin = buildBasicLoginReq();
  238.                 String nonce = res.getElementContents(ImpsTags.Nonce);
  239.                 String digestSchema = res.getElementContents(ImpsTags.DigestSchema);
  240.                 String digestBytes = mConfig.getPasswordDigest().digest(digestSchema, nonce,
  241.                         mSession.getPassword());
  242.                 secondLogin.addElement(ImpsTags.DigestBytes, digestBytes);
  243.                 sendRequest(secondLogin);
  244.                 return TransactionStatus.TRANSACTION_CONTINUE;
  245.             } catch (ImException e) {
  246.                 ImpsLog.logError(e);
  247.                 shutdownOnError(new ImErrorInfo(ImErrorInfo.UNKNOWN_ERROR, e.toString()));
  248.                 return TransactionStatus.TRANSACTION_COMPLETED;
  249.             }
  250.         }
  251.         private void onAuthenticated() {
  252.             if(mSession.isCapablityRequestRequired()) {
  253.                 mSession.negotiateCapabilityAsync(new AsyncCompletion(){
  254.                     public void onComplete() {
  255.                         onCapabilityNegotiated();
  256.                     }
  257.                     public void onError(ImErrorInfo error) {
  258.                         shutdownOnError(error);
  259.                     }
  260.                 });
  261.             } else {
  262.                 onCapabilityNegotiated();
  263.             }
  264.         }
  265.         void onCapabilityNegotiated() {
  266.             mDataChannel.setServerMinPoll(mSession.getServerPollMin());
  267.             if(getConfig().getCirChannelBinding() != CirMethod.NONE) {
  268.                 try {
  269.                     setupCIRChannel();
  270.                 } catch (ImException e) {
  271.                     shutdownOnError(new ImErrorInfo(
  272.                             ImErrorInfo.UNSUPPORTED_CIR_CHANNEL, e.toString()));
  273.                     return;
  274.                 }
  275.             }
  276.             mSession.negotiateServiceAsync(new AsyncCompletion(){
  277.                 public void onComplete() {
  278.                     onServiceNegotiated();
  279.                 }
  280.                 public void onError(ImErrorInfo error) {
  281.                     shutdownOnError(error);
  282.                 }
  283.             });
  284.         }
  285.         void onServiceNegotiated() {
  286.             mDataChannel.startKeepAlive(mSession.getKeepAliveTime());
  287.             retrieveUserPresenceAsync(new AsyncCompletion() {
  288.                 public void onComplete() {
  289.                     setState(LOGGED_IN, null);
  290.                     if (mReestablishing) {
  291.                         ImpsContactListManager listMgr=  (ImpsContactListManager) getContactListManager();
  292.                         listMgr.subscribeToAllListAsync();
  293.                         mReestablishing = false;
  294.                     }
  295.                 }
  296.                 public void onError(ImErrorInfo error) {
  297.                     // Just continue. initUserPresenceAsync already made a
  298.                     // default mUserPresence for us.
  299.                     onComplete();
  300.                 }
  301.             });
  302.         }
  303.     }
  304.     @Override
  305.     public void logoutAsync() {
  306.         setState(LOGGING_OUT, null);
  307.         // Shutdown the CIR channel first.
  308.         if(mCirChannel != null) {
  309.             mCirChannel.shutdown();
  310.             mCirChannel = null;
  311.         }
  312.         LogoutCompletion logoutCompletion = new LogoutCompletion();
  313.         AsyncTransaction tx = new SimpleAsyncTransaction(mTransactionManager,
  314.                 logoutCompletion);
  315.         Primitive logoutPrimitive = new Primitive(ImpsTags.Logout_Request);
  316.         tx.sendRequest(logoutPrimitive);
  317.     }
  318.     // We cannot shut down our connections in ImpsAsyncTransaction.onResponse()
  319.     // because at that time the logout transaction itself hasn't ended yet. So
  320.     // we have to do this in this completion object.
  321.     class LogoutCompletion implements AsyncCompletion {
  322.         public void onComplete() {
  323.             shutdown();
  324.         }
  325.         public void onError(ImErrorInfo error) {
  326.             // We simply ignore all errors when logging out.
  327.             // NowIMP responds a <Disconnect> instead of <Status> on logout request.
  328.             shutdown();
  329.         }
  330.     }
  331.     public ImpsSession getSession() {
  332.         return mSession;
  333.     }
  334.     @Override
  335.     public Contact getLoginUser() {
  336.         if(mSession == null){
  337.             return null;
  338.         }
  339.         Contact loginUser = mSession.getLoginUser();
  340.         loginUser.setPresence(getUserPresence());
  341.         return loginUser;
  342.     }
  343.     @Override
  344.     public int[] getSupportedPresenceStatus() {
  345.         return mConfig.getPresenceMapping().getSupportedPresenceStatus();
  346.     }
  347.     public ImpsTransactionManager getTransactionManager() {
  348.         return mTransactionManager;
  349.     }
  350.     @Override
  351.     public ChatSessionManager getChatSessionManager() {
  352.         return mChatSessionManager;
  353.     }
  354.     @Override
  355.     public ContactListManager getContactListManager() {
  356.         return mContactListManager;
  357.     }
  358.     @Override
  359.     public ChatGroupManager getChatGroupManager() {
  360.         return mChatGroupManager;
  361.     }
  362.     /**
  363.      * Sends a specific primitive to the server. It will return immediately
  364.      * after the primitive has been put to the sending queue.
  365.      *
  366.      * @param primitive the packet to send.
  367.      */
  368.     void sendPrimitive(Primitive primitive) {
  369.         mDataChannel.sendPrimitive(primitive);
  370.     }
  371.     /**
  372.      * Sends a PollingRequest to the server.
  373.      */
  374.     void sendPollingRequest() {
  375.         Primitive pollingRequest = new Primitive(ImpsTags.Polling_Request);
  376.         pollingRequest.setSession(getSession().getID());
  377.         mDataChannel.sendPrimitive(pollingRequest);
  378.     }
  379.     private void initDataChannel() throws ImException {
  380.         TransportType dataChannelBinding = mConfig.getDataChannelBinding();
  381.         if (dataChannelBinding == TransportType.HTTP) {
  382.             mDataChannel = new HttpDataChannel(this);
  383.         } else {
  384.             throw new ImException("Unsupported data channel binding");
  385.         }
  386.     }
  387.     void setupCIRChannel() throws ImException {
  388.         if(mConfig.getDataChannelBinding() == TransportType.SMS) {
  389.             // No CIR channel is needed, do nothing.
  390.             return;
  391.         }
  392.         CirMethod cirMethod = mSession.getCurrentCirMethod();
  393.         if (cirMethod == null) {
  394.             cirMethod = mConfig.getCirChannelBinding();
  395.             if (!mSession.getSupportedCirMethods().contains(cirMethod)) {
  396.                 // Sever don't support the CIR method
  397.                 cirMethod = CirMethod.SHTTP;
  398.             }
  399.             mSession.setCurrentCirMethod(cirMethod);
  400.         }
  401.         if (cirMethod == CirMethod.SHTTP) {
  402.             mCirChannel = new HttpCirChannel(this, mDataChannel);
  403.         } else if (cirMethod == CirMethod.STCP) {
  404.             mCirChannel = new TcpCirChannel(this);
  405.         } else if (cirMethod == CirMethod.NONE) {
  406.             //Do nothing
  407.         } else {
  408.             throw new ImException(ImErrorInfo.UNSUPPORTED_CIR_CHANNEL,
  409.                     "Unsupported CIR channel binding");
  410.         }
  411.         if(mCirChannel != null) {
  412.             mCirChannel.connect();
  413.         }
  414.     }
  415.     private class PrimitiveDispatcherThread extends Thread {
  416.         private boolean stopped;
  417.         private DataChannel mChannel;
  418.         public PrimitiveDispatcherThread(DataChannel channel)
  419.         {
  420.             super("ImpsPrimitiveDispatcher");
  421.             mChannel = channel;
  422.         }
  423.         @Override
  424.         public void run() {
  425.             Primitive primitive = null;
  426.             while (!stopped) {
  427.                 try {
  428.                     primitive = mChannel.receivePrimitive();
  429.                 } catch (InterruptedException e) {
  430.                     if (stopped) {
  431.                         break;
  432.                     }
  433.                     primitive = null;
  434.                 }
  435.                 if (primitive != null) {
  436.                     try {
  437.                         processIncomingPrimitive(primitive);
  438.                     } catch (Throwable t) {
  439.                         // We don't know what is going to happen in the various
  440.                         // listeners.
  441.                         ImpsLog.logError("ImpsDispatcher: uncaught Throwable", t);
  442.                     }
  443.                 }
  444.             }
  445.         }
  446.         void shutdown() {
  447.             stopped = true;
  448.             interrupt();
  449.         }
  450.     }
  451.     /**
  452.      * Handles the primitive received from the server.
  453.      *
  454.      * @param primitive the received primitive.
  455.      */
  456.     void processIncomingPrimitive(Primitive primitive) {
  457.         // if CIR is 'F', the CIR channel is not available. Re-establish it.
  458.         if (primitive.getCir() != null && ImpsUtils.isFalse(primitive.getCir())) {
  459.             if(mCirChannel != null) {
  460.                 mCirChannel.shutdown();
  461.             }
  462.             try {
  463.                 setupCIRChannel();
  464.             } catch (ImException e) {
  465.                 e.printStackTrace();
  466.             }
  467.         }
  468.         if (primitive.getPoll() != null && ImpsUtils.isTrue(primitive.getPoll())) {
  469.             sendPollingRequest();
  470.         }
  471.         if (primitive.getType().equals(ImpsTags.Disconnect)) {
  472.             if (mState != LOGGING_OUT) {
  473.                 ImErrorInfo error = ImpsUtils.checkResultError(primitive);
  474.                 shutdownOnError(error);
  475.                 return;
  476.             }
  477.         }
  478.         // According to the IMPS spec, only VersionDiscoveryResponse which
  479.         // are not supported now doesn't have a transaction ID.
  480.         if (primitive.getTransactionID() != null) {
  481.             mTransactionManager.notifyIncomingPrimitive(primitive);
  482.         }
  483.     }
  484.     @Override
  485.     protected void doUpdateUserPresenceAsync(Presence presence) {
  486.         ArrayList<PrimitiveElement> presenceSubList = ImpsPresenceUtils.buildUpdatePresenceElems(
  487.                 mUserPresence, presence, mConfig.getPresenceMapping());
  488.         Primitive request = buildUpdatePresenceReq(presenceSubList);
  489.         // Need to make a copy because the presence passed in may change
  490.         // before the transaction finishes.
  491.         final Presence newPresence = new Presence(presence);
  492.         AsyncTransaction tx = new AsyncTransaction(mTransactionManager) {
  493.             @Override
  494.             public void onResponseOk(Primitive response) {
  495.                 savePresenceChange(newPresence);
  496.                 notifyUserPresenceUpdated();
  497.             }
  498.             @Override
  499.             public void onResponseError(ImpsErrorInfo error) {
  500.                 notifyUpdateUserPresenceError(error);
  501.             }
  502.         };
  503.         tx.sendRequest(request);
  504.     }
  505.     void savePresenceChange(Presence newPresence) {
  506.         mUserPresence.setStatusText(newPresence.getStatusText());
  507.         mUserPresence.setStatus(newPresence.getStatus());
  508.         mUserPresence.setAvatar(newPresence.getAvatarData(), newPresence.getAvatarType());
  509.         // no need to update extended info because it's always read only.
  510.     }
  511.     void retrieveUserPresenceAsync(final AsyncCompletion completion) {
  512.         Primitive request = new Primitive(ImpsTags.GetPresence_Request);
  513.         request.addElement(this.getSession().getLoginUserAddress().toPrimitiveElement());
  514.         AsyncTransaction tx = new AsyncTransaction(mTransactionManager){
  515.             @Override
  516.             public void onResponseOk(Primitive response) {
  517.                 PrimitiveElement presence = response.getElement(ImpsTags.Presence);
  518.                 PrimitiveElement presenceSubList = presence.getChild(ImpsTags.PresenceSubList);
  519.                 mUserPresence = ImpsPresenceUtils.extractPresence(presenceSubList,
  520.                         mConfig.getPresenceMapping());
  521.                 // XXX: workaround for the OZ IMPS GTalk server that
  522.                 // returns an initial 'F' OnlineStatus. Set the online
  523.                 // status to available in this case.
  524.                 if(mUserPresence.getStatus() == Presence.OFFLINE) {
  525.                     mUserPresence.setStatus(Presence.AVAILABLE);
  526.                 }
  527.                 compareAndUpdateClientInfo();
  528.             }
  529.             @Override
  530.             public void onResponseError(ImpsErrorInfo error) {
  531.                 mUserPresence = new Presence(Presence.AVAILABLE, "", null,
  532.                         null, Presence.CLIENT_TYPE_MOBILE, ImpsUtils.getClientInfo());
  533.                 completion.onError(error);
  534.             }
  535.             private void compareAndUpdateClientInfo() {
  536.                 if (!ImpsUtils.getClientInfo().equals(mUserPresence.getExtendedInfo())) {
  537.                     updateClientInfoAsync(completion);
  538.                     return;
  539.                 }
  540.                 // no need to update our client info to the server again
  541.                 completion.onComplete();
  542.             }
  543.         };
  544.         tx.sendRequest(request);
  545.     }
  546.     void updateClientInfoAsync(AsyncCompletion completion) {
  547.         Primitive updatePresenceRequest = buildUpdatePresenceReq(buildClientInfoElem());
  548.         AsyncTransaction tx = new SimpleAsyncTransaction(mTransactionManager,
  549.                 completion);
  550.         tx.sendRequest(updatePresenceRequest);
  551.     }
  552.     private Primitive buildUpdatePresenceReq(PrimitiveElement presence) {
  553.         ArrayList<PrimitiveElement> presences = new ArrayList<PrimitiveElement>();
  554.         presences.add(presence);
  555.         return buildUpdatePresenceReq(presences);
  556.     }
  557.     private Primitive buildUpdatePresenceReq(ArrayList<PrimitiveElement> presences) {
  558.         Primitive updatePresenceRequest = new Primitive(ImpsTags.UpdatePresence_Request);
  559.         PrimitiveElement presenceSubList = updatePresenceRequest
  560.                 .addElement(ImpsTags.PresenceSubList);
  561.         presenceSubList.setAttribute(ImpsTags.XMLNS, mConfig.getPresenceNs());
  562.         for (PrimitiveElement presence : presences) {
  563.             presenceSubList.addChild(presence);
  564.         }
  565.         return updatePresenceRequest;
  566.     }
  567.     private PrimitiveElement buildClientInfoElem() {
  568.         PrimitiveElement clientInfo = new PrimitiveElement(ImpsTags.ClientInfo);
  569.         clientInfo.addChild(ImpsTags.Qualifier, true);
  570.         Map<String, String> map = ImpsUtils.getClientInfo();
  571.         for (Map.Entry<String, String> item : map.entrySet()) {
  572.             clientInfo.addChild(item.getKey(), item.getValue());
  573.         }
  574.         return clientInfo;
  575.     }
  576.     Primitive buildBasicLoginReq() {
  577.         Primitive login = new Primitive(ImpsTags.Login_Request);
  578.         login.addElement(ImpsTags.UserID, mSession.getUserName());
  579.         PrimitiveElement clientId = login.addElement(ImpsTags.ClientID);
  580.         clientId.addChild(ImpsTags.URL, mConfig.getClientId());
  581.         if (mConfig.getMsisdn() != null) {
  582.             clientId.addChild(ImpsTags.MSISDN, mConfig.getMsisdn());
  583.         }
  584.         // we request for a bigger TimeToLive value than our default keep
  585.         // alive interval to make sure we always have time to send the keep
  586.         // alive requests.
  587.         login.addElement(ImpsTags.TimeToLive,
  588.                 Integer.toString(mConfig.getDefaultKeepAliveInterval() + 5));
  589.         login.addElement(ImpsTags.SessionCookie, mSession.getCookie());
  590.         return login;
  591.     }
  592.     @Override
  593.     synchronized public void suspend() {
  594.         setState(SUSPENDING, null);
  595.         if (mCirChannel != null) {
  596.             mCirChannel.shutdown();
  597.         }
  598.         if (mDispatcherThread != null) {
  599.             mDispatcherThread.shutdown();
  600.         }
  601.         if (mDataChannel != null) {
  602.             mDataChannel.shutdown();
  603.         }
  604.         setState(SUSPENDED, null);
  605.     }
  606. }