search_controller.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/ui/app_list/search/search_controller.h" 6 7#include <algorithm> 8#include <vector> 9 10#include "base/bind.h" 11#include "base/command_line.h" 12#include "base/memory/scoped_ptr.h" 13#include "base/metrics/histogram.h" 14#include "base/strings/string_util.h" 15#include "base/strings/utf_string_conversions.h" 16#include "chrome/browser/profiles/profile.h" 17#include "chrome/browser/ui/app_list/search/app_search_provider.h" 18#include "chrome/browser/ui/app_list/search/chrome_search_result.h" 19#include "chrome/browser/ui/app_list/search/history.h" 20#include "chrome/browser/ui/app_list/search/history_factory.h" 21#include "chrome/browser/ui/app_list/search/omnibox_provider.h" 22#include "chrome/browser/ui/app_list/search/people/people_provider.h" 23#include "chrome/browser/ui/app_list/search/search_provider.h" 24#include "chrome/browser/ui/app_list/search/webstore/webstore_provider.h" 25#include "chrome/browser/ui/app_list/start_page_service.h" 26#include "chrome/common/chrome_switches.h" 27#include "content/public/browser/user_metrics.h" 28#include "grit/generated_resources.h" 29#include "grit/theme_resources.h" 30#include "ui/app_list/search_box_model.h" 31#include "ui/app_list/speech_ui_model.h" 32#include "ui/base/l10n/l10n_util.h" 33#include "ui/base/resource/resource_bundle.h" 34 35namespace { 36 const char kAppListSearchResultOpenTypeHistogram[] = 37 "Apps.AppListSearchResultOpenType"; 38} 39 40namespace app_list { 41 42SearchController::SearchController(Profile* profile, 43 SearchBoxModel* search_box, 44 AppListModel::SearchResults* results, 45 SpeechUIModel* speech_ui, 46 AppListControllerDelegate* list_controller) 47 : profile_(profile), 48 search_box_(search_box), 49 speech_ui_(speech_ui), 50 list_controller_(list_controller), 51 dispatching_query_(false), 52 mixer_(new Mixer(results)), 53 history_(HistoryFactory::GetForBrowserContext(profile)) { 54 speech_ui_->AddObserver(this); 55 Init(); 56} 57 58SearchController::~SearchController() { 59 speech_ui_->RemoveObserver(this); 60} 61 62void SearchController::Init() { 63 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); 64 search_box_->SetIcon(*bundle.GetImageSkiaNamed(IDR_OMNIBOX_SEARCH)); 65 StartPageService* service = StartPageService::Get(profile_); 66 if (service && service->GetSpeechRecognitionContents()) { 67 search_box_->SetSpeechRecognitionButton( 68 scoped_ptr<SearchBoxModel::SpeechButtonProperty>( 69 new SearchBoxModel::SpeechButtonProperty( 70 *bundle.GetImageSkiaNamed(IDR_OMNIBOX_MIC_SEARCH), 71 l10n_util::GetStringUTF16( 72 IDS_APP_LIST_HOTWORD_LISTENING), 73 *bundle.GetImageSkiaNamed(IDR_APP_LIST_MIC_HOTWORD_OFF), 74 l10n_util::GetStringUTF16( 75 IDS_APP_LIST_START_SPEECH_RECOGNITION)))); 76 } 77 OnSpeechRecognitionStateChanged(speech_ui_->state()); 78 79 mixer_->Init(); 80 81 AddProvider(Mixer::MAIN_GROUP, scoped_ptr<SearchProvider>( 82 new AppSearchProvider(profile_, list_controller_)).Pass()); 83 AddProvider(Mixer::OMNIBOX_GROUP, scoped_ptr<SearchProvider>( 84 new OmniboxProvider(profile_)).Pass()); 85 AddProvider(Mixer::WEBSTORE_GROUP, scoped_ptr<SearchProvider>( 86 new WebstoreProvider(profile_, list_controller_)).Pass()); 87 if (!CommandLine::ForCurrentProcess()->HasSwitch( 88 switches::kDisablePeopleSearch)) { 89 AddProvider(Mixer::PEOPLE_GROUP, scoped_ptr<SearchProvider>( 90 new PeopleProvider(profile_)).Pass()); 91 } 92} 93 94void SearchController::Start() { 95 Stop(); 96 97 base::string16 query; 98 TrimWhitespace(search_box_->text(), TRIM_ALL, &query); 99 100 dispatching_query_ = true; 101 for (Providers::iterator it = providers_.begin(); 102 it != providers_.end(); 103 ++it) { 104 (*it)->Start(query); 105 } 106 dispatching_query_ = false; 107 108 OnResultsChanged(); 109 110 // Maximum time (in milliseconds) to wait to the search providers to finish. 111 const int kStopTimeMS = 1500; 112 stop_timer_.Start(FROM_HERE, 113 base::TimeDelta::FromMilliseconds(kStopTimeMS), 114 base::Bind(&SearchController::Stop, 115 base::Unretained(this))); 116} 117 118void SearchController::Stop() { 119 stop_timer_.Stop(); 120 121 for (Providers::iterator it = providers_.begin(); 122 it != providers_.end(); 123 ++it) { 124 (*it)->Stop(); 125 } 126} 127 128void SearchController::OpenResult(SearchResult* result, int event_flags) { 129 // Count AppList.Search here because it is composed of search + action. 130 content::RecordAction(base::UserMetricsAction("AppList_Search")); 131 132 ChromeSearchResult* chrome_result = 133 static_cast<app_list::ChromeSearchResult*>(result); 134 UMA_HISTOGRAM_ENUMERATION(kAppListSearchResultOpenTypeHistogram, 135 chrome_result->GetType(), 136 SEARCH_RESULT_TYPE_BOUNDARY); 137 chrome_result->Open(event_flags); 138 139 if (history_ && history_->IsReady()) { 140 history_->AddLaunchEvent(base::UTF16ToUTF8(search_box_->text()), 141 chrome_result->id()); 142 } 143} 144 145void SearchController::InvokeResultAction(SearchResult* result, 146 int action_index, 147 int event_flags) { 148 // TODO(xiyuan): Hook up with user learning. 149 static_cast<app_list::ChromeSearchResult*>(result)->InvokeAction( 150 action_index, event_flags); 151} 152 153void SearchController::AddProvider(Mixer::GroupId group, 154 scoped_ptr<SearchProvider> provider) { 155 provider->set_result_changed_callback(base::Bind( 156 &SearchController::OnResultsChanged, 157 base::Unretained(this))); 158 mixer_->AddProviderToGroup(group, provider.get()); 159 providers_.push_back(provider.release()); // Takes ownership. 160} 161 162void SearchController::OnResultsChanged() { 163 if (dispatching_query_) 164 return; 165 166 KnownResults known_results; 167 if (history_ && history_->IsReady()) { 168 history_->GetKnownResults(base::UTF16ToUTF8(search_box_->text())) 169 ->swap(known_results); 170 } 171 172 mixer_->MixAndPublish(known_results); 173} 174 175void SearchController::OnSpeechRecognitionStateChanged( 176 SpeechRecognitionState new_state) { 177 search_box_->SetHintText(l10n_util::GetStringUTF16( 178 (new_state == SPEECH_RECOGNITION_HOTWORD_LISTENING) ? 179 IDS_SEARCH_BOX_HOTWORD_HINT : IDS_SEARCH_BOX_HINT)); 180} 181 182} // namespace app_list 183