docs: public void pingServerIfNecessary() {
          final XMPPConnection connection = connection();
          if (connection == null) {
              // connection has been collected by GC
              // which means we can stop the thread by breaking the loop
              return;
          }
          if (pingInterval <= 0) {
              // Ping has been disabled
              return;
          }
          long lastStanzaReceived = connection.getLastStanzaReceived();
          if (lastStanzaReceived > 0) {
              long now = System.currentTimeMillis();
              // Delta since the last stanza was received
              int deltaInSeconds = (int)  ((now - lastStanzaReceived) / 1000);
              // If the delta is small then the ping interval, then we can defer the ping
              if (deltaInSeconds < pingInterval) {
                  maybeSchedulePingServerTask(deltaInSeconds);
                  return;
              }
          }
          if (!connection.isAuthenticated()) {
              LOGGER.warning(connection + " was not authenticated");
              return;
          }
  
          final long minimumTimeout = TimeUnit.MINUTES.toMillis(2);
          final long connectionReplyTimeout = connection.getReplyTimeout();
          final long timeout = connectionReplyTimeout > minimumTimeout ? connectionReplyTimeout : minimumTimeout;
  
          SmackFuture<Boolean, Exception> pingFuture = pingAsync(connection.getXMPPServiceDomain(), timeout);
          pingFuture.onSuccess(new SuccessCallback<Boolean>() {
              @Override
              public void onSuccess(Boolean result) {
                  // Ping was successful, wind-up the periodic task again
                  maybeSchedulePingServerTask();
              }
          });
          pingFuture.onError(new ExceptionCallback<Exception>() {
              @Override
              public void processException(Exception exception) {
                  long lastStanzaReceived = connection.getLastStanzaReceived();
                  if (lastStanzaReceived > 0) {
                      long now = System.currentTimeMillis();
                      // Delta since the last stanza was received
                      int deltaInSeconds = (int)  ((now - lastStanzaReceived) / 1000);
                      // If the delta is smaller then the ping interval, we have got an valid stanza in time
                      // So not error notification needed
                      if (deltaInSeconds < pingInterval) {
                          maybeSchedulePingServerTask(deltaInSeconds);
                          return;
                      }
                  }
  
                  for (PingFailedListener l : pingFailedListeners) {
                      l.pingFailed();
                  }
              }
          });
      }