constructor(parent, controls, containerClassNames, barClassNames) {
    super(parent, controls);

    /**
     * This container is to support IE 11.  See detailed notes in
     * less/range_elements.less for a complete explanation.
     * @protected {!HTMLElement}
     */
    this.container = shaka.util.Dom.createHTMLElement('div');
    this.container.classList.add('shaka-range-container');
    this.container.classList.add(...containerClassNames);

    /** @private {boolean} */
    this.isChanging_ = false;

    /** @protected {!HTMLInputElement} */
    this.bar =
      /** @type {!HTMLInputElement} */ (document.createElement('input'));

    /** @private {shaka.util.Timer} */
    this.endFakeChangeTimer_ = new shaka.util.Timer(() => {
      this.onChangeEnd();
      this.isChanging_ = false;
    });

    this.bar.classList.add('shaka-range-element');
    this.bar.classList.add(...barClassNames);
    this.bar.type = 'range';
    this.bar.step = 'any';
    this.bar.min = '0';
    this.bar.max = '1';
    this.bar.value = '0';
    this.bar.disabled = !this.controls.isOpaque();

    this.container.appendChild(this.bar);
    this.parent.appendChild(this.container);

    this.showingUITimer_ = new shaka.util.Timer(() => {
      this.bar.disabled = false;
    });

    this.eventManager.listen(this.controls, 'showingui', (e) => {
      this.showingUITimer_.tickAfter(/* seconds= */ 0);
    });

    this.eventManager.listen(this.controls, 'hidingui', (e) => {
      this.showingUITimer_.stop();
      this.bar.disabled = true;
    });

    this.eventManager.listen(this.bar, 'mousedown', (e) => {
      if (!this.bar.disabled) {
        this.isChanging_ = true;
        this.onChangeStart();
        e.stopPropagation();
      }
    });

    this.eventManager.listen(this.bar, 'touchstart', (e) => {
      if (!this.bar.disabled) {
        this.isChanging_ = true;
        this.setBarValueForTouch_(e);
        this.onChangeStart();
        e.stopPropagation();
      }
    });

    this.eventManager.listen(this.bar, 'input', () => {
      this.onChange();
    });

    this.eventManager.listen(this.bar, 'touchmove', (e) => {
      if (this.isChanging_) {
        this.setBarValueForTouch_(e);
        this.onChange();
        e.stopPropagation();
      }
    });

    this.eventManager.listen(this.bar, 'touchend', (e) => {
      if (this.isChanging_) {
        this.isChanging_ = false;
        this.setBarValueForTouch_(e);
        this.onChangeEnd();
        e.stopPropagation();
      }
    });

    this.eventManager.listen(this.bar, 'touchcancel', (e) => {
      if (this.isChanging_) {
        this.isChanging_ = false;
        this.setBarValueForTouch_(e);
        this.onChangeEnd();
        e.stopPropagation();
      }
    });

    this.eventManager.listen(this.bar, 'mouseup', (e) => {
      if (this.isChanging_) {
        this.isChanging_ = false;
        this.onChangeEnd();
        e.stopPropagation();
      }
    });

    this.eventManager.listen(this.bar, 'blur', () => {
      if (this.isChanging_) {
        this.isChanging_ = false;
        this.onChangeEnd();
      }
    });

    this.eventManager.listen(this.bar, 'contextmenu', (e) => {
      e.preventDefault();
      e.stopPropagation();
    });
  }
@param {!HTMLElement} parent
@param {!shaka.ui.Controls} controls
@param {!Array<string>} containerClassNames
@param {!Array<string>} barClassNames