/**
   * Checks according to preferences and charging/wifi state, whether syncthing should be enabled or
   * not.
   *
   * <p>Depending on the result, syncthing is started or stopped, and {@link #onApiChange()} is
   * called.
   */
  public void updateState() {
    // Start syncthing.
    if (mDeviceStateHolder.shouldRun()) {
      if (mCurrentState == State.ACTIVE || mCurrentState == State.STARTING) {
        mStopScheduled = false;
        return;
      }

      // HACK: Make sure there is no syncthing binary left running from an improper
      // shutdown (eg Play Store update).
      // NOTE: This will log an exception if syncthing is not actually running.
      shutdown();

      Log.i(TAG, "Starting syncthing according to current state and preferences");
      mConfig = null;
      try {
        mConfig = new ConfigXml(SyncthingService.this);
      } catch (ConfigXml.OpenConfigException e) {
        mCurrentState = State.ERROR;
        Toast.makeText(this, R.string.config_create_failed, Toast.LENGTH_LONG).show();
      }

      if (mConfig != null) {
        mCurrentState = State.STARTING;

        if (mApi != null) registerOnWebGuiAvailableListener(mApi);
        if (mEventProcessor != null) registerOnWebGuiAvailableListener(mEventProcessor);
        new PollWebGuiAvailableTaskImpl(
                getWebGuiUrl(), getFilesDir() + "/" + HTTPS_CERT_FILE, mConfig.getApiKey())
            .execute();
        mRunnable = new SyncthingRunnable(this, SyncthingRunnable.Command.main);
        new Thread(mRunnable).start();
        updateNotification();
      }
    }
    // Stop syncthing.
    else {
      if (mCurrentState == State.DISABLED) return;

      Log.i(TAG, "Stopping syncthing according to current state and preferences");
      mCurrentState = State.DISABLED;

      shutdown();
    }
    onApiChange();
  }
  /**
   * Handles intents, either {@link #ACTION_RESTART}, or intents having {@link
   * DeviceStateHolder#EXTRA_HAS_WIFI} or {@link DeviceStateHolder#EXTRA_IS_CHARGING} (which are
   * handled by {@link DeviceStateHolder}.
   */
  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    if (intent == null) return START_STICKY;

    if (ACTION_RESTART.equals(intent.getAction()) && mCurrentState == State.ACTIVE) {
      shutdown();
      mCurrentState = State.INIT;
      updateState();
    } else if (ACTION_RESET.equals(intent.getAction())) {
      shutdown();
      new SyncthingRunnable(this, SyncthingRunnable.Command.reset).run();
      mCurrentState = State.INIT;
      updateState();
    } else if (mCurrentState != State.INIT) {
      mDeviceStateHolder.update(intent);
      updateState();
    }
    return START_STICKY;
  }