1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// found in the LICENSE file.
4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @fileoverview Script that runs on the background page.
7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.provide('cvox.ChromeVoxBackground');
11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.AbstractEarcons');
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.AccessibilityApiHandler');
14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.BrailleBackground');
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.BrailleCaptionsBackground');
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.ChromeVox');
17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.ChromeVoxEditableTextBase');
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.ChromeVoxPrefs');
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.CompositeTts');
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.ConsoleTts');
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.EarconsBackground');
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.ExtensionBridge');
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.HostFactory');
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.InjectedScriptLoader');
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccigoog.require('cvox.Msgs');
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.NavBraille');
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// TODO(dtseng): This is required to prevent Closure from stripping our export
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// prefs on window.
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.OptionsPage');
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.PlatformFilter');
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.PlatformUtil');
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccigoog.require('cvox.TabsApiHandler');
33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.TtsBackground');
34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * This object manages the global and persistent state for ChromeVox.
38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * It listens for messages from the content scripts on pages and
39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * interprets them.
40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @constructor
41cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.ChromeVoxBackground = function() {
43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Initialize the background page: set up TTS and bridge listeners.
48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.ChromeVoxBackground.prototype.init = function() {
50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // In the case of ChromeOS, only continue initialization if this instance of
51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // ChromeVox is as we expect. This prevents ChromeVox from the webstore from
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // running.
53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (cvox.ChromeVox.isChromeOS &&
54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      chrome.i18n.getMessage('@@extension_id') !=
55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          'mndnfokpggljbaajbnioimlmbfngpief') {
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  cvox.ChromeVox.msgs = new cvox.Msgs();
60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  this.prefs = new cvox.ChromeVoxPrefs();
61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  this.readPrefs();
62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var consoleTts = cvox.ConsoleTts.getInstance();
64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  consoleTts.setEnabled(true);
65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  /**
67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)   * Chrome's actual TTS which knows and cares about pitch, volume, etc.
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)   * @type {cvox.TtsBackground}
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)   * @private
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)   */
71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  this.backgroundTts_ = new cvox.TtsBackground();
72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  /**
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)   * @type {cvox.TtsInterface}
75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)   */
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  this.tts = new cvox.CompositeTts()
77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      .add(this.backgroundTts_)
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      .add(consoleTts);
79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  this.earcons = new cvox.EarconsBackground();
81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  this.addBridgeListener();
82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  /**
84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)   * The actual Braille service.
85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)   * @type {cvox.BrailleBackground}
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)   * @private
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)   */
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  this.backgroundBraille_ = new cvox.BrailleBackground();
89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  this.accessibilityApiHandler_ = new cvox.AccessibilityApiHandler(
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      this.tts, this.backgroundBraille_, this.earcons);
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.tabsApiHandler_ = new cvox.TabsApiHandler(
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      this.tts, this.backgroundBraille_, this.earcons);
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Export globals on cvox.ChromeVox.
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  cvox.ChromeVox.tts = this.tts;
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  cvox.ChromeVox.braille = this.backgroundBraille_;
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  cvox.ChromeVox.earcons = this.earcons;
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // TODO(dtseng): Remove the second check on or after m33.
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (cvox.ChromeVox.isChromeOS &&
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      chrome.accessibilityPrivate.onChromeVoxLoadStateChanged) {
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    chrome.accessibilityPrivate.onChromeVoxLoadStateChanged.addListener(
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        this.onLoadStateChanged);
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  this.checkVersionNumber();
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Set up a message passing system for goog.provide() calls from
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // within the content scripts.
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  chrome.extension.onMessage.addListener(
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      function(request, sender, callback) {
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        if (request['srcFile']) {
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          var srcFile = request['srcFile'];
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          cvox.InjectedScriptLoader.fetchCode(
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              [srcFile],
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              function(code) {
118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                callback({'code': code[srcFile]});
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              });
120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        }
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        return true;
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      });
123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  var self = this;
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (chrome.commandLinePrivate) {
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    chrome.commandLinePrivate.hasSwitch('enable-chromevox-next',
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        goog.bind(function(result) {
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            if (result) {
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              return;
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            }
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            // Inject the content script into all running tabs.
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            chrome.windows.getAll({'populate': true}, function(windows) {
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              for (var i = 0; i < windows.length; i++) {
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                var tabs = windows[i].tabs;
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                self.injectChromeVoxIntoTabs(tabs);
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              }
1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            });
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        }, this));
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (localStorage['active'] == 'false') {
142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Warn the user when the browser first starts if ChromeVox is inactive.
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    this.tts.speak(cvox.ChromeVox.msgs.getMsg('chromevox_inactive'), 1);
144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else if (cvox.PlatformUtil.matchesPlatform(cvox.PlatformFilter.WML)) {
145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Introductory message.
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    this.tts.speak(cvox.ChromeVox.msgs.getMsg('chromevox_intro'), 1);
147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    cvox.ChromeVox.braille.write(cvox.NavBraille.fromText(
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        cvox.ChromeVox.msgs.getMsg('intro_brl')));
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Inject ChromeVox into a tab.
1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {Array.<Tab>} tabs The tab where ChromeVox scripts should be injected.
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {boolean=} opt_forceCompiled forces compiled ChromeVox to be injected;
1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * defaults to Closure's compiled flag.
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccicvox.ChromeVoxBackground.prototype.injectChromeVoxIntoTabs =
1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    function(tabs, opt_forceCompiled) {
1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  var listOfFiles;
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // These lists of files must match the content_scripts section in
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // the manifest files.
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (COMPILED || opt_forceCompiled) {
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    listOfFiles = ['chromeVoxChromePageScript.js'];
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else {
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    listOfFiles = [
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        'closure/closure_preinit.js',
1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        'closure/base.js',
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        'deps.js',
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        'chromevox/injected/loader.js'];
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  var stageTwo = function(code) {
1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    for (var i = 0, tab; tab = tabs[i]; i++) {
1771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      window.console.log('Injecting into ' + tab.id, tab);
1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      var sawError = false;
1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      /**
1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       * A helper function which executes code.
1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       * @param {string} code The code to execute.
1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       */
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      var executeScript = goog.bind(function(code) {
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        chrome.tabs.executeScript(
1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            tab.id,
1871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            {'code': code,
1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci             'allFrames': true},
1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            goog.bind(function() {
1901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              if (!chrome.extension.lastError) {
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                return;
1921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              }
1931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              if (sawError) {
1941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                return;
1951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              }
1961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              sawError = true;
1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              console.error('Could not inject into tab', tab);
1981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              this.tts.speak('Error starting ChromeVox for ' +
1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                  tab.title + ', ' + tab.url, 1);
2001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            }, this));
2011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      }, this);
2021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // There is a scenario where two copies of the content script can get
2041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // loaded into the same tab on browser startup - one automatically and one
2051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // because the background page injects the content script into every tab
2061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // on startup. To work around potential bugs resulting from this,
2071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // ChromeVox exports a global function called disableChromeVox() that can
2081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // be used here to disable any existing running instance before we inject
2091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // a new instance of the content script into this tab.
2101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      //
2111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // It's harmless if there wasn't a copy of ChromeVox already running.
2121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      //
2131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // Also, set some variables so that Closure deps work correctly and so
2141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // that ChromeVox knows not to announce feedback as if a page just loaded.
2151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      executeScript('try { window.disableChromeVox(); } catch(e) { }\n' +
2161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          'window.INJECTED_AFTER_LOAD = true;\n' +
2171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          'window.CLOSURE_NO_DEPS = true\n');
2181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // Now inject the ChromeVox content script code into the tab.
2201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      listOfFiles.forEach(function(file) { executeScript(code[file]); });
2211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
2221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  };
2231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // We use fetchCode instead of chrome.extensions.executeFile because
2251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // executeFile doesn't propagate the file name to the content script
2261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // which means that script is not visible in Dev Tools.
2271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  cvox.InjectedScriptLoader.fetchCode(listOfFiles, stageTwo);
228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
229cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
230cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Called when a TTS message is received from a page content script.
233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {Object} msg The TTS message.
234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
235cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.ChromeVoxBackground.prototype.onTtsMessage = function(msg) {
236cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (msg['action'] == 'speak') {
237cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Tell the handler for native UI (chrome of chrome) events that
238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // the last speech came from web, and not from native UI.
239cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    this.accessibilityApiHandler_.setWebContext();
240cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    this.tts.speak(msg['text'], msg['queueMode'], msg['properties']);
241cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else if (msg['action'] == 'stop') {
242cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    this.tts.stop();
243cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else if (msg['action'] == 'increaseOrDecrease') {
244cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    this.tts.increaseOrDecreaseProperty(msg['property'], msg['increase']);
245cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var property = msg['property'];
246cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var engine = this.backgroundTts_;
247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var valueAsPercent = Math.round(
248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        this.backgroundTts_.propertyToPercentage(property) * 100);
249cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var announcement;
250cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    switch (msg['property']) {
251cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case cvox.AbstractTts.RATE:
252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      announcement = cvox.ChromeVox.msgs.getMsg('announce_rate',
253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                                [valueAsPercent]);
254cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      break;
255cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case cvox.AbstractTts.PITCH:
256cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      announcement = cvox.ChromeVox.msgs.getMsg('announce_pitch',
257cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                                [valueAsPercent]);
258cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      break;
259cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case cvox.AbstractTts.VOLUME:
260cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      announcement = cvox.ChromeVox.msgs.getMsg('announce_volume',
261cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                                [valueAsPercent]);
262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      break;
263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
264cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (announcement) {
265cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      this.tts.speak(announcement,
266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                     cvox.AbstractTts.QUEUE_MODE_FLUSH,
267cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                     cvox.AbstractTts.PERSONALITY_ANNOTATION);
268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
269cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else if (msg['action'] == 'cyclePunctuationEcho') {
270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    this.tts.speak(cvox.ChromeVox.msgs.getMsg(
271cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            this.backgroundTts_.cyclePunctuationEcho()),
272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                   cvox.AbstractTts.QUEUE_MODE_FLUSH);
273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
275cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
276cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
277cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
278cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Called when an earcon message is received from a page content script.
279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {Object} msg The earcon message.
280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.ChromeVoxBackground.prototype.onEarconMessage = function(msg) {
282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (msg.action == 'play') {
283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    this.earcons.playEarcon(msg.earcon);
284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
285cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
286cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
288cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
289cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Listen for connections from our content script bridges, and dispatch the
290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * messages to the proper destination.
291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.ChromeVoxBackground.prototype.addBridgeListener = function() {
293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  cvox.ExtensionBridge.addMessageListener(goog.bind(function(msg, port) {
294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var target = msg['target'];
295cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var action = msg['action'];
296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    switch (target) {
298cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case 'OpenTab':
299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      var destination = new Object();
300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      destination.url = msg['url'];
301cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      chrome.tabs.create(destination);
302cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      break;
303cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case 'KbExplorer':
304cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      var explorerPage = new Object();
305cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      explorerPage.url = 'chromevox/background/kbexplorer.html';
306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      chrome.tabs.create(explorerPage);
307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      break;
308cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case 'HelpDocs':
309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      var helpPage = new Object();
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      helpPage.url = 'http://chromevox.com/tutorial/index.html';
311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      chrome.tabs.create(helpPage);
312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      break;
313cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case 'Options':
314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (action == 'open') {
315cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        var optionsPage = new Object();
316cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        optionsPage.url = 'chromevox/background/options.html';
317cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        chrome.tabs.create(optionsPage);
318cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
319cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      break;
320cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case 'Data':
321cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (action == 'getHistory') {
322cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        var results = {};
323cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        chrome.history.search({text: '', maxResults: 25}, function(items) {
324cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          items.forEach(function(item) {
325cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            if (item.url) {
326cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              results[item.url] = true;
327cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            }
328cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          });
329cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          port.postMessage({
330cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            'history': results
331cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          });
332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        });
333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
334cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      break;
335cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case 'Prefs':
336cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (action == 'getPrefs') {
337cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        this.prefs.sendPrefsToPort(port);
338cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      } else if (action == 'setPref') {
339cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        if (msg['pref'] == 'active' &&
340cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            msg['value'] != cvox.ChromeVox.isActive) {
341cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          if (cvox.ChromeVox.isActive) {
342cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            this.tts.speak(cvox.ChromeVox.msgs.getMsg('chromevox_inactive'));
343cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            chrome.accessibilityPrivate.setNativeAccessibilityEnabled(
344cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                true);
345cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          } else {
346cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            chrome.accessibilityPrivate.setNativeAccessibilityEnabled(
347cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                false);
348cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          }
349cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        } else if (msg['pref'] == 'earcons') {
350cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          this.earcons.enabled = msg['value'];
351cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        } else if (msg['pref'] == 'sticky' && msg['announce']) {
352cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          if (msg['value']) {
353cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            this.tts.speak(cvox.ChromeVox.msgs.getMsg('sticky_mode_enabled'));
354cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          } else {
355cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            this.tts.speak(
356cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                cvox.ChromeVox.msgs.getMsg('sticky_mode_disabled'));
357cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          }
358cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        } else if (msg['pref'] == 'typingEcho' && msg['announce']) {
359cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          var announce = '';
360cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          switch (msg['value']) {
361cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            case cvox.TypingEcho.CHARACTER:
362cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              announce = cvox.ChromeVox.msgs.getMsg('character_echo');
363cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              break;
364cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            case cvox.TypingEcho.WORD:
365cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              announce = cvox.ChromeVox.msgs.getMsg('word_echo');
366cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              break;
367cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            case cvox.TypingEcho.CHARACTER_AND_WORD:
368cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              announce = cvox.ChromeVox.msgs.getMsg('character_and_word_echo');
369cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              break;
370cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            case cvox.TypingEcho.NONE:
371cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              announce = cvox.ChromeVox.msgs.getMsg('none_echo');
372cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              break;
373cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            default:
374cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              break;
375cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          }
376cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          if (announce) {
377cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            this.tts.speak(announce);
378cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          }
379cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        } else if (msg['pref'] == 'brailleCaptions') {
380cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          cvox.BrailleCaptionsBackground.setActive(msg['value']);
381cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        }
382cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        this.prefs.setPref(msg['pref'], msg['value']);
383cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        this.readPrefs();
384cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
385cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      break;
386cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case 'Math':
387cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // TODO (sorge): Put the change of styles etc. here!
388cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (msg['action'] == 'getDomains') {
389cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        port.postMessage({'message': 'DOMAINS_STYLES',
390cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                          'domains': this.backgroundTts_.mathmap.allDomains,
391cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                          'styles': this.backgroundTts_.mathmap.allStyles});
392cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
393cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      break;
394cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case 'TTS':
395cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (msg['startCallbackId'] != undefined) {
396cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        msg['properties']['startCallback'] = function() {
397cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          port.postMessage({'message': 'TTS_CALLBACK',
398cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            'id': msg['startCallbackId']});
399cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        };
400cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
401cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (msg['endCallbackId'] != undefined) {
402cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        msg['properties']['endCallback'] = function() {
403cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          port.postMessage({'message': 'TTS_CALLBACK',
404cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            'id': msg['endCallbackId']});
405cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        };
406cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
407cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      try {
408cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        this.onTtsMessage(msg);
409cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      } catch (err) {
410cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        console.log(err);
411cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
412cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      break;
413cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case 'EARCON':
414cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      this.onEarconMessage(msg);
415cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      break;
416cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case 'BRAILLE':
417cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      try {
418cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        this.backgroundBraille_.onBrailleMessage(msg);
419cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      } catch (err) {
420cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        console.log(err);
421cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
422cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      break;
423cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
424cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }, this));
425cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
426cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
427cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
428cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
429cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Checks the version number. If it has changed, display release notes
430cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * to the user.
431cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
432cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.ChromeVoxBackground.prototype.checkVersionNumber = function() {
433cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Don't update version or show release notes if the current tab is within an
434cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // incognito window (which may occur on ChromeOS immediately after OOBE).
435cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (this.isIncognito_()) {
436cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
437cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
438cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  this.localStorageVersion = localStorage['versionString'];
439cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  this.showNotesIfNewVersion();
440cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
441cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
442cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
443cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
444cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Display release notes to the user.
445cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
446cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.ChromeVoxBackground.prototype.displayReleaseNotes = function() {
447cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  chrome.tabs.create(
448cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      {'url': 'http://chromevox.com/release_notes.html'});
449cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
450cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
451cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
452cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
453cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Gets the current version number from the extension manifest.
454cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
455cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.ChromeVoxBackground.prototype.showNotesIfNewVersion = function() {
456cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Check version number in manifest.
457cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var url = chrome.extension.getURL('manifest.json');
458cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var xhr = new XMLHttpRequest();
459cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var context = this;
460cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  xhr.onreadystatechange = function() {
461cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (xhr.readyState == 4) {
462cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      var manifest = JSON.parse(xhr.responseText);
463cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      console.log('Version: ' + manifest.version);
464cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
465cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      var shouldShowReleaseNotes =
466cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          (context.localStorageVersion != manifest.version);
467cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
468cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // On Chrome OS, don't show the release notes the first time, only
469cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // after a version upgrade.
470cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (navigator.userAgent.indexOf('CrOS') != -1 &&
471cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          context.localStorageVersion == undefined) {
472cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        shouldShowReleaseNotes = false;
473cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
474cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
475cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (shouldShowReleaseNotes) {
476cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        context.displayReleaseNotes();
477cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
478cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
479cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // Update version number in local storage
480cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      localStorage['versionString'] = manifest.version;
481cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      this.localStorageVersion = manifest.version;
482cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
483cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  };
484cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  xhr.open('GET', url);
485cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  xhr.send();
486cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
487cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
488cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
489cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
490cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Read and apply preferences that affect the background context.
491cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
492cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.ChromeVoxBackground.prototype.readPrefs = function() {
493cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var prefs = this.prefs.getPrefs();
494cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  cvox.ChromeVoxEditableTextBase.useIBeamCursor =
495cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      (prefs['useIBeamCursor'] == 'true');
496cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  cvox.ChromeVox.isActive =
497cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      (prefs['active'] == 'true' || cvox.ChromeVox.isChromeOS);
49846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  cvox.ChromeVox.isStickyPrefOn = (prefs['sticky'] == 'true');
499cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
500cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
501cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
502cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Checks if we are currently in an incognito window.
503cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @return {boolean} True if incognito or not within a tab context, false
504cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * otherwise.
505cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @private
506cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
507cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.ChromeVoxBackground.prototype.isIncognito_ = function() {
508cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var incognito = false;
509cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  chrome.tabs.getCurrent(function(tab) {
510cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Tab is null if not called from a tab context. In that case, also consider
511cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // it incognito.
512cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    incognito = tab ? tab.incognito : true;
513cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  });
514cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return incognito;
515cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
516cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
517cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
518cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// TODO(dtseng): The loading param is no longer used. Remove it once the
519cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// upstream Chrome API changes.
520cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
521cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Handles the onChromeVoxLoadStateChanged event.
522cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {boolean} loading True if ChromeVox is loading; false if it is
523cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * unloading.
524cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {boolean} makeAnnouncements True if announcements should be made.
525cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
526cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.ChromeVoxBackground.prototype.onLoadStateChanged = function(
527cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    loading, makeAnnouncements) {
528cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (loading) {
529cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (makeAnnouncements) {
530cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        cvox.ChromeVox.tts.speak(cvox.ChromeVox.msgs.getMsg('chromevox_intro'),
531cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                 1,
532cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                 {doNotInterrupt: true});
533cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        cvox.ChromeVox.braille.write(cvox.NavBraille.fromText(
534cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            cvox.ChromeVox.msgs.getMsg('intro_brl')));
535cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
536cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
537cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  };
538cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
539cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
540cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Create the background page object and export a function window['speak']
541cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// so that other background pages can access it. Also export the prefs object
542cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// for access by the options page.
543cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)(function() {
544cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var background = new cvox.ChromeVoxBackground();
545cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  background.init();
546cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  window['speak'] = goog.bind(background.tts.speak, background.tts);
547cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
548cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Export the prefs object for access by the options page.
549cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  window['prefs'] = background.prefs;
550cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
551cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Export the braille object for access by the options page.
552cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  window['braille'] = cvox.ChromeVox.braille;
5531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
5541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Export this background page for ChromeVox Next to access.
5551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  cvox.ChromeVox.background = background;
556cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)})();
557