- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / app_list / search / webstore / webstore_provider.cc
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/webstore/webstore_provider.h"
6
7 #include <string>
8
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/metrics/field_trial.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/search/search.h"
17 #include "chrome/browser/ui/app_list/search/common/json_response_fetcher.h"
18 #include "chrome/browser/ui/app_list/search/search_webstore_result.h"
19 #include "chrome/browser/ui/app_list/search/webstore/webstore_result.h"
20 #include "chrome/common/extensions/extension_constants.h"
21 #include "url/gurl.h"
22
23 namespace app_list {
24
25 namespace {
26
27 const char kKeyResults[] = "results";
28 const char kKeyId[] = "id";
29 const char kKeyLocalizedName[] = "localized_name";
30 const char kKeyIconUrl[] = "icon_url";
31
32 // Returns true if the launcher should send queries to the web store server.
33 bool UseWebstoreSearch() {
34   const char kFieldTrialName[] = "LauncherUseWebstoreSearch";
35   const char kEnable[] = "Enable";
36   return base::FieldTrialList::FindFullName(kFieldTrialName) == kEnable;
37 }
38
39 }  // namespace
40
41 WebstoreProvider::WebstoreProvider(Profile* profile,
42                                    AppListControllerDelegate* controller)
43   :  WebserviceSearchProvider(profile),
44      controller_(controller){}
45
46 WebstoreProvider::~WebstoreProvider() {}
47
48 void WebstoreProvider::Start(const base::string16& query) {
49   ClearResults();
50   if (!IsValidQuery(query)) {
51     query_.clear();
52     return;
53   }
54
55   query_ = UTF16ToUTF8(query);
56   const CacheResult result = cache_->Get(WebserviceCache::WEBSTORE, query_);
57   if (result.second) {
58     ProcessWebstoreSearchResults(result.second);
59     if (!webstore_search_fetched_callback_.is_null())
60       webstore_search_fetched_callback_.Run();
61     if (result.first == FRESH)
62       return;
63   }
64
65   if (UseWebstoreSearch()) {
66     if (!webstore_search_) {
67       webstore_search_.reset(new JSONResponseFetcher(
68           base::Bind(&WebstoreProvider::OnWebstoreSearchFetched,
69                      base::Unretained(this)),
70           profile_->GetRequestContext()));
71     }
72
73     StartThrottledQuery(base::Bind(&WebstoreProvider::StartQuery,
74                                    base::Unretained(this)));
75   }
76
77   // Add a placeholder result which when clicked will run the user's query in a
78   // browser. This placeholder is removed when the search results arrive.
79   Add(scoped_ptr<ChromeSearchResult>(
80       new SearchWebstoreResult(profile_, query_)).Pass());
81 }
82
83 void WebstoreProvider::Stop() {
84   if (webstore_search_)
85     webstore_search_->Stop();
86 }
87
88 void WebstoreProvider::StartQuery() {
89   // |query_| can be NULL when the query is scheduled but then canceled.
90   if (!webstore_search_ || query_.empty())
91     return;
92
93   webstore_search_->Start(extension_urls::GetWebstoreJsonSearchUrl(
94       query_, g_browser_process->GetApplicationLocale()));
95 }
96
97 void WebstoreProvider::OnWebstoreSearchFetched(
98     scoped_ptr<base::DictionaryValue> json) {
99   ProcessWebstoreSearchResults(json.get());
100   cache_->Put(WebserviceCache::WEBSTORE, query_, json.Pass());
101
102   if (!webstore_search_fetched_callback_.is_null())
103     webstore_search_fetched_callback_.Run();
104 }
105
106 void WebstoreProvider::ProcessWebstoreSearchResults(
107     const base::DictionaryValue* json) {
108   const base::ListValue* result_list = NULL;
109   if (!json ||
110       !json->GetList(kKeyResults, &result_list) ||
111       !result_list ||
112       result_list->empty()) {
113     return;
114   }
115
116   bool first_result = true;
117   for (ListValue::const_iterator it = result_list->begin();
118        it != result_list->end();
119        ++it) {
120     const base::DictionaryValue* dict;
121     if (!(*it)->GetAsDictionary(&dict))
122       continue;
123
124     scoped_ptr<ChromeSearchResult> result(CreateResult(*dict));
125     if (!result)
126       continue;
127
128     if (first_result) {
129       // Clears "search in webstore" place holder results.
130       ClearResults();
131       first_result = false;
132     }
133
134     Add(result.Pass());
135   }
136 }
137
138 scoped_ptr<ChromeSearchResult> WebstoreProvider::CreateResult(
139     const base::DictionaryValue& dict) {
140   scoped_ptr<ChromeSearchResult> result;
141
142   std::string app_id;
143   std::string localized_name;
144   std::string icon_url_string;
145   if (!dict.GetString(kKeyId, &app_id) ||
146       !dict.GetString(kKeyLocalizedName, &localized_name) ||
147       !dict.GetString(kKeyIconUrl, &icon_url_string)) {
148     return result.Pass();
149   }
150
151   GURL icon_url(icon_url_string);
152   if (!icon_url.is_valid())
153     return result.Pass();
154
155   result.reset(new WebstoreResult(
156       profile_, app_id, localized_name, icon_url, controller_));
157   return result.Pass();
158 }
159
160 }  // namespace app_list