15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/speech/chrome_speech_recognition_manager_delegate.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/lock.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_restrictions.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/browser_process.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile_manager.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/tab_contents/tab_util.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_registrar.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_source.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_types.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_process_host.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_view_host.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/resource_context.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/speech_recognition_manager.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/speech_recognition_session_config.h" 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/speech_recognition_session_context.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/speech_recognition_error.h" 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/speech_recognition_result.h" 33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "extensions/browser/view_type_utils.h" 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context_getter.h" 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/wmi.h" 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::SpeechRecognitionManager; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebContents; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace speech { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Asynchronously fetches the PC and audio hardware/driver info if 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the user has opted into UMA. This information is sent with speech input 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// requests to the server for identifying and improving quality issues with 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// specific device configurations. 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ChromeSpeechRecognitionManagerDelegate::OptionalRequestInfo 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : public base::RefCountedThreadSafe<OptionalRequestInfo> { 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OptionalRequestInfo() : can_report_metrics_(false) { 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Refresh() { 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // UMA opt-in can be checked only from the UI thread, so switch to that. 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&OptionalRequestInfo::CheckUMAAndGetHardwareInfo, this)); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void CheckUMAAndGetHardwareInfo() { 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (g_browser_process->local_state()->GetBoolean( 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefs::kMetricsReportingEnabled)) { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Access potentially slow OS calls from the FILE thread. 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&OptionalRequestInfo::GetHardwareInfo, this)); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void GetHardwareInfo() { 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock lock(lock_); 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) can_report_metrics_ = true; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 device_model = 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpeechRecognitionManager::GetInstance()->GetAudioInputDeviceModel(); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_ = UTF16ToUTF8( 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) installer::WMIComputerSystem::GetModel() + L"|" + device_model); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else // defined(OS_WIN) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_ = UTF16ToUTF8(device_model); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // defined(OS_WIN) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string value() { 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock lock(lock_); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return value_; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool can_report_metrics() { 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock lock(lock_); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return can_report_metrics_; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) friend class base::RefCountedThreadSafe<OptionalRequestInfo>; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~OptionalRequestInfo() {} 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Lock lock_; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string value_; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool can_report_metrics_; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(OptionalRequestInfo); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Simple utility to get notified when a WebContent (a tab or an extension's 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// background page) is closed or crashes. Both the callback site and the 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// callback thread are passed by the caller in the constructor. 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// There is no restriction on the constructor, however this class must be 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// destroyed on the UI thread, due to the NotificationRegistrar dependency. 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ChromeSpeechRecognitionManagerDelegate::TabWatcher 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : public base::RefCountedThreadSafe<TabWatcher>, 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public content::NotificationObserver { 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef base::Callback<void(int render_process_id, int render_view_id)> 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabClosedCallback; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabWatcher(TabClosedCallback tab_closed_callback, 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::ID callback_thread) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : tab_closed_callback_(tab_closed_callback), 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_thread_(callback_thread) { 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Starts monitoring the WebContents corresponding to the given 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |render_process_id|, |render_view_id| pair, invoking |tab_closed_callback_| 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // if closed/unloaded. 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Watch(int render_process_id, int render_view_id) { 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &TabWatcher::Watch, this, render_process_id, render_view_id)); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebContents* web_contents = tab_util::GetWebContentsByID(render_process_id, 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) render_view_id); 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sessions initiated by speech input extension APIs will end up in a NULL 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // WebContent here, but they are properly managed by the 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // chrome::SpeechInputExtensionManager. However, sessions initiated within a 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // extension using the (new) speech JS APIs, will be properly handled here. 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(primiano) turn this line into a DCHECK once speech input extension 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // API is deprecated. 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!web_contents) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Avoid multiple registrations on |registrar_| for the same |web_contents|. 149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (FindWebContents(web_contents) != registered_web_contents_.end()) { 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) registered_web_contents_.push_back( 153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) WebContentsInfo(web_contents, render_process_id, render_view_id)); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Lazy initialize the registrar. 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!registrar_.get()) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) registrar_.reset(new content::NotificationRegistrar()); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) registrar_->Add(this, 160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::NOTIFICATION_WEB_CONTENTS_SWAPPED, 161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::Source<WebContents>(web_contents)); 162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) registrar_->Add(this, 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Source<WebContents>(web_contents)); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // content::NotificationObserver implementation. 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void Observe(int type, 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::NotificationSource& source, 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::NotificationDetails& details) OVERRIDE { 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(type == content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED || 173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) type == content::NOTIFICATION_WEB_CONTENTS_SWAPPED); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebContents* web_contents = content::Source<WebContents>(source).ptr(); 176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<WebContentsInfo>::iterator iter = FindWebContents(web_contents); 177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(iter != registered_web_contents_.end()); 178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int render_process_id = iter->render_process_id; 179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int render_view_id = iter->render_view_id; 180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) registered_web_contents_.erase(iter); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) registrar_->Remove(this, 183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::NOTIFICATION_WEB_CONTENTS_SWAPPED, 184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::Source<WebContents>(web_contents)); 185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) registrar_->Remove(this, 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Source<WebContents>(web_contents)); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask(callback_thread_, FROM_HERE, base::Bind( 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_closed_callback_, render_process_id, render_view_id)); 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) struct WebContentsInfo { 195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) WebContentsInfo(content::WebContents* web_contents, 196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int render_process_id, 197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int render_view_id) 198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : web_contents(web_contents), 199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) render_process_id(render_process_id), 200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) render_view_id(render_view_id) {} 201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ~WebContentsInfo() {} 203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::WebContents* web_contents; 205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int render_process_id; 206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int render_view_id; 207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) }; 208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) friend class base::RefCountedThreadSafe<TabWatcher>; 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~TabWatcher() { 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Must be destroyed on the UI thread due to |registrar_| non thread-safety. 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Helper function to find the iterator in |registered_web_contents_| which 217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // contains |web_contents|. 218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<WebContentsInfo>::iterator FindWebContents( 219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::WebContents* web_contents) { 220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (std::vector<WebContentsInfo>::iterator i( 221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) registered_web_contents_.begin()); 222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) i != registered_web_contents_.end(); ++i) { 223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (i->web_contents == web_contents) 224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return i; 225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return registered_web_contents_.end(); 228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Lazy-initialized and used on the UI thread to handle web contents 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // notifications (tab closing). 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<content::NotificationRegistrar> registrar_; 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Keeps track of which WebContent(s) have been registered, in order to avoid 235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // double registrations on |registrar_| and to pass the correct render 236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // process id and render view id to |tab_closed_callback_| after the process 237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // has gone away. 238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<WebContentsInfo> registered_web_contents_; 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Callback used to notify, on the thread specified by |callback_thread_| the 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // closure of a registered tab. 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabClosedCallback tab_closed_callback_; 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::BrowserThread::ID callback_thread_; 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(TabWatcher); 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ChromeSpeechRecognitionManagerDelegate 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)::ChromeSpeechRecognitionManagerDelegate() { 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ChromeSpeechRecognitionManagerDelegate 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)::~ChromeSpeechRecognitionManagerDelegate() { 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ChromeSpeechRecognitionManagerDelegate::TabClosedCallback( 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int render_process_id, int render_view_id) { 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpeechRecognitionManager* manager = SpeechRecognitionManager::GetInstance(); 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |manager| becomes NULL if a browser shutdown happens between the post of 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // this task (from the UI thread) and this call (on the IO thread). In this 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // case we just return. 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!manager) 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) manager->AbortAllSessionsForRenderView(render_process_id, render_view_id); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ChromeSpeechRecognitionManagerDelegate::OnRecognitionStart( 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int session_id) { 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::SpeechRecognitionSessionContext& context = 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Register callback to auto abort session on tab closure. 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |tab_watcher_| is lazyly istantiated on the first call. 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!tab_watcher_.get()) { 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_watcher_ = new TabWatcher( 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&ChromeSpeechRecognitionManagerDelegate::TabClosedCallback, 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this)), 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::IO); 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_watcher_->Watch(context.render_process_id, context.render_view_id); 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ChromeSpeechRecognitionManagerDelegate::OnAudioStart(int session_id) { 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ChromeSpeechRecognitionManagerDelegate::OnEnvironmentEstimationComplete( 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int session_id) { 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ChromeSpeechRecognitionManagerDelegate::OnSoundStart(int session_id) { 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ChromeSpeechRecognitionManagerDelegate::OnSoundEnd(int session_id) { 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ChromeSpeechRecognitionManagerDelegate::OnAudioEnd(int session_id) { 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChromeSpeechRecognitionManagerDelegate::OnRecognitionResults( 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int session_id, const content::SpeechRecognitionResults& result) { 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ChromeSpeechRecognitionManagerDelegate::OnRecognitionError( 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int session_id, const content::SpeechRecognitionError& error) { 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ChromeSpeechRecognitionManagerDelegate::OnAudioLevelsChange( 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int session_id, float volume, float noise_volume) { 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ChromeSpeechRecognitionManagerDelegate::OnRecognitionEnd(int session_id) { 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ChromeSpeechRecognitionManagerDelegate::GetDiagnosticInformation( 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* can_report_metrics, 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* hardware_info) { 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!optional_request_info_.get()) { 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) optional_request_info_ = new OptionalRequestInfo(); 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Since hardware info is optional with speech input requests, we start an 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // asynchronous fetch here and move on with recording audio. This first 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // speech input request would send an empty string for hardware info and 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // subsequent requests may have the hardware info available if the fetch 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // completed before them. This way we don't end up stalling the user with 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a long wait and disk seeks when they click on a UI element and start 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // speaking. 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) optional_request_info_->Refresh(); 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *can_report_metrics = optional_request_info_->can_report_metrics(); 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *hardware_info = optional_request_info_->value(); 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ChromeSpeechRecognitionManagerDelegate::CheckRecognitionIsAllowed( 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int session_id, 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Callback<void(bool ask_user, bool is_allowed)> callback) { 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::SpeechRecognitionSessionContext& context = 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make sure that initiators (extensions/web pages) properly set the 3457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // |render_process_id| field, which is needed later to retrieve the profile. 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(context.render_process_id, 0); 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check that the render view type is appropriate, and whether or not we 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // need to request permission from the user. 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&CheckRenderViewType, 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback, 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context.render_process_id, 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) context.render_view_id, 3557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch !context.requested_by_page_element)); 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)content::SpeechRecognitionEventListener* 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ChromeSpeechRecognitionManagerDelegate::GetEventListener() { 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return this; 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool ChromeSpeechRecognitionManagerDelegate::FilterProfanities( 3647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch int render_process_id) { 3657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch content::RenderProcessHost* rph = 3667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch content::RenderProcessHost::FromID(render_process_id); 3677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (!rph) // Guard against race conditions on RPH lifetime. 3687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return true; 3697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 3707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return Profile::FromBrowserContext(rph->GetBrowserContext())->GetPrefs()-> 3717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch GetBoolean(prefs::kSpeechRecognitionFilterProfanities); 3727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch} 3737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ChromeSpeechRecognitionManagerDelegate::CheckRenderViewType( 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Callback<void(bool ask_user, bool is_allowed)> callback, 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int render_process_id, 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int render_view_id, 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool js_api) { 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::RenderViewHost* render_view_host = 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::RenderViewHost::FromID(render_process_id, render_view_id); 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool allowed = false; 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ask_permission = false; 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!render_view_host) { 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!js_api) { 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If there is no render view, we cannot show the speech bubble, so this 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is not allowed. 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allowed = false; 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ask_permission = false; 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This happens for extensions. Manifest should be checked for permission. 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allowed = true; 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ask_permission = false; 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(callback, ask_permission, allowed)); 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebContents* web_contents = WebContents::FromRenderViewHost(render_view_host); 403c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) extensions::ViewType view_type = extensions::GetViewType(web_contents); 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(kalman): Also enable speech bubble for extension popups 4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // (VIEW_TYPE_EXTENSION_POPUP) once popup-like control UI works properly in 4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // extensions: http://crbug.com/163851. 4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Right now the extension popup closes and dismisses immediately on user 4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // click. 410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (view_type == extensions::VIEW_TYPE_TAB_CONTENTS || 41190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) view_type == extensions::VIEW_TYPE_APP_SHELL || 41290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) view_type == extensions::VIEW_TYPE_VIRTUAL_KEYBOARD) { 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If it is a tab, we can show the speech input bubble or ask for 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // permission. 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allowed = true; 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (js_api) 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ask_permission = true; 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(callback, ask_permission, allowed)); 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace speech 426