| 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 18 matching lines...) Expand all Loading... |
| 29 | 29 |
| 30 /** | 30 /** |
| 31 * Chrome event listeners. Saved so that they can be de-registered when | 31 * Chrome event listeners. Saved so that they can be de-registered when |
| 32 * hotwording is disabled. | 32 * hotwording is disabled. |
| 33 */ | 33 */ |
| 34 this.connectListener_ = this.handleConnect_.bind(this); | 34 this.connectListener_ = this.handleConnect_.bind(this); |
| 35 this.tabCreatedListener_ = this.handleCreatedTab_.bind(this); | 35 this.tabCreatedListener_ = this.handleCreatedTab_.bind(this); |
| 36 this.tabUpdatedListener_ = this.handleUpdatedTab_.bind(this); | 36 this.tabUpdatedListener_ = this.handleUpdatedTab_.bind(this); |
| 37 this.tabActivatedListener_ = this.handleActivatedTab_.bind(this); | 37 this.tabActivatedListener_ = this.handleActivatedTab_.bind(this); |
| 38 this.windowFocusChangedListener_ = this.handleChangedWindow_.bind(this); | 38 this.windowFocusChangedListener_ = this.handleChangedWindow_.bind(this); |
| 39 this.messageListener_ = this.handleMessageFromPage_.bind(this); |
| 39 | 40 |
| 40 // Need to setup listeners on startup, otherwise events that caused the | 41 // Need to setup listeners on startup, otherwise events that caused the |
| 41 // event page to start up, will be lost. | 42 // event page to start up, will be lost. |
| 42 this.setupListeners_(); | 43 this.setupListeners_(); |
| 43 | 44 |
| 44 this.stateManager_.onStatusChanged.addListener(function() { | 45 this.stateManager_.onStatusChanged.addListener(function() { |
| 45 this.updateListeners_(); | 46 this.updateListeners_(); |
| 47 this.updateTabState_(); |
| 46 }.bind(this)); | 48 }.bind(this)); |
| 47 }; | 49 }; |
| 48 | 50 |
| 49 var CommandToPage = hotword.constants.CommandToPage; | 51 var CommandToPage = hotword.constants.CommandToPage; |
| 50 var CommandFromPage = hotword.constants.CommandFromPage; | 52 var CommandFromPage = hotword.constants.CommandFromPage; |
| 51 | 53 |
| 52 PageAudioManager.prototype = { | 54 PageAudioManager.prototype = { |
| 53 /** | 55 /** |
| 54 * Helper function to test if a URL path is eligible for hotwording. | 56 * Helper function to test if a URL path is eligible for hotwording. |
| 55 * @param {!string} url URL to check. | 57 * @param {!string} url URL to check. |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 220 handleUpdatedTab_: function(tabId, info, tab) { | 222 handleUpdatedTab_: function(tabId, info, tab) { |
| 221 // Chrome fires multiple update events: undefined, loading and completed. | 223 // Chrome fires multiple update events: undefined, loading and completed. |
| 222 // We perform content injection on loading state. | 224 // We perform content injection on loading state. |
| 223 if (info['status'] != 'loading') | 225 if (info['status'] != 'loading') |
| 224 return; | 226 return; |
| 225 | 227 |
| 226 this.prepareTab_(tab); | 228 this.prepareTab_(tab); |
| 227 }, | 229 }, |
| 228 | 230 |
| 229 /** | 231 /** |
| 230 * Handles a tab that was just became active. | 232 * Handles a tab that has just become active. |
| 231 * @param {{tabId: number}} info Information about the activated tab. | 233 * @param {{tabId: number}} info Information about the activated tab. |
| 232 * @private | 234 * @private |
| 233 */ | 235 */ |
| 234 handleActivatedTab_: function(info) { | 236 handleActivatedTab_: function(info) { |
| 235 this.updateTabState_(); | 237 this.updateTabState_(); |
| 236 }, | 238 }, |
| 237 | 239 |
| 238 | 240 |
| 239 /** | 241 /** |
| 240 * Handles a change in Chrome windows. | 242 * Handles a change in Chrome windows. |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 this.stateManager_.startSession( | 343 this.stateManager_.startSession( |
| 342 hotword.constants.SessionSource.NTP, | 344 hotword.constants.SessionSource.NTP, |
| 343 function() { | 345 function() { |
| 344 this.sendAllClients_(CommandToPage.HOTWORD_STARTED); | 346 this.sendAllClients_(CommandToPage.HOTWORD_STARTED); |
| 345 }.bind(this), | 347 }.bind(this), |
| 346 this.hotwordTriggered_.bind(this)); | 348 this.hotwordTriggered_.bind(this)); |
| 347 }, | 349 }, |
| 348 | 350 |
| 349 /** | 351 /** |
| 350 * Starts hotwording if the currently active tab is eligible for hotwording | 352 * Starts hotwording if the currently active tab is eligible for hotwording |
| 351 * (i.e. google.com). | 353 * (e.g. google.com). |
| 352 * @private | 354 * @private |
| 353 */ | 355 */ |
| 354 startHotwordingIfEligible_: function() { | 356 startHotwordingIfEligible_: function() { |
| 355 this.findCurrentTab_(function(tab) { | 357 this.findCurrentTab_(function(tab) { |
| 356 if (!tab) { | 358 if (!tab) { |
| 357 this.stopHotwording_(); | 359 this.stopHotwording_(); |
| 358 return; | 360 return; |
| 359 } | 361 } |
| 360 if (this.isEligibleUrl_(tab.url)) | 362 if (this.isEligibleUrl_(tab.url)) |
| 361 this.startHotwording_(); | 363 this.startHotwording_(); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 401 case CommandFromPage.SPEECH_START: | 403 case CommandFromPage.SPEECH_START: |
| 402 this.stopHotwording_(); | 404 this.stopHotwording_(); |
| 403 break; | 405 break; |
| 404 case CommandFromPage.SPEECH_END: | 406 case CommandFromPage.SPEECH_END: |
| 405 case CommandFromPage.SPEECH_RESET: | 407 case CommandFromPage.SPEECH_RESET: |
| 406 this.startHotwording_(); | 408 this.startHotwording_(); |
| 407 break; | 409 break; |
| 408 } | 410 } |
| 409 }, | 411 }, |
| 410 | 412 |
| 413 |
| 414 /** |
| 415 * Handles a message directly from the NTP/HP/SERP. |
| 416 * @param {!Object} request Message from the sender. |
| 417 * @param {!MessageSender} sender Information about the sender. |
| 418 * @param {!function(HotwordStatus)} sendResponse Callback to respond |
| 419 * to sender. |
| 420 * @return {boolean} Whether to maintain the port open to call sendResponse. |
| 421 * @private |
| 422 */ |
| 423 handleMessageFromPage_: function(request, sender, sendResponse) { |
| 424 switch (request.type) { |
| 425 case CommandFromPage.PAGE_WAKEUP: |
| 426 if (sender.tab && this.isEligibleUrl_(sender.tab.url)) { |
| 427 chrome.hotwordPrivate.getStatus( |
| 428 this.statusDone_.bind( |
| 429 this, |
| 430 request.tab || sender.tab || {incognito: true}, |
| 431 sendResponse)); |
| 432 return true; |
| 433 } |
| 434 break; |
| 435 case CommandFromPage.CLICKED_OPTIN: |
| 436 chrome.hotwordPrivate.setEnabled(true); |
| 437 break; |
| 438 // User has explicitly clicked 'no thanks'. |
| 439 case CommandFromPage.CLICKED_NO_OPTIN: |
| 440 chrome.hotwordPrivate.setEnabled(false); |
| 441 break; |
| 442 } |
| 443 return false; |
| 444 }, |
| 445 |
| 446 /** |
| 447 * Sends the response to the tab. |
| 448 * @param {Tab} tab The tab that the request was sent from. |
| 449 * @param {function(HotwordStatus)} sendResponse Callback function to |
| 450 * respond to sender. |
| 451 * @param {HotwordStatus} hotwordStatus Status of the hotword extension. |
| 452 * @private |
| 453 */ |
| 454 statusDone_: function(tab, sendResponse, hotwordStatus) { |
| 455 var response = {'doNotShowOptinMessage': true}; |
| 456 |
| 457 if (!tab.incognito && hotwordStatus.available && |
| 458 !hotwordStatus.enabledSet) { |
| 459 response = hotwordStatus; |
| 460 } |
| 461 |
| 462 try { |
| 463 sendResponse(response); |
| 464 } catch (err) { |
| 465 // Suppress the exception thrown by sendResponse() when the page doesn't |
| 466 // specify a response callback in the call to |
| 467 // chrome.runtime.sendMessage(). |
| 468 // Unfortunately, there doesn't appear to be a way to detect one-way |
| 469 // messages without explicitly saying in the message itself. This |
| 470 // message is defined as a constant in |
| 471 // extensions/renderer/messaging_bindings.cc |
| 472 if (err.message == 'Attempting to use a disconnected port object') |
| 473 return; |
| 474 throw err; |
| 475 } |
| 476 }, |
| 477 |
| 411 /** | 478 /** |
| 412 * Set up event listeners. | 479 * Set up event listeners. |
| 413 * @private | 480 * @private |
| 414 */ | 481 */ |
| 415 setupListeners_: function() { | 482 setupListeners_: function() { |
| 416 if (chrome.runtime.onConnect.hasListener(this.connectListener_)) | 483 if (chrome.runtime.onConnect.hasListener(this.connectListener_)) |
| 417 return; | 484 return; |
| 418 | 485 |
| 419 chrome.runtime.onConnect.addListener(this.connectListener_); | 486 chrome.runtime.onConnect.addListener(this.connectListener_); |
| 420 chrome.tabs.onCreated.addListener(this.tabCreatedListener_); | 487 chrome.tabs.onCreated.addListener(this.tabCreatedListener_); |
| 421 chrome.tabs.onUpdated.addListener(this.tabUpdatedListener_); | 488 chrome.tabs.onUpdated.addListener(this.tabUpdatedListener_); |
| 422 chrome.tabs.onActivated.addListener(this.tabActivatedListener_); | 489 chrome.tabs.onActivated.addListener(this.tabActivatedListener_); |
| 423 chrome.windows.onFocusChanged.addListener( | 490 chrome.windows.onFocusChanged.addListener( |
| 424 this.windowFocusChangedListener_); | 491 this.windowFocusChangedListener_); |
| 492 if (chrome.runtime.onMessage.hasListener(this.messageListener_)) |
| 493 return; |
| 494 chrome.runtime.onMessageExternal.addListener( |
| 495 this.messageListener_); |
| 425 }, | 496 }, |
| 426 | 497 |
| 427 /** | 498 /** |
| 428 * Remove event listeners. | 499 * Remove event listeners. |
| 429 * @private | 500 * @private |
| 430 */ | 501 */ |
| 431 removeListeners_: function() { | 502 removeListeners_: function() { |
| 432 chrome.runtime.onConnect.removeListener(this.connectListener_); | 503 chrome.runtime.onConnect.removeListener(this.connectListener_); |
| 433 chrome.tabs.onCreated.removeListener(this.tabCreatedListener_); | 504 chrome.tabs.onCreated.removeListener(this.tabCreatedListener_); |
| 434 chrome.tabs.onUpdated.removeListener(this.tabUpdatedListener_); | 505 chrome.tabs.onUpdated.removeListener(this.tabUpdatedListener_); |
| 435 chrome.tabs.onActivated.removeListener(this.tabActivatedListener_); | 506 chrome.tabs.onActivated.removeListener(this.tabActivatedListener_); |
| 436 chrome.windows.onFocusChanged.removeListener( | 507 chrome.windows.onFocusChanged.removeListener( |
| 437 this.windowFocusChangedListener_); | 508 this.windowFocusChangedListener_); |
| 509 // Don't remove the Message listener, as we want them listening all |
| 510 // the time, |
| 438 }, | 511 }, |
| 439 | 512 |
| 440 /** | 513 /** |
| 441 * Update event listeners based on the current hotwording state. | 514 * Update event listeners based on the current hotwording state. |
| 442 * @private | 515 * @private |
| 443 */ | 516 */ |
| 444 updateListeners_: function() { | 517 updateListeners_: function() { |
| 445 if (this.stateManager_.isSometimesOnEnabled()) { | 518 if (this.stateManager_.isSometimesOnEnabled()) { |
| 446 this.setupListeners_(); | 519 this.setupListeners_(); |
| 447 } else { | 520 } else { |
| 448 this.removeListeners_(); | 521 this.removeListeners_(); |
| 449 this.stopHotwording_(); | 522 this.stopHotwording_(); |
| 450 this.disconnectAllClients_(); | 523 this.disconnectAllClients_(); |
| 451 } | 524 } |
| 452 } | 525 } |
| 453 }; | 526 }; |
| 454 | 527 |
| 455 return { | 528 return { |
| 456 PageAudioManager: PageAudioManager | 529 PageAudioManager: PageAudioManager |
| 457 }; | 530 }; |
| 458 }); | 531 }); |
| OLD | NEW |