@Override
  public void autoLogin() {
    synchronized (this) {
      if (this.userState != GSUserState.Logoff) {
        logger.warn("skip auto login -- user state({}) error", this.userState);
        return;
      }

      if (this.emptyUser()) {

        logger.warn("skip auto login -- can't find user info", this.userState);

        return;
      }

      this.userState = GSUserState.LoginProcessing;

      onUserStateChanged(GSError.SUCCESS);

      try {

        if (emptyToken()) {

          logger.debug("start login({})", this.client.getUser());

          imGateway.Login(this.client.getUser());

          logger.debug("start login({}) -- success", this.client.getUser());

        } else {

          logger.debug("start fastlogin({})", this.client.getUser());

          imGateway.fastLogin(this.client.getUser(), this.client.getToken());

          logger.debug("start fastlogin({}) -- success", this.client.getUser());
        }

        this.binderDataBase.openUserDataBase(client.getUser());

      } catch (Exception e) {

        logger.error("fast login with token {} error", Arrays.toString(this.client.getToken()), e);

        this.userState = GSUserState.Logoff;

        onUserStateChanged(GSError.UNKNOWN_ERROR);
      }
    }
  }
  @Override
  public void logoff() throws RemoteException {
    synchronized (this) {
      String username = this.client.getUser();

      if (username == null) {
        return;
      }

      if (userState == GSUserState.Logoff) {
        return;
      }

      logger.debug("user {} logoff ...", username);

      this.userState = GSUserState.LogoffProcessing;

      onUserStateChanged(GSError.SUCCESS);

      try {
        imGateway.Logoff(this.client.getToken());

      } catch (Exception e) {

        this.userState = GSUserState.Login;

        onUserStateChanged(GSError.UNKNOWN_ERROR);
      }
    }
  }