Home | History | Annotate | Download | only in search
      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 
     31 namespace {
     32   const char kAppListSearchResultOpenTypeHistogram[] =
     33       "Apps.AppListSearchResultOpenType";
     34 }
     35 
     36 namespace app_list {
     37 
     38 SearchController::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 
     51 SearchController::~SearchController() {}
     52 
     53 void 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 
     69 void 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 
     93 void 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 
    103 void 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 
    120 void 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 
    128 void 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 
    137 void 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