Chromium Code Reviews| 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..f17342c5813648a8daf19315c80d6e203a767561 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,16 @@ void SpeechInputBubbleController::CreateBubble(int caller_id, |
| return; |
| bubbles_[caller_id] = bubble; |
| + |
| + // If this is the first bubble in our list for this TabContents, register |
|
hans
2011/01/06 12:30:54
"First in our list", but the call is to IsOnlyBubb
|
| + // for notifications when the tab closes. This ensures that we can safely |
| + // kill the bubble and recording session even if the user clicked on the |
| + // speech button and immediately closes the tab, or if the tab crashes in |
|
bulach
2011/01/06 12:32:39
s/in the somewhere/
|
| + // the somewhere while the bubble & recording are active. |
|
hans
2011/01/06 12:30:54
nit: "crashes in the somewhere" sounds weird
|
| + if (IsOnlyBubbleForTab(caller_id)) { |
|
bulach
2011/01/06 12:32:39
as we chatted, the "IsOnlyBubbleForTab" is the bes
|
| + registrar_->Add(this, NotificationType::TAB_CONTENTS_DESTROYED, |
| + Source<TabContents>(tab_contents)); |
| + } |
| } |
| void SpeechInputBubbleController::CloseBubble(int caller_id) { |
| @@ -70,6 +84,47 @@ void SpeechInputBubbleController::SetBubbleMessage(int caller_id, |
| ProcessRequestInUiThread(caller_id, REQUEST_SET_MESSAGE, text, 0); |
| } |
| +bool SpeechInputBubbleController::IsOnlyBubbleForTab(int caller_id) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + 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. |
|
bulach
2011/01/06 12:32:39
yeah, as above, this would be the best place to sa
|
| + return false; |
| + } |
| + } |
| + return true; |
| +} |
| + |
| +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 +164,12 @@ void SpeechInputBubbleController::ProcessRequestInUiThread( |
| case REQUEST_CLOSE: |
| if (current_bubble_caller_id_ == caller_id) |
| current_bubble_caller_id_ = 0; |
| + // If this is the last bubble for this TabContents, unregister from |
| + // close notifications. |
| + if (IsOnlyBubbleForTab(caller_id)) { |
| + registrar_->Remove(this, NotificationType::TAB_CONTENTS_DESTROYED, |
| + Source<TabContents>(bubble->tab_contents())); |
| + } |
| delete bubble; |
| bubbles_.erase(caller_id); |
| break; |