Index: chrome/browser/speech/speech_input_bubble_controller.cc |
diff --git a/chrome/browser/speech/speech_input_bubble_controller.cc b/chrome/browser/speech/speech_input_bubble_controller.cc |
index 682d0283d27bc4ebbea220175f1e754ccecbb4c0..b048589f04ffa813023bba9602c4c8c1e03e133c 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; |