- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / app_list / search / people / people_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/people/people_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/string_number_conversions.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/values.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/search/search.h"
18 #include "chrome/browser/signin/profile_oauth2_token_service.h"
19 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
20 #include "chrome/browser/ui/app_list/search/common/json_response_fetcher.h"
21 #include "chrome/browser/ui/app_list/search/people/people_result.h"
22 #include "chrome/browser/ui/app_list/search/people/person.h"
23 #include "google_apis/gaia/gaia_constants.h"
24 #include "net/base/url_util.h"
25 #include "url/gurl.h"
26
27 namespace app_list {
28
29 namespace {
30
31 const char kKeyItems[] = "items";
32
33 const char kAccessTokenField[] = "access_token";
34 const char kQueryField[] = "query";
35 const char kPeopleSearchUrl[] =
36     "https://www.googleapis.com/plus/v2whitelisted/people/autocomplete";
37
38 // OAuth2 scope for access to the Google+ People Search API.
39 const char kPeopleSearchOAuth2Scope[] =
40     "https://www.googleapis.com/auth/plus.peopleapi.readwrite";
41
42 }  // namespace
43
44 PeopleProvider::PeopleProvider(Profile* profile)
45   : WebserviceSearchProvider(profile),
46     people_search_url_(kPeopleSearchUrl),
47     skip_request_token_for_test_(false) {
48   oauth2_scope_.insert(kPeopleSearchOAuth2Scope);
49 }
50
51 PeopleProvider::~PeopleProvider() {}
52
53 void PeopleProvider::Start(const base::string16& query) {
54   ClearResults();
55   if (!IsValidQuery(query)) {
56     query_.clear();
57     return;
58   }
59
60   query_ = UTF16ToUTF8(query);
61
62   const CacheResult result = cache_->Get(WebserviceCache::PEOPLE, query_);
63   if (result.second) {
64     ProcessPeopleSearchResults(result.second);
65     if (!people_search_fetched_callback_.is_null())
66       people_search_fetched_callback_.Run();
67     if (result.first == FRESH)
68       return;
69   }
70
71
72   if (!people_search_) {
73     people_search_.reset(new JSONResponseFetcher(
74         base::Bind(&PeopleProvider::OnPeopleSearchFetched,
75                    base::Unretained(this)),
76         profile_->GetRequestContext()));
77   }
78
79   if (!skip_request_token_for_test_) {
80     // We start with reqesting the access token. Once the token is fetched,
81     // we'll create the full query URL and fetch it.
82     StartThrottledQuery(base::Bind(&PeopleProvider::RequestAccessToken,
83                                    base::Unretained(this)));
84   } else {
85     // Running in a test, skip requesting the access token, straight away
86     // start our query.
87     StartThrottledQuery(base::Bind(&PeopleProvider::StartQuery,
88                                    base::Unretained(this)));
89   }
90 }
91
92 void PeopleProvider::Stop() {
93   if (people_search_)
94     people_search_->Stop();
95 }
96
97 void PeopleProvider::OnGetTokenSuccess(
98     const OAuth2TokenService::Request* request,
99     const std::string& access_token,
100     const base::Time& expiration_time) {
101   DCHECK_EQ(access_token_request_, request);
102   access_token_request_.reset();
103   access_token_ = access_token;
104   StartQuery();
105 }
106
107 void PeopleProvider::OnGetTokenFailure(
108     const OAuth2TokenService::Request* request,
109     const GoogleServiceAuthError& error) {
110   DCHECK_EQ(access_token_request_, request);
111   access_token_request_.reset();
112 }
113
114 void PeopleProvider::RequestAccessToken() {
115   // Only one active request at a time.
116   if (access_token_request_ != NULL)
117     return;
118
119   ProfileOAuth2TokenService* token_service =
120       ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
121   access_token_request_ = token_service->StartRequest(
122       token_service->GetPrimaryAccountId(), oauth2_scope_, this);
123 }
124
125 GURL PeopleProvider::GetQueryUrl(const std::string& query) {
126   GURL people_search_url = people_search_url_;
127   people_search_url = net::AppendQueryParameter(people_search_url,
128                                                 kAccessTokenField,
129                                                 access_token_);
130   people_search_url = net::AppendQueryParameter(people_search_url,
131                                                 kQueryField,
132                                                 query);
133
134   return people_search_url;
135 }
136
137 void PeopleProvider::StartQuery() {
138   // |query_| can be NULL when the query is scheduled but then canceled.
139   if (!people_search_ || query_.empty())
140     return;
141
142   GURL url = GetQueryUrl(query_);
143   people_search_->Start(url);
144 }
145
146 void PeopleProvider::OnPeopleSearchFetched(
147     scoped_ptr<base::DictionaryValue> json) {
148   ProcessPeopleSearchResults(json.get());
149   cache_->Put(WebserviceCache::PEOPLE, query_, json.Pass());
150
151   if (!people_search_fetched_callback_.is_null())
152     people_search_fetched_callback_.Run();
153 }
154
155 void PeopleProvider::ProcessPeopleSearchResults(
156     const base::DictionaryValue* json) {
157   const base::ListValue* item_list = NULL;
158   if (!json ||
159       !json->GetList(kKeyItems, &item_list) ||
160       !item_list ||
161       item_list->empty()) {
162     return;
163   }
164
165   ClearResults();
166   for (ListValue::const_iterator it = item_list->begin();
167        it != item_list->end();
168        ++it) {
169     const base::DictionaryValue* dict;
170     if (!(*it)->GetAsDictionary(&dict))
171       continue;
172
173     scoped_ptr<ChromeSearchResult> result(CreateResult(*dict));
174     if (!result)
175       continue;
176
177     Add(result.Pass());
178   }
179 }
180
181 scoped_ptr<ChromeSearchResult> PeopleProvider::CreateResult(
182     const base::DictionaryValue& dict) {
183   scoped_ptr<ChromeSearchResult> result;
184
185   scoped_ptr<Person> person = Person::Create(dict);
186   if (!person)
187     return result.Pass();
188
189   result.reset(new PeopleResult(profile_, person.Pass()));
190   return result.Pass();
191 }
192
193 void PeopleProvider::SetupForTest(
194     const base::Closure& people_search_fetched_callback,
195     const GURL& people_search_url) {
196   people_search_fetched_callback_ = people_search_fetched_callback;
197   people_search_url_ = people_search_url;
198   skip_request_token_for_test_ = true;
199 }
200
201 }  // namespace app_list