diff options
Diffstat (limited to 'chrome/browser/speech/speech_input_bubble_controller.cc')
-rw-r--r-- | chrome/browser/speech/speech_input_bubble_controller.cc | 63 |
1 files changed, 62 insertions, 1 deletions
diff --git a/chrome/browser/speech/speech_input_bubble_controller.cc b/chrome/browser/speech/speech_input_bubble_controller.cc index 682d028..b048589 100644 --- a/chrome/browser/speech/speech_input_bubble_controller.cc +++ b/chrome/browser/speech/speech_input_bubble_controller.cc @@ -7,13 +7,17 @@ #include "chrome/browser/browser_thread.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/tab_contents/tab_util.h" +#include "chrome/common/notification_registrar.h" +#include "chrome/common/notification_source.h" +#include "chrome/common/notification_type.h" #include "gfx/rect.h" namespace speech_input { SpeechInputBubbleController::SpeechInputBubbleController(Delegate* delegate) : delegate_(delegate), - current_bubble_caller_id_(0) { + current_bubble_caller_id_(0), + registrar_(new NotificationRegistrar) { } SpeechInputBubbleController::~SpeechInputBubbleController() { @@ -43,6 +47,8 @@ void SpeechInputBubbleController::CreateBubble(int caller_id, return; bubbles_[caller_id] = bubble; + + UpdateTabContentsSubscription(caller_id, BUBBLE_ADDED); } void SpeechInputBubbleController::CloseBubble(int caller_id) { @@ -70,6 +76,60 @@ void SpeechInputBubbleController::SetBubbleMessage(int caller_id, ProcessRequestInUiThread(caller_id, REQUEST_SET_MESSAGE, text, 0); } +void SpeechInputBubbleController::UpdateTabContentsSubscription( + int caller_id, ManageSubscriptionAction action) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + // If there are any other bubbles existing for the same TabContents, we would + // have subscribed to tab close notifications on their behalf and we need to + // stay registered. So we don't change the subscription in such cases. + TabContents* tab_contents = bubbles_[caller_id]->tab_contents(); + for (BubbleCallerIdMap::iterator iter = bubbles_.begin(); + iter != bubbles_.end(); ++iter) { + if (iter->second->tab_contents() == tab_contents && + iter->first != caller_id) { + // At least one other bubble exists for the same TabContents. So don't + // make any change to the subscription. + return; + } + } + + if (action == BUBBLE_ADDED) { + registrar_->Add(this, NotificationType::TAB_CONTENTS_DESTROYED, + Source<TabContents>(tab_contents)); + } else { + registrar_->Remove(this, NotificationType::TAB_CONTENTS_DESTROYED, + Source<TabContents>(tab_contents)); + } +} + +void SpeechInputBubbleController::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (type == NotificationType::TAB_CONTENTS_DESTROYED) { + // Cancel all bubbles and active recognition sessions for this tab. + TabContents* tab_contents = Source<TabContents>(source).ptr(); + BubbleCallerIdMap::iterator iter = bubbles_.begin(); + while (iter != bubbles_.end()) { + if (iter->second->tab_contents() == tab_contents) { + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + NewRunnableMethod( + this, + &SpeechInputBubbleController::InvokeDelegateButtonClicked, + iter->first, SpeechInputBubble::BUTTON_CANCEL)); + CloseBubble(iter->first); + // We expect to have a very small number of items in this map so + // redo-ing from start is ok. + iter = bubbles_.begin(); + } else { + ++iter; + } + } + } else { + NOTREACHED() << "Unknown notification"; + } +} + void SpeechInputBubbleController::ProcessRequestInUiThread( int caller_id, RequestType type, const string16& text, float volume) { if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { @@ -109,6 +169,7 @@ void SpeechInputBubbleController::ProcessRequestInUiThread( case REQUEST_CLOSE: if (current_bubble_caller_id_ == caller_id) current_bubble_caller_id_ = 0; + UpdateTabContentsSubscription(caller_id, BUBBLE_REMOVED); delete bubble; bubbles_.erase(caller_id); break; |