search_controller.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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/search_provider.h" 23#include "chrome/browser/ui/app_list/search/webstore_provider.h" 24#include "content/public/browser/user_metrics.h" 25#include "grit/generated_resources.h" 26#include "grit/theme_resources.h" 27#include "ui/app_list/search_box_model.h" 28#include "ui/base/l10n/l10n_util.h" 29#include "ui/base/resource/resource_bundle.h" 30 31namespace { 32 const char kAppListSearchResultOpenTypeHistogram[] = 33 "Apps.AppListSearchResultOpenType"; 34} 35 36namespace app_list { 37 38SearchController::SearchController(Profile* profile, 39 SearchBoxModel* search_box, 40 AppListModel::SearchResults* results, 41 AppListControllerDelegate* list_controller) 42 : profile_(profile), 43 search_box_(search_box), 44 list_controller_(list_controller), 45 dispatching_query_(false), 46 mixer_(new Mixer(results)), 47 history_(HistoryFactory::GetForBrowserContext(profile)) { 48 Init(); 49} 50 51SearchController::~SearchController() {} 52 53void SearchController::Init() { 54 search_box_->SetHintText( 55 l10n_util::GetStringUTF16(IDS_SEARCH_BOX_HINT)); 56 search_box_->SetIcon(*ui::ResourceBundle::GetSharedInstance(). 57 GetImageSkiaNamed(IDR_OMNIBOX_SEARCH)); 58 59 mixer_->Init(); 60 61 AddProvider(Mixer::MAIN_GROUP, scoped_ptr<SearchProvider>( 62 new AppSearchProvider(profile_, list_controller_)).Pass()); 63 AddProvider(Mixer::OMNIBOX_GROUP, scoped_ptr<SearchProvider>( 64 new OmniboxProvider(profile_)).Pass()); 65 AddProvider(Mixer::WEBSTORE_GROUP, scoped_ptr<SearchProvider>( 66 new WebstoreProvider(profile_, list_controller_)).Pass()); 67} 68 69void SearchController::Start() { 70 Stop(); 71 72 string16 query; 73 TrimWhitespace(search_box_->text(), TRIM_ALL, &query); 74 75 dispatching_query_ = true; 76 for (Providers::iterator it = providers_.begin(); 77 it != providers_.end(); 78 ++it) { 79 (*it)->Start(query); 80 } 81 dispatching_query_ = false; 82 83 OnResultsChanged(); 84 85 // Maximum time (in milliseconds) to wait to the search providers to finish. 86 const int kStopTimeMS = 1500; 87 stop_timer_.Start(FROM_HERE, 88 base::TimeDelta::FromMilliseconds(kStopTimeMS), 89 base::Bind(&SearchController::Stop, 90 base::Unretained(this))); 91} 92 93void SearchController::Stop() { 94 stop_timer_.Stop(); 95 96 for (Providers::iterator it = providers_.begin(); 97 it != providers_.end(); 98 ++it) { 99 (*it)->Stop(); 100 } 101} 102 103void SearchController::OpenResult(SearchResult* result, int event_flags) { 104 // Count AppList.Search here because it is composed of search + action. 105 content::RecordAction(content::UserMetricsAction("AppList_Search")); 106 107 ChromeSearchResult* chrome_result = 108 static_cast<app_list::ChromeSearchResult*>(result); 109 UMA_HISTOGRAM_ENUMERATION(kAppListSearchResultOpenTypeHistogram, 110 chrome_result->GetType(), 111 SEARCH_RESULT_TYPE_BOUNDARY); 112 chrome_result->Open(event_flags); 113 114 if (history_ && history_->IsReady()) { 115 history_->AddLaunchEvent(UTF16ToUTF8(search_box_->text()), 116 chrome_result->id()); 117 } 118} 119 120void SearchController::InvokeResultAction(SearchResult* result, 121 int action_index, 122 int event_flags) { 123 // TODO(xiyuan): Hook up with user learning. 124 static_cast<app_list::ChromeSearchResult*>(result)->InvokeAction( 125 action_index, event_flags); 126} 127 128void SearchController::AddProvider(Mixer::GroupId group, 129 scoped_ptr<SearchProvider> provider) { 130 provider->set_result_changed_callback(base::Bind( 131 &SearchController::OnResultsChanged, 132 base::Unretained(this))); 133 mixer_->AddProviderToGroup(group, provider.get()); 134 providers_.push_back(provider.release()); // Takes ownership. 135} 136 137void SearchController::OnResultsChanged() { 138 if (dispatching_query_) 139 return; 140 141 KnownResults known_results; 142 if (history_ && history_->IsReady()) { 143 history_->GetKnownResults(UTF16ToUTF8(search_box_->text())) 144 ->swap(known_results); 145 } 146 147 mixer_->MixAndPublish(known_results); 148} 149 150} // namespace app_list 151