| Index: chrome/browser/autocomplete/keyword_provider.cc | 
| diff --git a/chrome/browser/autocomplete/keyword_provider.cc b/chrome/browser/autocomplete/keyword_provider.cc | 
| index 756818c865b86d51a0974ade5019bb8fbf1889fc..1e68de52265ea79814c653d01aa2d15dace04e99 100644 | 
| --- a/chrome/browser/autocomplete/keyword_provider.cc | 
| +++ b/chrome/browser/autocomplete/keyword_provider.cc | 
| @@ -20,6 +20,24 @@ | 
| #include "net/base/escape.h" | 
| #include "net/base/net_util.h" | 
|  | 
| +// Helper functor for Start(), for ending keyword mode unless explicitly told | 
| +// otherwise. | 
| +class KeywordProvider::ScopedEndExtensionKeywordMode { | 
| + public: | 
| +  ScopedEndExtensionKeywordMode(KeywordProvider* provider) | 
| +      : provider_(provider) { } | 
| +  ~ScopedEndExtensionKeywordMode() { | 
| +    if (provider_) | 
| +      provider_->MaybeEndExtensionKeywordMode(); | 
| +  } | 
| + | 
| +  void StayInKeywordMode() { | 
| +    provider_ = NULL; | 
| +  } | 
| + private: | 
| +  KeywordProvider* provider_; | 
| +}; | 
| + | 
| // static | 
| std::wstring KeywordProvider::SplitReplacementStringFromInput( | 
| const std::wstring& input) { | 
| @@ -42,6 +60,8 @@ KeywordProvider::KeywordProvider(ACProviderListener* listener, Profile* profile) | 
| // suggestions are meant for us. | 
| registrar_.Add(this, NotificationType::EXTENSION_OMNIBOX_SUGGESTIONS_READY, | 
| Source<Profile>(profile->GetOriginalProfile())); | 
| +  registrar_.Add(this, NotificationType::EXTENSION_OMNIBOX_INPUT_ENTERED, | 
| +                 Source<Profile>(profile)); | 
| } | 
|  | 
| KeywordProvider::KeywordProvider(ACProviderListener* listener, | 
| @@ -97,6 +117,10 @@ const TemplateURL* KeywordProvider::GetSubstitutingTemplateURLForInput( | 
|  | 
| void KeywordProvider::Start(const AutocompleteInput& input, | 
| bool minimal_changes) { | 
| +  // This object ensures we end keyword mode if we exit the function without | 
| +  // toggling keyword mode to on. | 
| +  ScopedEndExtensionKeywordMode keyword_mode_toggle(this); | 
| + | 
| matches_.clear(); | 
|  | 
| if (!minimal_changes) { | 
| @@ -165,6 +189,12 @@ void KeywordProvider::Start(const AutocompleteInput& input, | 
| if (!enabled) | 
| return; | 
|  | 
| +      if (extension->id() != current_keyword_extension_id_) | 
| +        MaybeEndExtensionKeywordMode(); | 
| +      if (current_keyword_extension_id_.empty()) | 
| +        EnterExtensionKeywordMode(extension->id()); | 
| +      keyword_mode_toggle.StayInKeywordMode(); | 
| + | 
| if (minimal_changes) { | 
| // If the input hasn't significantly changed, we can just use the | 
| // suggestions from last time. We need to readjust the relevance to | 
| @@ -205,6 +235,11 @@ void KeywordProvider::Start(const AutocompleteInput& input, | 
| } | 
| } | 
|  | 
| +void KeywordProvider::Stop() { | 
| +  done_ = true; | 
| +  MaybeEndExtensionKeywordMode(); | 
| +} | 
| + | 
| // static | 
| bool KeywordProvider::ExtractKeywordFromInput(const AutocompleteInput& input, | 
| std::wstring* keyword, | 
| @@ -365,6 +400,13 @@ AutocompleteMatch KeywordProvider::CreateAutocompleteMatch( | 
| void KeywordProvider::Observe(NotificationType type, | 
| const NotificationSource& source, | 
| const NotificationDetails& details) { | 
| +  if (type == NotificationType::EXTENSION_OMNIBOX_INPUT_ENTERED) { | 
| +    // Input has been accepted, so we're done with this input session. Ensure | 
| +    // we don't send the OnInputCancelled event. | 
| +    current_keyword_extension_id_.clear(); | 
| +    return; | 
| +  } | 
| + | 
| // TODO(mpcomplete): consider clamping the number of suggestions to | 
| // AutocompleteProvider::kMaxMatches. | 
| DCHECK(type == NotificationType::EXTENSION_OMNIBOX_SUGGESTIONS_READY); | 
| @@ -409,3 +451,21 @@ void KeywordProvider::Observe(NotificationType type, | 
| extension_suggest_matches_.end()); | 
| listener_->OnProviderUpdate(!extension_suggest_matches_.empty()); | 
| } | 
| + | 
| +void KeywordProvider::EnterExtensionKeywordMode( | 
| +    const std::string& extension_id) { | 
| +  DCHECK(current_keyword_extension_id_.empty()); | 
| +  current_keyword_extension_id_ = extension_id; | 
| + | 
| +  ExtensionOmniboxEventRouter::OnInputStarted( | 
| +      profile_, current_keyword_extension_id_); | 
| +} | 
| + | 
| +void KeywordProvider::MaybeEndExtensionKeywordMode() { | 
| +  if (!current_keyword_extension_id_.empty()) { | 
| +    ExtensionOmniboxEventRouter::OnInputCancelled( | 
| +        profile_, current_keyword_extension_id_); | 
| + | 
| +    current_keyword_extension_id_.clear(); | 
| +  } | 
| +} | 
|  |