chromium/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.ts

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import '../common/learn_mode_bridge.js';

import {Flags} from '/common/flags.js';
import {InstanceChecker} from '/common/instance_checker.js';
import {LocalStorage} from '/common/local_storage.js';

import {BrailleKeyEvent} from '../common/braille/braille_key_types.js';
import {NavBraille} from '../common/braille/nav_braille.js';
import {EarconId} from '../common/earcon_id.js';
import {LocaleOutputHelper} from '../common/locale_output_helper.js';
import {Msgs} from '../common/msgs.js';
import {PanelCommand, PanelCommandType} from '../common/panel_command.js';
import {PermissionChecker} from '../common/permission_checker.js';
import {SettingsManager} from '../common/settings_manager.js';
import {QueueMode, TtsSpeechProperties} from '../common/tts_types.js';
import {JaPhoneticData} from '../third_party/tamachiyomi/ja_phonetic_data.js';
import {JaPhoneticMap} from '../third_party/tamachiyomi/ja_phonetic_map.js';

import {AbstractEarcons} from './abstract_earcons.js';
import {AutoScrollHandler} from './auto_scroll_handler.js';
import {BrailleBackground} from './braille/braille_background.js';
import {BrailleCommandHandler} from './braille/braille_command_handler.js';
import {ChromeVox} from './chromevox.js';
import {ChromeVoxRange} from './chromevox_range.js';
import {ChromeVoxState} from './chromevox_state.js';
import {DownloadHandler} from './download_handler.js';
import {Earcons} from './earcons.js';
import {EditingRangeObserver} from './editing/editing_range_observer.js';
import {DesktopAutomationHandler} from './event/desktop_automation_handler.js';
import {FocusAutomationHandler} from './event/focus_automation_handler.js';
import {MediaAutomationHandler} from './event/media_automation_handler.js';
import {PageLoadSoundHandler} from './event/page_load_sound_handler.js';
import {RangeAutomationHandler} from './event/range_automation_handler.js';
import {EventSource} from './event_source.js';
import {FindHandler} from './find_handler.js';
import {InjectedScriptLoader} from './injected_script_loader.js';
import {BackgroundKeyboardHandler} from './input/background_keyboard_handler.js';
import {ClipboardHandler} from './input/clipboard_handler.js';
import {CommandHandler} from './input/command_handler.js';
import {GestureCommandHandler} from './input/gesture_command_handler.js';
import {SmartStickyMode} from './input/smart_sticky_mode.js';
import {LiveRegions} from './live_regions.js';
import {EventStreamLogger} from './logging/event_stream_logger.js';
import {LogStore} from './logging/log_store.js';
import {LogUrlWatcher} from './logging/log_url_watcher.js';
import {PanelBackground} from './panel/panel_background.js';
import {ChromeVoxPrefs} from './prefs.js';
import {TtsBackground} from './tts_background.js';

/**
 * @fileoverview The entry point for all ChromeVox related code for the
 * background page.
 */

/** ChromeVox background context. */
export class Background extends ChromeVoxState {
  private startUpTime_ = new Date().getTime();
  private earcons_: AbstractEarcons;
  private isReadingContinuously_ = false;
  private talkBackEnabled_ = false;

  constructor() {
    super();

    this.earcons_ = new Earcons();
    this.earcons_.playEarcon(EarconId.CHROMEVOX_LOADING);

    // Export globals on ChromeVox.
    ChromeVox.braille = BrailleBackground.instance;
    // Read-only earcons.
    Object.defineProperty(ChromeVox, 'earcons', {
      get: () => this.earcons_,
    });

    chrome.accessibilityPrivate.onAnnounceForAccessibility.addListener(
        announceText => {
          ChromeVox.tts.speak(announceText.join(' '), QueueMode.FLUSH);
        });
    chrome.accessibilityPrivate.onCustomSpokenFeedbackToggled.addListener(
        enabled => this.talkBackEnabled_ = enabled);
    chrome.accessibilityPrivate.onShowChromeVoxTutorial.addListener(() => {
      (new PanelCommand(PanelCommandType.TUTORIAL)).send();
    });
  }

  static async init(): Promise<void> {
    // Pre-initialization.
    await Flags.init();
    await LocalStorage.init();
    await SettingsManager.init();
    BrailleBackground.init();
    ChromeVoxPrefs.init();
    ChromeVoxRange.init();
    TtsBackground.init();
    LogStore.init();

    ChromeVoxState.instance = new Background();

    // Standard initialization.
    AutoScrollHandler.init();
    BackgroundKeyboardHandler.init();
    BrailleCommandHandler.init();
    ClipboardHandler.init();
    CommandHandler.init();
    DownloadHandler.init();
    EditingRangeObserver.init();
    EventSource.init();
    FindHandler.init();
    GestureCommandHandler.init();
    InjectedScriptLoader.injectContentScriptForGoogleDocs();
    JaPhoneticData.init(JaPhoneticMap.MAP);
    LiveRegions.init();
    LocaleOutputHelper.init();
    LogUrlWatcher.init();
    PanelBackground.init();
    RangeAutomationHandler.init();
    SmartStickyMode.init();

    // Async initialization.
    // Allow all async initializers to run simultaneously, but wait for them to
    // complete before continuing.
    // The order that these are run in is not guaranteed.
    await Promise.all([
      DesktopAutomationHandler.init(),
      EventStreamLogger.init(),
      FocusAutomationHandler.init(),
      MediaAutomationHandler.init(),
      PageLoadSoundHandler.init(),
      PermissionChecker.init(),
      waitForIntroducePromise,
    ]);
    ChromeVoxState.resolveReadyPromise_();
    ChromeVoxState.instance.onIntroduceChromeVox();
  }

  override get isReadingContinuously(): boolean {
    return this.isReadingContinuously_;
  }

  override get talkBackEnabled(): boolean {
    return this.talkBackEnabled_;
  }

  override set isReadingContinuously(newValue: boolean) {
    this.isReadingContinuously_ = newValue;
  }

  override onBrailleKeyEvent(
      evt: BrailleKeyEvent, content: NavBraille): boolean {
    return BrailleCommandHandler.onBrailleKeyEvent(evt, content);
  }

  /** Handles the onIntroduceChromeVox event. */
  override onIntroduceChromeVox(): void {
    this.earcons_.playEarcon(EarconId.CHROMEVOX_LOADED);
    ChromeVox.tts.speak(
        Msgs.getMsg('chromevox_intro'), QueueMode.QUEUE,
        new TtsSpeechProperties({
          doNotInterrupt: true,
          startCallback: () => {
            chrome.metricsPrivate.recordMediumTime(
                'Accessibility.ChromeVox.StartUpSpeechDelay',
                new Date().getTime() - this.startUpTime_);
          },
        }));
    ChromeVox.braille.write(NavBraille.fromText(Msgs.getMsg('intro_brl')));
  }
}

InstanceChecker.closeExtraInstances();
const waitForIntroducePromise = new Promise(
    (resolve: (value: unknown) => void) =>
        chrome.accessibilityPrivate.onIntroduceChromeVox.addListener(
            resolve as VoidFunction));
Background.init();