| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 cr.define('hotword', function() { | 5 cr.define('hotword', function() { |
| 6 'use strict'; | 6 'use strict'; |
| 7 | 7 |
| 8 /** | 8 /** |
| 9 * Class used to manage the interaction between hotwording and the | 9 * Class used to manage the interaction between hotwording and the |
| 10 * NTP/google.com. Injects a content script to interact with NTP/google.com | 10 * NTP/google.com. Injects a content script to interact with NTP/google.com |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 | 55 |
| 56 PageAudioManager.prototype = { | 56 PageAudioManager.prototype = { |
| 57 /** | 57 /** |
| 58 * Helper function to test if a URL path is eligible for hotwording. | 58 * Helper function to test if a URL path is eligible for hotwording. |
| 59 * @param {!string} url URL to check. | 59 * @param {!string} url URL to check. |
| 60 * @param {!string} base Base URL to compare against.. | 60 * @param {!string} base Base URL to compare against.. |
| 61 * @return {boolean} True if url is an eligible hotword URL. | 61 * @return {boolean} True if url is an eligible hotword URL. |
| 62 * @private | 62 * @private |
| 63 */ | 63 */ |
| 64 checkUrlPathIsEligible_: function(url, base) { | 64 checkUrlPathIsEligible_: function(url, base) { |
| 65 if (url == base || | 65 if (url == base || url == base + '/' || |
| 66 url == base + '/' || | |
| 67 url.startsWith(base + '/_/chrome/newtab?') || // Appcache NTP. | 66 url.startsWith(base + '/_/chrome/newtab?') || // Appcache NTP. |
| 68 url.startsWith(base + '/?') || | 67 url.startsWith(base + '/?') || url.startsWith(base + '/#') || |
| 69 url.startsWith(base + '/#') || | 68 url.startsWith(base + '/webhp') || url.startsWith(base + '/search') || |
| 70 url.startsWith(base + '/webhp') || | |
| 71 url.startsWith(base + '/search') || | |
| 72 url.startsWith(base + '/imghp')) { | 69 url.startsWith(base + '/imghp')) { |
| 73 return true; | 70 return true; |
| 74 } | 71 } |
| 75 return false; | 72 return false; |
| 76 }, | 73 }, |
| 77 | 74 |
| 78 /** | 75 /** |
| 79 * Determines if a URL is eligible for hotwording. For now, the valid pages | 76 * Determines if a URL is eligible for hotwording. For now, the valid pages |
| 80 * are the Google HP and SERP (this will include the NTP). | 77 * are the Google HP and SERP (this will include the NTP). |
| 81 * @param {!string} url URL to check. | 78 * @param {!string} url URL to check. |
| 82 * @return {boolean} True if url is an eligible hotword URL. | 79 * @return {boolean} True if url is an eligible hotword URL. |
| 83 * @private | 80 * @private |
| 84 */ | 81 */ |
| 85 isEligibleUrl_: function(url) { | 82 isEligibleUrl_: function(url) { |
| 86 if (!url) | 83 if (!url) |
| 87 return false; | 84 return false; |
| 88 | 85 |
| 89 var baseGoogleUrls = [ | 86 var baseGoogleUrls = [ |
| 90 'https://encrypted.google.', | 87 'https://encrypted.google.', 'https://images.google.', |
| 91 'https://images.google.', | |
| 92 'https://www.google.' | 88 'https://www.google.' |
| 93 ]; | 89 ]; |
| 94 // TODO(amistry): Get this list from a file in the shared module instead. | 90 // TODO(amistry): Get this list from a file in the shared module instead. |
| 95 var tlds = [ | 91 var tlds = [ |
| 96 'at', | 92 'at', 'ca', 'com', 'com.au', 'com.mx', 'com.br', 'co.jp', 'co.kr', |
| 97 'ca', | 93 'co.nz', 'co.uk', 'co.za', 'de', 'es', 'fr', 'it', 'ru' |
| 98 'com', | |
| 99 'com.au', | |
| 100 'com.mx', | |
| 101 'com.br', | |
| 102 'co.jp', | |
| 103 'co.kr', | |
| 104 'co.nz', | |
| 105 'co.uk', | |
| 106 'co.za', | |
| 107 'de', | |
| 108 'es', | |
| 109 'fr', | |
| 110 'it', | |
| 111 'ru' | |
| 112 ]; | 94 ]; |
| 113 | 95 |
| 114 // Check for the new tab page first. | 96 // Check for the new tab page first. |
| 115 if (this.checkUrlPathIsEligible_(url, 'chrome://newtab')) | 97 if (this.checkUrlPathIsEligible_(url, 'chrome://newtab')) |
| 116 return true; | 98 return true; |
| 117 | 99 |
| 118 // Check URLs with each type of local-based TLD. | 100 // Check URLs with each type of local-based TLD. |
| 119 for (var i = 0; i < baseGoogleUrls.length; i++) { | 101 for (var i = 0; i < baseGoogleUrls.length; i++) { |
| 120 for (var j = 0; j < tlds.length; j++) { | 102 for (var j = 0; j < tlds.length; j++) { |
| 121 var base = baseGoogleUrls[i] + tlds[j]; | 103 var base = baseGoogleUrls[i] + tlds[j]; |
| 122 if (this.checkUrlPathIsEligible_(url, base)) | 104 if (this.checkUrlPathIsEligible_(url, base)) |
| 123 return true; | 105 return true; |
| 124 } | 106 } |
| 125 } | 107 } |
| 126 return false; | 108 return false; |
| 127 }, | 109 }, |
| 128 | 110 |
| 129 /** | 111 /** |
| 130 * Locates the current active tab in the current focused window and | 112 * Locates the current active tab in the current focused window and |
| 131 * performs a callback with the tab as the parameter. | 113 * performs a callback with the tab as the parameter. |
| 132 * @param {function(?Tab)} callback Function to call with the | 114 * @param {function(?Tab)} callback Function to call with the |
| 133 * active tab or null if not found. The function's |this| will be set to | 115 * active tab or null if not found. The function's |this| will be set to |
| 134 * this object. | 116 * this object. |
| 135 * @private | 117 * @private |
| 136 */ | 118 */ |
| 137 findCurrentTab_: function(callback) { | 119 findCurrentTab_: function(callback) { |
| 138 chrome.windows.getAll( | 120 chrome.windows.getAll({'populate': true}, function(windows) { |
| 139 {'populate': true}, | 121 for (var i = 0; i < windows.length; ++i) { |
| 140 function(windows) { | 122 if (!windows[i].focused) |
| 141 for (var i = 0; i < windows.length; ++i) { | 123 continue; |
| 142 if (!windows[i].focused) | |
| 143 continue; | |
| 144 | 124 |
| 145 for (var j = 0; j < windows[i].tabs.length; ++j) { | 125 for (var j = 0; j < windows[i].tabs.length; ++j) { |
| 146 var tab = windows[i].tabs[j]; | 126 var tab = windows[i].tabs[j]; |
| 147 if (tab.active) { | 127 if (tab.active) { |
| 148 callback.call(this, tab); | 128 callback.call(this, tab); |
| 149 return; | 129 return; |
| 150 } | |
| 151 } | |
| 152 } | 130 } |
| 153 callback.call(this, null); | 131 } |
| 154 }.bind(this)); | 132 } |
| 133 callback.call(this, null); |
| 134 }.bind(this)); |
| 155 }, | 135 }, |
| 156 | 136 |
| 157 /** | 137 /** |
| 158 * This function is called when a tab is activated (comes into focus). | 138 * This function is called when a tab is activated (comes into focus). |
| 159 * @param {Tab} tab Current active tab. | 139 * @param {Tab} tab Current active tab. |
| 160 * @private | 140 * @private |
| 161 */ | 141 */ |
| 162 activateTab_: function(tab) { | 142 activateTab_: function(tab) { |
| 163 if (!tab) { | 143 if (!tab) { |
| 164 this.stopHotwording_(); | 144 this.stopHotwording_(); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 175 /** | 155 /** |
| 176 * Prepare a new or updated tab by injecting the content script. | 156 * Prepare a new or updated tab by injecting the content script. |
| 177 * @param {!Tab} tab Newly updated or created tab. | 157 * @param {!Tab} tab Newly updated or created tab. |
| 178 * @private | 158 * @private |
| 179 */ | 159 */ |
| 180 prepareTab_: function(tab) { | 160 prepareTab_: function(tab) { |
| 181 if (!this.isEligibleUrl_(tab.url)) | 161 if (!this.isEligibleUrl_(tab.url)) |
| 182 return; | 162 return; |
| 183 | 163 |
| 184 chrome.tabs.executeScript( | 164 chrome.tabs.executeScript( |
| 185 tab.id, | 165 tab.id, {'file': 'audio_client.js'}, function(results) { |
| 186 {'file': 'audio_client.js'}, | |
| 187 function(results) { | |
| 188 if (chrome.runtime.lastError) { | 166 if (chrome.runtime.lastError) { |
| 189 // Ignore this error. For new tab pages, even though the URL is | 167 // Ignore this error. For new tab pages, even though the URL is |
| 190 // reported to be chrome://newtab/, the actual URL is a | 168 // reported to be chrome://newtab/, the actual URL is a |
| 191 // country-specific google domain. Since we don't have permission | 169 // country-specific google domain. Since we don't have permission |
| 192 // to inject on every page, an error will happen when the user is | 170 // to inject on every page, an error will happen when the user is |
| 193 // in an unsupported country. | 171 // in an unsupported country. |
| 194 // | 172 // |
| 195 // The property still needs to be accessed so that the error | 173 // The property still needs to be accessed so that the error |
| 196 // condition is cleared. If it isn't, exectureScript will log an | 174 // condition is cleared. If it isn't, exectureScript will log an |
| 197 // error the next time it is called. | 175 // error the next time it is called. |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 267 | 245 |
| 268 /** | 246 /** |
| 269 * Handles a content script attempting to connect. | 247 * Handles a content script attempting to connect. |
| 270 * @param {!Port} port Communications port from the client. | 248 * @param {!Port} port Communications port from the client. |
| 271 * @private | 249 * @private |
| 272 */ | 250 */ |
| 273 handleConnect_: function(port) { | 251 handleConnect_: function(port) { |
| 274 if (port.name != hotword.constants.CLIENT_PORT_NAME) | 252 if (port.name != hotword.constants.CLIENT_PORT_NAME) |
| 275 return; | 253 return; |
| 276 | 254 |
| 277 var tab = /** @type {!Tab} */(port.sender.tab); | 255 var tab = /** @type {!Tab} */ (port.sender.tab); |
| 278 // An existing port from the same tab might already exist. But that port | 256 // An existing port from the same tab might already exist. But that port |
| 279 // may be from the previous page, so just overwrite the port. | 257 // may be from the previous page, so just overwrite the port. |
| 280 this.portMap_[tab.id] = port; | 258 this.portMap_[tab.id] = port; |
| 281 port.onDisconnect.addListener(function() { | 259 port.onDisconnect.addListener(function() { |
| 282 this.handleClientDisconnect_(port); | 260 this.handleClientDisconnect_(port); |
| 283 }.bind(this)); | 261 }.bind(this)); |
| 284 port.onMessage.addListener(function(msg) { | 262 port.onMessage.addListener(function(msg) { |
| 285 this.handleMessage_(msg, port.sender, port.postMessage); | 263 this.handleMessage_(msg, port.sender, port.postMessage); |
| 286 }.bind(this)); | 264 }.bind(this)); |
| 287 }, | 265 }, |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 351 this.sendClient_(CommandToPage.HOTWORD_VOICE_TRIGGER, tab.id); | 329 this.sendClient_(CommandToPage.HOTWORD_VOICE_TRIGGER, tab.id); |
| 352 }); | 330 }); |
| 353 }, | 331 }, |
| 354 | 332 |
| 355 /** | 333 /** |
| 356 * Starts hotwording. | 334 * Starts hotwording. |
| 357 * @private | 335 * @private |
| 358 */ | 336 */ |
| 359 startHotwording_: function() { | 337 startHotwording_: function() { |
| 360 this.stateManager_.startSession( | 338 this.stateManager_.startSession( |
| 361 hotword.constants.SessionSource.NTP, | 339 hotword.constants.SessionSource.NTP, function() { |
| 362 function() { | |
| 363 this.sendAllClients_(CommandToPage.HOTWORD_STARTED); | 340 this.sendAllClients_(CommandToPage.HOTWORD_STARTED); |
| 364 }.bind(this), | 341 }.bind(this), this.hotwordTriggered_.bind(this)); |
| 365 this.hotwordTriggered_.bind(this)); | |
| 366 }, | 342 }, |
| 367 | 343 |
| 368 /** | 344 /** |
| 369 * Starts hotwording if the currently active tab is eligible for hotwording | 345 * Starts hotwording if the currently active tab is eligible for hotwording |
| 370 * (e.g. google.com). | 346 * (e.g. google.com). |
| 371 * @private | 347 * @private |
| 372 */ | 348 */ |
| 373 startHotwordingIfEligible_: function() { | 349 startHotwordingIfEligible_: function() { |
| 374 this.findCurrentTab_(function(tab) { | 350 this.findCurrentTab_(function(tab) { |
| 375 if (!tab) { | 351 if (!tab) { |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 437 * @return {boolean} Whether to maintain the port open to call sendResponse. | 413 * @return {boolean} Whether to maintain the port open to call sendResponse. |
| 438 * @private | 414 * @private |
| 439 */ | 415 */ |
| 440 handleMessageFromPage_: function(request, sender, sendResponse) { | 416 handleMessageFromPage_: function(request, sender, sendResponse) { |
| 441 switch (request.type) { | 417 switch (request.type) { |
| 442 case CommandFromPage.PAGE_WAKEUP: | 418 case CommandFromPage.PAGE_WAKEUP: |
| 443 if (sender.tab && this.isEligibleUrl_(sender.tab.url)) { | 419 if (sender.tab && this.isEligibleUrl_(sender.tab.url)) { |
| 444 chrome.hotwordPrivate.getStatus( | 420 chrome.hotwordPrivate.getStatus( |
| 445 true /* getOptionalFields */, | 421 true /* getOptionalFields */, |
| 446 this.statusDone_.bind( | 422 this.statusDone_.bind( |
| 447 this, | 423 this, request.tab || sender.tab || {incognito: true}, |
| 448 request.tab || sender.tab || {incognito: true}, | |
| 449 sendResponse)); | 424 sendResponse)); |
| 450 return true; | 425 return true; |
| 451 } | 426 } |
| 452 | 427 |
| 453 // Do not show the opt-in promo for ineligible urls. | 428 // Do not show the opt-in promo for ineligible urls. |
| 454 this.sendResponse_({'doNotShowOptinMessage': true}, sendResponse); | 429 this.sendResponse_({'doNotShowOptinMessage': true}, sendResponse); |
| 455 break; | 430 break; |
| 456 case CommandFromPage.CLICKED_OPTIN: | 431 case CommandFromPage.CLICKED_OPTIN: |
| 457 chrome.hotwordPrivate.setEnabled(true); | 432 chrome.hotwordPrivate.setEnabled(true); |
| 458 break; | 433 break; |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 520 chrome.runtime.onConnect.addListener(this.connectListener_); | 495 chrome.runtime.onConnect.addListener(this.connectListener_); |
| 521 chrome.tabs.onCreated.addListener(this.tabCreatedListener_); | 496 chrome.tabs.onCreated.addListener(this.tabCreatedListener_); |
| 522 chrome.tabs.onUpdated.addListener(this.tabUpdatedListener_); | 497 chrome.tabs.onUpdated.addListener(this.tabUpdatedListener_); |
| 523 chrome.tabs.onActivated.addListener(this.tabActivatedListener_); | 498 chrome.tabs.onActivated.addListener(this.tabActivatedListener_); |
| 524 chrome.windows.onFocusChanged.addListener( | 499 chrome.windows.onFocusChanged.addListener( |
| 525 this.windowFocusChangedListener_); | 500 this.windowFocusChangedListener_); |
| 526 chrome.hotwordPrivate.onMicrophoneStateChanged.addListener( | 501 chrome.hotwordPrivate.onMicrophoneStateChanged.addListener( |
| 527 this.microphoneStateChangedListener_); | 502 this.microphoneStateChangedListener_); |
| 528 if (chrome.runtime.onMessage.hasListener(this.messageListener_)) | 503 if (chrome.runtime.onMessage.hasListener(this.messageListener_)) |
| 529 return; | 504 return; |
| 530 chrome.runtime.onMessageExternal.addListener( | 505 chrome.runtime.onMessageExternal.addListener(this.messageListener_); |
| 531 this.messageListener_); | |
| 532 }, | 506 }, |
| 533 | 507 |
| 534 /** | 508 /** |
| 535 * Remove event listeners. | 509 * Remove event listeners. |
| 536 * @private | 510 * @private |
| 537 */ | 511 */ |
| 538 removeListeners_: function() { | 512 removeListeners_: function() { |
| 539 chrome.runtime.onConnect.removeListener(this.connectListener_); | 513 chrome.runtime.onConnect.removeListener(this.connectListener_); |
| 540 chrome.tabs.onCreated.removeListener(this.tabCreatedListener_); | 514 chrome.tabs.onCreated.removeListener(this.tabCreatedListener_); |
| 541 chrome.tabs.onUpdated.removeListener(this.tabUpdatedListener_); | 515 chrome.tabs.onUpdated.removeListener(this.tabUpdatedListener_); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 556 if (this.stateManager_.isSometimesOnEnabled()) { | 530 if (this.stateManager_.isSometimesOnEnabled()) { |
| 557 this.setupListeners_(); | 531 this.setupListeners_(); |
| 558 } else { | 532 } else { |
| 559 this.removeListeners_(); | 533 this.removeListeners_(); |
| 560 this.stopHotwording_(); | 534 this.stopHotwording_(); |
| 561 this.disconnectAllClients_(); | 535 this.disconnectAllClients_(); |
| 562 } | 536 } |
| 563 } | 537 } |
| 564 }; | 538 }; |
| 565 | 539 |
| 566 return { | 540 return {PageAudioManager: PageAudioManager}; |
| 567 PageAudioManager: PageAudioManager | |
| 568 }; | |
| 569 }); | 541 }); |
| OLD | NEW |