webstore_provider.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/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 23namespace app_list { 24 25namespace { 26 27const char kKeyResults[] = "results"; 28const char kKeyId[] = "id"; 29const char kKeyLocalizedName[] = "localized_name"; 30const char kKeyIconUrl[] = "icon_url"; 31 32// Returns true if the launcher should send queries to the web store server. 33bool UseWebstoreSearch() { 34 const char kFieldTrialName[] = "LauncherUseWebstoreSearch"; 35 const char kEnable[] = "Enable"; 36 return base::FieldTrialList::FindFullName(kFieldTrialName) == kEnable; 37} 38 39} // namespace 40 41WebstoreProvider::WebstoreProvider(Profile* profile, 42 AppListControllerDelegate* controller) 43 : WebserviceSearchProvider(profile), 44 controller_(controller){} 45 46WebstoreProvider::~WebstoreProvider() {} 47 48void WebstoreProvider::Start(const base::string16& query) { 49 ClearResults(); 50 if (!IsValidQuery(query)) { 51 query_.clear(); 52 return; 53 } 54 55 query_ = base::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 83void WebstoreProvider::Stop() { 84 if (webstore_search_) 85 webstore_search_->Stop(); 86} 87 88void 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 97void 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 106void 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 (base::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 138scoped_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 161