public void onUpdatePresenceError(final ImErrorInfo error) {
   final int N = mRemoteConnListeners.beginBroadcast();
   for (int i = 0; i < N; i++) {
     IConnectionListener listener = mRemoteConnListeners.getBroadcastItem(i);
     try {
       listener.onUpdatePresenceError(ImConnectionAdapter.this, error);
     } catch (RemoteException e) {
       // The RemoteCallbackList will take care of removing the
       // dead listeners.
     }
   }
   mRemoteConnListeners.finishBroadcast();
 }
    public void onUserPresenceUpdated() {
      updateAccountStatusInDb();

      final int N = mRemoteConnListeners.beginBroadcast();
      for (int i = 0; i < N; i++) {
        IConnectionListener listener = mRemoteConnListeners.getBroadcastItem(i);
        try {
          listener.onUserPresenceUpdated(ImConnectionAdapter.this);
        } catch (RemoteException e) {
          // The RemoteCallbackList will take care of removing the
          // dead listeners.
        }
      }
      mRemoteConnListeners.finishBroadcast();
    }
    public void onStateChanged(final int state, final ImErrorInfo error) {
      synchronized (this) {
        if (state == ImConnection.LOGGED_IN && mConnectionState == ImConnection.LOGGING_OUT) {

          // A bit tricky here. The engine did login successfully
          // but the notification comes a bit late; user has already
          // issued a cancelLogin() and that cannot be undone. Here
          // we have to ignore the LOGGED_IN event and wait for
          // the upcoming DISCONNECTED.
          return;
        }

        if (state != ImConnection.DISCONNECTED) {
          mConnectionState = state;
        }
      }

      ContentResolver cr = mService.getContentResolver();
      if (state == ImConnection.LOGGED_IN) {
        if ((mConnection.getCapability() & ImConnection.CAPABILITY_SESSION_REESTABLISHMENT) != 0) {
          saveSessionCookie(cr);
        }

        if (mAutoLoadContacts
            && mContactListManager.getState() != ContactListManager.LISTS_LOADED) {
          mContactListManager.loadContactLists();
        }

        for (ChatSessionAdapter session : mChatSessionManager.mActiveChatSessionAdapters.values()) {
          session.sendPostponedMessages();
        }
      } else if (state == ImConnection.LOGGING_OUT) {
        // The engine has started to logout the connection, remove it
        // from the active connection list.
        mService.removeConnection(ImConnectionAdapter.this);
      } else if (state == ImConnection.DISCONNECTED) {
        mService.removeConnection(ImConnectionAdapter.this);

        clearSessionCookie(cr);
        // mContactListManager might still be null if we fail
        // immediately in loginAsync (say, an invalid host URL)
        if (mContactListManager != null) {
          mContactListManager.clearOnLogout();
        }
        if (mChatSessionManager != null) {
          mChatSessionManager.closeAllChatSessions();
        }

        mConnectionState = state;
      } else if (state == ImConnection.SUSPENDED && error != null) {
        // re-establish failed, schedule to retry
        // TODO increase delay after retry failed.
        mService.scheduleReconnect(15000);
      }

      updateAccountStatusInDb();

      final int N = mRemoteConnListeners.beginBroadcast();
      for (int i = 0; i < N; i++) {
        IConnectionListener listener = mRemoteConnListeners.getBroadcastItem(i);
        try {
          listener.onStateChanged(ImConnectionAdapter.this, state, error);
        } catch (RemoteException e) {
          // The RemoteCallbackList will take care of removing the
          // dead listeners.
        }
      }
      mRemoteConnListeners.finishBroadcast();
    }