Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(274)

Side by Side Diff: chrome/browser/chrome_to_mobile_service.cc

Issue 10834203: Integrate invalidation API into ChromeToMobileService. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Tie to ProfileSyncService state, move invalidation registration back into ctor, update tests, etc. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chrome_to_mobile_service.h" 5 #include "chrome/browser/chrome_to_mobile_service.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/file_util.h" 9 #include "base/file_util.h"
10 #include "base/guid.h" 10 #include "base/guid.h"
11 #include "base/json/json_reader.h" 11 #include "base/json/json_reader.h"
12 #include "base/json/json_writer.h" 12 #include "base/json/json_writer.h"
13 #include "base/metrics/histogram.h" 13 #include "base/metrics/histogram.h"
14 #include "base/stringprintf.h"
15 #include "base/utf_string_conversions.h" 14 #include "base/utf_string_conversions.h"
16 #include "chrome/app/chrome_command_ids.h" 15 #include "chrome/app/chrome_command_ids.h"
17 #include "chrome/browser/content_settings/cookie_settings.h"
18 #include "chrome/browser/prefs/pref_service.h" 16 #include "chrome/browser/prefs/pref_service.h"
19 #include "chrome/browser/printing/cloud_print/cloud_print_url.h" 17 #include "chrome/browser/printing/cloud_print/cloud_print_url.h"
20 #include "chrome/browser/profiles/profile.h" 18 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/signin/token_service.h" 19 #include "chrome/browser/signin/token_service.h"
22 #include "chrome/browser/signin/token_service_factory.h" 20 #include "chrome/browser/signin/token_service_factory.h"
21 #include "chrome/browser/sync/profile_sync_service.h"
22 #include "chrome/browser/sync/profile_sync_service_factory.h"
23 #include "chrome/browser/ui/browser.h" 23 #include "chrome/browser/ui/browser.h"
24 #include "chrome/browser/ui/browser_command_controller.h" 24 #include "chrome/browser/ui/browser_command_controller.h"
25 #include "chrome/browser/ui/browser_finder.h" 25 #include "chrome/browser/ui/browser_finder.h"
26 #include "chrome/browser/ui/browser_list.h" 26 #include "chrome/browser/ui/browser_list.h"
27 #include "chrome/browser/ui/browser_navigator.h" 27 #include "chrome/browser/ui/browser_navigator.h"
28 #include "chrome/browser/ui/browser_tabstrip.h" 28 #include "chrome/browser/ui/browser_tabstrip.h"
29 #include "chrome/common/chrome_notification_types.h" 29 #include "chrome/common/chrome_notification_types.h"
30 #include "chrome/common/chrome_switches.h" 30 #include "chrome/common/chrome_switches.h"
31 #include "chrome/common/cloud_print/cloud_print_helpers.h" 31 #include "chrome/common/cloud_print/cloud_print_helpers.h"
32 #include "chrome/common/net/gaia/gaia_constants.h" 32 #include "chrome/common/net/gaia/gaia_constants.h"
33 #include "chrome/common/net/gaia/gaia_urls.h" 33 #include "chrome/common/net/gaia/gaia_urls.h"
34 #include "chrome/common/net/gaia/oauth2_access_token_fetcher.h" 34 #include "chrome/common/net/gaia/oauth2_access_token_fetcher.h"
35 #include "chrome/common/pref_names.h" 35 #include "chrome/common/pref_names.h"
36 #include "chrome/common/url_constants.h" 36 #include "chrome/common/url_constants.h"
37 #include "content/public/browser/browser_thread.h" 37 #include "content/public/browser/browser_thread.h"
38 #include "content/public/browser/notification_details.h" 38 #include "content/public/browser/notification_details.h"
39 #include "content/public/browser/notification_source.h" 39 #include "content/public/browser/notification_source.h"
40 #include "content/public/browser/web_contents.h" 40 #include "content/public/browser/web_contents.h"
41 #include "google/cacheinvalidation/include/types.h"
42 #include "google/cacheinvalidation/types.pb.h"
41 #include "net/base/escape.h" 43 #include "net/base/escape.h"
42 #include "net/base/load_flags.h" 44 #include "net/base/load_flags.h"
43 #include "net/url_request/url_fetcher.h" 45 #include "net/url_request/url_fetcher.h"
44 #include "net/url_request/url_request_context_getter.h" 46 #include "net/url_request/url_request_context_getter.h"
47 #include "sync/notifier/invalidation_util.h"
45 48
46 namespace { 49 namespace {
47 50
48 // The default enabled/disabled state of the Chrome To Mobile feature. 51 // The default enabled/disabled state of the Chrome To Mobile feature.
49 const bool kChromeToMobileEnabled = true; 52 const bool kChromeToMobileEnabled = true;
50 53
51 // The maximum number of retries for the URLFetcher requests. 54 // The maximum number of retries for the URLFetcher requests.
52 const size_t kMaxRetries = 1; 55 const size_t kMaxRetries = 1;
53 56
54 // The number of hours to delay before retrying authentication on failure. 57 // The number of hours to delay before retrying authentication on failure.
55 const size_t kAuthRetryDelayHours = 6; 58 const size_t kAuthRetryDelayHours = 6;
56 59
57 // The number of hours before subsequent search requests are allowed. 60 // The number of hours before subsequent search requests are allowed.
58 // This value is used to throttle expensive cloud print search requests. 61 // This value is used to throttle expensive cloud print search requests.
59 // Note that this limitation does not hold across application restarts. 62 // Note that this limitation does not hold across application restarts.
60 const int kSearchRequestDelayHours = 24; 63 const int kSearchRequestDelayHours = 24;
61 64
65 // The sync invalidation object ID for Chrome to Mobile's mobile device list.
66 // This corresponds with cloud print's server-side invalidation object ID.
67 // Meaning: "U" == "User", "CM" == "Chrome to Mobile", "MLST" == "Mobile LiST".
68 const char kSyncInvalidationObjectIdChromeToMobileDeviceList[] = "UCMMLST";
69
62 // The cloud print OAuth2 scope and 'printer' type of compatible mobile devices. 70 // The cloud print OAuth2 scope and 'printer' type of compatible mobile devices.
63 const char kCloudPrintAuth[] = "https://www.googleapis.com/auth/cloudprint"; 71 const char kCloudPrintAuth[] = "https://www.googleapis.com/auth/cloudprint";
64 const char kTypeAndroid[] = "ANDROID_CHROME_SNAPSHOT"; 72 const char kTypeAndroid[] = "ANDROID_CHROME_SNAPSHOT";
65 const char kTypeIOS[] = "IOS_CHROME_SNAPSHOT"; 73 const char kTypeIOS[] = "IOS_CHROME_SNAPSHOT";
66 74
67 // The account info URL pattern and strings to check for cloud print access.
68 // The 'key=' query parameter is used for caching; supply a random number.
69 // The 'rv=2' query parameter requests a JSON response; use 'rv=1' for XML.
70 const char kAccountInfoURL[] =
71 "https://clients1.google.com/tbproxy/getaccountinfo?key=%s&rv=2&%s";
72 const char kAccountServicesKey[] = "services";
73 const char kCloudPrintSerivceValue[] = "cprt";
74
75 // The Chrome To Mobile requestor type; used by services for filtering. 75 // The Chrome To Mobile requestor type; used by services for filtering.
76 const char kChromeToMobileRequestor[] = "requestor=chrome-to-mobile"; 76 const char kChromeToMobileRequestor[] = "requestor=chrome-to-mobile";
77 77
78 // Get the job type string for a cloud print job submission. 78 // Get the job type string for a cloud print job submission.
79 std::string GetType(const ChromeToMobileService::JobData& data) { 79 std::string GetType(const ChromeToMobileService::JobData& data) {
80 if (data.type == ChromeToMobileService::URL) 80 if (data.type == ChromeToMobileService::URL)
81 return "url"; 81 return "url";
82 if (data.type == ChromeToMobileService::DELAYED_SNAPSHOT) 82 if (data.type == ChromeToMobileService::DELAYED_SNAPSHOT)
83 return "url_with_delayed_snapshot"; 83 return "url_with_delayed_snapshot";
84 DCHECK_EQ(data.type, ChromeToMobileService::SNAPSHOT); 84 DCHECK_EQ(data.type, ChromeToMobileService::SNAPSHOT);
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 if (command_line->HasSwitch(switches::kEnableChromeToMobile)) 173 if (command_line->HasSwitch(switches::kEnableChromeToMobile))
174 return true; 174 return true;
175 175
176 return kChromeToMobileEnabled; 176 return kChromeToMobileEnabled;
177 } 177 }
178 178
179 // static 179 // static
180 void ChromeToMobileService::RegisterUserPrefs(PrefService* prefs) { 180 void ChromeToMobileService::RegisterUserPrefs(PrefService* prefs) {
181 prefs->RegisterListPref(prefs::kChromeToMobileDeviceList, 181 prefs->RegisterListPref(prefs::kChromeToMobileDeviceList,
182 PrefService::UNSYNCABLE_PREF); 182 PrefService::UNSYNCABLE_PREF);
183 prefs->RegisterInt64Pref(prefs::kChromeToMobileTimestamp, 0,
184 PrefService::UNSYNCABLE_PREF);
185 } 183 }
186 184
187 ChromeToMobileService::ChromeToMobileService(Profile* profile) 185 ChromeToMobileService::ChromeToMobileService(Profile* profile)
188 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), 186 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)),
189 profile_(profile), 187 profile_(profile),
190 cloud_print_url_(new CloudPrintURL(profile)), 188 profile_sync_service_enabled_(false),
191 cloud_print_accessible_(false) { 189 sync_invalidation_enabled_(false),
192 // TODO(msw): Fix GMock tests, which lack profiles (http://crbug.com/122183). 190 cloud_print_url_(new CloudPrintURL(profile)) {
191 // TODO(msw): Unit tests do not provide profiles; see http://crbug.com/122183
193 if (profile_) { 192 if (profile_) {
194 // Get an access token as soon as the Gaia login refresh token is available. 193 // Register for profile sync and cloud print device list notifications.
195 TokenService* service = TokenServiceFactory::GetForProfile(profile_); 194 ProfileSyncService* profile_sync_service =
196 registrar_.Add(this, chrome::NOTIFICATION_TOKEN_AVAILABLE, 195 ProfileSyncServiceFactory::GetForProfile(profile_);
akalin 2012/08/20 20:50:17 may want to handle a NULL pss? in case --disable-
msw 2012/08/20 21:56:15 Done.
197 content::Source<TokenService>(service)); 196 profile_sync_service_enabled_ = profile_sync_service->ShouldPushChanges();
akalin 2012/08/20 20:50:17 may want to add a comment re. the unintuitive func
msw 2012/08/20 21:56:15 Done.
198 if (service->HasOAuthLoginToken()) 197 profile_sync_service->AddObserver(this);
199 RequestAccessToken(); 198 profile_sync_service->RegisterInvalidationHandler(this);
199 syncer::ObjectIdSet ids;
akalin 2012/08/20 20:50:17 add the TODO here to initialize sync_invalidation_
msw 2012/08/20 21:56:15 Done.
200 ids.insert(invalidation::ObjectId(
201 ipc::invalidation::ObjectSource::CHROME_COMPONENTS,
202 kSyncInvalidationObjectIdChromeToMobileDeviceList));
203 profile_sync_service->UpdateRegisteredInvalidationIds(this, ids);
200 } 204 }
201 } 205 }
202 206
203 ChromeToMobileService::~ChromeToMobileService() { 207 ChromeToMobileService::~ChromeToMobileService() {
204 while (!snapshots_.empty()) 208 while (!snapshots_.empty())
205 DeleteSnapshot(*snapshots_.begin()); 209 DeleteSnapshot(*snapshots_.begin());
210 // TODO(msw): Unit tests do not provide profiles; see http://crbug.com/122183
211 if (profile_) {
212 // Unregister for profile sync and cloud print device list notifications.
213 ProfileSyncService* profile_sync_service =
214 ProfileSyncServiceFactory::GetForProfile(profile_);
215 profile_sync_service->RemoveObserver(this);
akalin 2012/08/20 20:50:17 here too
msw 2012/08/20 21:56:15 Done.
216 profile_sync_service->UnregisterInvalidationHandler(this);
217 }
206 } 218 }
207 219
208 bool ChromeToMobileService::HasMobiles() const { 220 bool ChromeToMobileService::HasMobiles() const {
209 return !GetMobiles()->empty(); 221 const base::ListValue* mobiles = GetMobiles();
222 return mobiles && !mobiles->empty();
210 } 223 }
211 224
212 const base::ListValue* ChromeToMobileService::GetMobiles() const { 225 const base::ListValue* ChromeToMobileService::GetMobiles() const {
213 return profile_->GetPrefs()->GetList(prefs::kChromeToMobileDeviceList); 226 return (profile_sync_service_enabled_ && sync_invalidation_enabled_) ?
214 } 227 profile_->GetPrefs()->GetList(prefs::kChromeToMobileDeviceList) : NULL;
215
216 void ChromeToMobileService::RequestMobileListUpdate() {
217 if (access_token_.empty())
218 RequestAccessToken();
219 else if (cloud_print_accessible_)
220 RequestDeviceSearch();
221 } 228 }
222 229
223 void ChromeToMobileService::GenerateSnapshot(Browser* browser, 230 void ChromeToMobileService::GenerateSnapshot(Browser* browser,
224 base::WeakPtr<Observer> observer) { 231 base::WeakPtr<Observer> observer) {
225 // Callback SnapshotFileCreated from CreateSnapshotFile to continue. 232 // Callback SnapshotFileCreated from CreateSnapshotFile to continue.
226 CreateSnapshotFileCallback callback = 233 CreateSnapshotFileCallback callback =
227 base::Bind(&ChromeToMobileService::SnapshotFileCreated, 234 base::Bind(&ChromeToMobileService::SnapshotFileCreated,
228 weak_ptr_factory_.GetWeakPtr(), observer, 235 weak_ptr_factory_.GetWeakPtr(), observer,
229 browser->session_id().id()); 236 browser->session_id().id());
230 // Create a temporary file via the blocking pool for snapshot storage. 237 // Create a temporary file via the blocking pool for snapshot storage.
231 if (!content::BrowserThread::PostBlockingPoolTask(FROM_HERE, 238 if (!content::BrowserThread::PostBlockingPoolTask(FROM_HERE,
232 base::Bind(&CreateSnapshotFile, callback))) { 239 base::Bind(&CreateSnapshotFile, callback))) {
233 NOTREACHED(); 240 NOTREACHED();
234 } 241 }
235 } 242 }
236 243
237 void ChromeToMobileService::SendToMobile(const base::DictionaryValue& mobile, 244 void ChromeToMobileService::SendToMobile(const base::DictionaryValue* mobile,
238 const FilePath& snapshot, 245 const FilePath& snapshot,
239 Browser* browser, 246 Browser* browser,
240 base::WeakPtr<Observer> observer) { 247 base::WeakPtr<Observer> observer) {
248 if (access_token_.empty()) {
249 // Enqueue this task to perform after obtaining an access token.
250 task_queue_.push(base::Bind(&ChromeToMobileService::SendToMobile,
251 weak_ptr_factory_.GetWeakPtr(), base::Owned(mobile->DeepCopy()),
252 snapshot, browser, observer));
253 RequestAccessToken();
254 return;
255 }
256
241 LogMetric(SENDING_URL); 257 LogMetric(SENDING_URL);
242 258
243 JobData data; 259 JobData data;
244 std::string mobile_os; 260 std::string mobile_os;
245 if (!mobile.GetString("type", &mobile_os)) 261 if (!mobile->GetString("type", &mobile_os))
246 NOTREACHED(); 262 NOTREACHED();
247 data.mobile_os = (mobile_os.compare(kTypeAndroid) == 0) ? 263 data.mobile_os = (mobile_os.compare(kTypeAndroid) == 0) ?
248 ChromeToMobileService::ANDROID : ChromeToMobileService::IOS; 264 ChromeToMobileService::ANDROID : ChromeToMobileService::IOS;
249 if (!mobile.GetString("id", &data.mobile_id)) 265 if (!mobile->GetString("id", &data.mobile_id))
250 NOTREACHED(); 266 NOTREACHED();
251 content::WebContents* web_contents = chrome::GetActiveWebContents(browser); 267 content::WebContents* web_contents = chrome::GetActiveWebContents(browser);
252 data.url = web_contents->GetURL(); 268 data.url = web_contents->GetURL();
253 data.title = web_contents->GetTitle(); 269 data.title = web_contents->GetTitle();
254 data.snapshot = snapshot; 270 data.snapshot = snapshot;
255 data.snapshot_id = base::GenerateGUID(); 271 data.snapshot_id = base::GenerateGUID();
256 data.type = !snapshot.empty() ? DELAYED_SNAPSHOT : URL; 272 data.type = !snapshot.empty() ? DELAYED_SNAPSHOT : URL;
257 273
258 net::URLFetcher* submit_url = CreateRequest(data); 274 net::URLFetcher* submit_url = CreateRequest(data);
259 request_observer_map_[submit_url] = observer; 275 request_observer_map_[submit_url] = observer;
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 } 310 }
295 311
296 void ChromeToMobileService::LearnMore(Browser* browser) const { 312 void ChromeToMobileService::LearnMore(Browser* browser) const {
297 LogMetric(LEARN_MORE_CLICKED); 313 LogMetric(LEARN_MORE_CLICKED);
298 chrome::NavigateParams params(browser, 314 chrome::NavigateParams params(browser,
299 GURL(chrome::kChromeToMobileLearnMoreURL), content::PAGE_TRANSITION_LINK); 315 GURL(chrome::kChromeToMobileLearnMoreURL), content::PAGE_TRANSITION_LINK);
300 params.disposition = NEW_FOREGROUND_TAB; 316 params.disposition = NEW_FOREGROUND_TAB;
301 chrome::Navigate(&params); 317 chrome::Navigate(&params);
302 } 318 }
303 319
304 void ChromeToMobileService::OnURLFetchComplete( 320 void ChromeToMobileService::OnURLFetchComplete(const net::URLFetcher* source) {
305 const net::URLFetcher* source) { 321 if (source == search_request_.get())
306 if (source == account_info_request_.get())
307 HandleAccountInfoResponse();
308 else if (source == search_request_.get())
309 HandleSearchResponse(); 322 HandleSearchResponse();
310 else 323 else
311 HandleSubmitResponse(source); 324 HandleSubmitResponse(source);
312 } 325 }
313 326
314 void ChromeToMobileService::Observe( 327 void ChromeToMobileService::Observe(
315 int type, 328 int type,
316 const content::NotificationSource& source, 329 const content::NotificationSource& source,
317 const content::NotificationDetails& details) { 330 const content::NotificationDetails& details) {
318 DCHECK_EQ(type, chrome::NOTIFICATION_TOKEN_AVAILABLE); 331 DCHECK_EQ(type, chrome::NOTIFICATION_TOKEN_AVAILABLE);
319 TokenService::TokenAvailableDetails* token_details = 332 TokenService::TokenAvailableDetails* token_details =
320 content::Details<TokenService::TokenAvailableDetails>(details).ptr(); 333 content::Details<TokenService::TokenAvailableDetails>(details).ptr();
334 // Invalidate the cloud print access token on Gaia login token updates.
321 if (token_details->service() == GaiaConstants::kGaiaOAuth2LoginRefreshToken) 335 if (token_details->service() == GaiaConstants::kGaiaOAuth2LoginRefreshToken)
322 RequestAccessToken(); 336 access_token_.clear();
323 } 337 }
324 338
325 void ChromeToMobileService::OnGetTokenSuccess( 339 void ChromeToMobileService::OnGetTokenSuccess(
326 const std::string& access_token, 340 const std::string& access_token,
327 const base::Time& expiration_time) { 341 const base::Time& expiration_time) {
328 DCHECK(!access_token.empty()); 342 DCHECK(!access_token.empty());
329 access_token_fetcher_.reset(); 343 access_token_fetcher_.reset();
330 auth_retry_timer_.Stop(); 344 auth_retry_timer_.Stop();
331 access_token_ = access_token; 345 access_token_ = access_token;
332 RequestAccountInfo(); 346
347 while (!task_queue_.empty()) {
348 // Post all tasks that were queued and waiting on a valid access token.
349 if (!content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
350 task_queue_.front())) {
351 NOTREACHED();
352 }
353 task_queue_.pop();
354 }
333 } 355 }
334 356
335 void ChromeToMobileService::OnGetTokenFailure( 357 void ChromeToMobileService::OnGetTokenFailure(
336 const GoogleServiceAuthError& error) { 358 const GoogleServiceAuthError& error) {
337 access_token_fetcher_.reset(); 359 access_token_fetcher_.reset();
338 auth_retry_timer_.Stop(); 360 auth_retry_timer_.Stop();
361
339 auth_retry_timer_.Start( 362 auth_retry_timer_.Start(
340 FROM_HERE, base::TimeDelta::FromHours(kAuthRetryDelayHours), 363 FROM_HERE, base::TimeDelta::FromHours(kAuthRetryDelayHours),
341 this, &ChromeToMobileService::RequestAccessToken); 364 this, &ChromeToMobileService::RequestAccessToken);
342 } 365 }
343 366
367 void ChromeToMobileService::OnStateChanged() {
368 profile_sync_service_enabled_ =
369 ProfileSyncServiceFactory::GetForProfile(profile_)->ShouldPushChanges();
370 UpdateCommandState();
371 }
372
373 void ChromeToMobileService::OnNotificationsEnabled() {
374 sync_invalidation_enabled_ = true;
375 UpdateCommandState();
376 }
377
378 void ChromeToMobileService::OnNotificationsDisabled(
379 syncer::NotificationsDisabledReason reason) {
380 sync_invalidation_enabled_ = false;
381 UpdateCommandState();
382 }
383
384 void ChromeToMobileService::OnIncomingNotification(
385 const syncer::ObjectIdPayloadMap& id_payloads,
386 syncer::IncomingNotificationSource source) {
387 DCHECK_EQ(id_payloads.size(), 1U);
388 DCHECK_EQ(id_payloads.count(invalidation::ObjectId(
389 ipc::invalidation::ObjectSource::CHROME_COMPONENTS,
390 kSyncInvalidationObjectIdChromeToMobileDeviceList)), 1U);
391 RequestDeviceSearch();
392 }
393
394 const std::string& ChromeToMobileService::GetAccessTokenForTest() const {
395 return access_token_;
396 }
397
398 void ChromeToMobileService::SetAccessTokenForTest(
399 const std::string& access_token) {
400 access_token_ = access_token;
401 }
402
344 void ChromeToMobileService::UpdateCommandState() const { 403 void ChromeToMobileService::UpdateCommandState() const {
345 // Ensure the feature is not disabled by commandline options. 404 // Ensure the feature is not disabled by commandline options.
346 DCHECK(IsChromeToMobileEnabled()); 405 DCHECK(IsChromeToMobileEnabled());
347 const bool has_mobiles = HasMobiles(); 406 const bool has_mobiles = HasMobiles();
348 for (BrowserList::const_iterator i = BrowserList::begin(); 407 for (BrowserList::const_iterator i = BrowserList::begin();
349 i != BrowserList::end(); ++i) { 408 i != BrowserList::end(); ++i) {
350 Browser* browser = *i; 409 Browser* browser = *i;
351 if (browser->profile() == profile_) 410 if (browser->profile() == profile_)
352 browser->command_controller()->SendToMobileStateChanged(has_mobiles); 411 browser->command_controller()->SendToMobileStateChanged(has_mobiles);
353 } 412 }
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
428 } 487 }
429 cloud_print::AddMultipartValueForUpload("content", file, bound, 488 cloud_print::AddMultipartValueForUpload("content", file, bound,
430 "text/mhtml", &post); 489 "text/mhtml", &post);
431 490
432 post.append("--" + bound + "--\r\n"); 491 post.append("--" + bound + "--\r\n");
433 request->SetUploadData("multipart/form-data; boundary=" + bound, post); 492 request->SetUploadData("multipart/form-data; boundary=" + bound, post);
434 request->Start(); 493 request->Start();
435 } 494 }
436 495
437 void ChromeToMobileService::RequestAccessToken() { 496 void ChromeToMobileService::RequestAccessToken() {
497 // Register to observe Gaia login refresh token updates.
498 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
499 if (registrar_.IsEmpty())
500 registrar_.Add(this, chrome::NOTIFICATION_TOKEN_AVAILABLE,
501 content::Source<TokenService>(token_service));
502
438 // Deny concurrent requests and bail without a valid Gaia login refresh token. 503 // Deny concurrent requests and bail without a valid Gaia login refresh token.
439 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
440 if (access_token_fetcher_.get() || !token_service->HasOAuthLoginToken()) 504 if (access_token_fetcher_.get() || !token_service->HasOAuthLoginToken())
441 return; 505 return;
442 506
443 auth_retry_timer_.Stop(); 507 auth_retry_timer_.Stop();
444 access_token_fetcher_.reset( 508 access_token_fetcher_.reset(
445 new OAuth2AccessTokenFetcher(this, profile_->GetRequestContext())); 509 new OAuth2AccessTokenFetcher(this, profile_->GetRequestContext()));
446 GaiaUrls* gaia_urls = GaiaUrls::GetInstance(); 510 GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
447 access_token_fetcher_->Start(gaia_urls->oauth2_chrome_client_id(), 511 access_token_fetcher_->Start(gaia_urls->oauth2_chrome_client_id(),
448 gaia_urls->oauth2_chrome_client_secret(), 512 gaia_urls->oauth2_chrome_client_secret(),
449 token_service->GetOAuth2LoginRefreshToken(), 513 token_service->GetOAuth2LoginRefreshToken(),
450 std::vector<std::string>(1, kCloudPrintAuth)); 514 std::vector<std::string>(1, kCloudPrintAuth));
451 } 515 }
452 516
453 void ChromeToMobileService::RequestAccountInfo() { 517 void ChromeToMobileService::RequestDeviceSearch() {
454 // Deny concurrent requests. 518 DCHECK(sync_invalidation_enabled_);
455 if (account_info_request_.get()) 519 if (access_token_.empty()) {
456 return; 520 // Enqueue this task to perform after obtaining an access token.
457 521 task_queue_.push(base::Bind(&ChromeToMobileService::RequestDeviceSearch,
458 std::string url_string = StringPrintf(kAccountInfoURL, 522 weak_ptr_factory_.GetWeakPtr()));
459 base::GenerateGUID().c_str(), kChromeToMobileRequestor); 523 RequestAccessToken();
460 GURL url(url_string);
461
462 // Account information is read from the profile's cookie. If cookies are
463 // blocked, access cloud print directly to list any potential devices.
464 scoped_refptr<CookieSettings> cookie_settings =
465 CookieSettings::Factory::GetForProfile(profile_);
466 if (cookie_settings && !cookie_settings->IsReadingCookieAllowed(url, url)) {
467 cloud_print_accessible_ = true;
468 RequestMobileListUpdate();
469 return; 524 return;
470 } 525 }
471 526
472 account_info_request_.reset( 527 // Deny concurrent requests.
473 net::URLFetcher::Create(url, net::URLFetcher::GET, this)); 528 if (search_request_.get())
474 account_info_request_->SetRequestContext(profile_->GetRequestContext());
475 account_info_request_->SetMaxRetries(kMaxRetries);
476 // This request sends the user's cookie to check the cloud print service flag.
477 account_info_request_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES);
478 account_info_request_->Start();
479 }
480
481 void ChromeToMobileService::RequestDeviceSearch() {
482 // Deny requests if cloud print is inaccessible, and deny concurrent requests.
483 if (!cloud_print_accessible_ || search_request_.get())
484 return;
485
486 PrefService* prefs = profile_->GetPrefs();
487 base::TimeTicks previous_search_time = base::TimeTicks::FromInternalValue(
488 prefs->GetInt64(prefs::kChromeToMobileTimestamp));
489
490 // Deny requests before the delay period has passed since the last request.
491 base::TimeDelta elapsed_time = base::TimeTicks::Now() - previous_search_time;
492 if (!previous_search_time.is_null() &&
493 elapsed_time.InHours() < kSearchRequestDelayHours)
494 return; 529 return;
495 530
496 LogMetric(DEVICES_REQUESTED); 531 LogMetric(DEVICES_REQUESTED);
497 532
498 const GURL service_url(cloud_print_url_->GetCloudPrintServiceURL()); 533 const GURL service_url(cloud_print_url_->GetCloudPrintServiceURL());
499 search_request_.reset(net::URLFetcher::Create(GetSearchURL(service_url), 534 search_request_.reset(net::URLFetcher::Create(GetSearchURL(service_url),
500 net::URLFetcher::GET, this)); 535 net::URLFetcher::GET, this));
501 InitRequest(search_request_.get()); 536 InitRequest(search_request_.get());
502 search_request_->Start(); 537 search_request_->Start();
503 } 538 }
504 539
505 void ChromeToMobileService::HandleAccountInfoResponse() {
506 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
507
508 std::string data;
509 account_info_request_->GetResponseAsString(&data);
510 account_info_request_.reset();
511
512 ListValue* services = NULL;
513 DictionaryValue* dictionary = NULL;
514 scoped_ptr<Value> json(base::JSONReader::Read(data));
515 StringValue cloud_print_service(kCloudPrintSerivceValue);
516 if (json.get() && json->GetAsDictionary(&dictionary) && dictionary &&
517 dictionary->GetList(kAccountServicesKey, &services) && services &&
518 services->Find(cloud_print_service) != services->end()) {
519 cloud_print_accessible_ = true;
520 RequestMobileListUpdate();
521 }
522 }
523
524 void ChromeToMobileService::HandleSearchResponse() { 540 void ChromeToMobileService::HandleSearchResponse() {
525 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 541 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
526 542
527 std::string data; 543 std::string data;
528 search_request_->GetResponseAsString(&data); 544 search_request_->GetResponseAsString(&data);
529 search_request_.reset(); 545 search_request_.reset();
530 546
531 ListValue* list = NULL; 547 ListValue* list = NULL;
532 DictionaryValue* dictionary = NULL; 548 DictionaryValue* dictionary = NULL;
533 scoped_ptr<Value> json(base::JSONReader::Read(data)); 549 scoped_ptr<Value> json(base::JSONReader::Read(data));
(...skipping 14 matching lines...) Expand all
548 mobile->SetString("type", type); 564 mobile->SetString("type", type);
549 mobile->SetString("name", name); 565 mobile->SetString("name", name);
550 mobile->SetString("id", id); 566 mobile->SetString("id", id);
551 mobiles.Append(mobile); 567 mobiles.Append(mobile);
552 } else { 568 } else {
553 NOTREACHED(); 569 NOTREACHED();
554 } 570 }
555 } 571 }
556 } 572 }
557 573
558 // Update the mobile list and timestamp in prefs. 574 // Update the cached mobile device list in profile prefs.
559 PrefService* prefs = profile_->GetPrefs(); 575 profile_->GetPrefs()->Set(prefs::kChromeToMobileDeviceList, mobiles);
560 prefs->Set(prefs::kChromeToMobileDeviceList, mobiles);
561 prefs->SetInt64(prefs::kChromeToMobileTimestamp,
562 base::TimeTicks::Now().ToInternalValue());
563 576
564 if (HasMobiles()) 577 if (HasMobiles())
565 LogMetric(DEVICES_AVAILABLE); 578 LogMetric(DEVICES_AVAILABLE);
566 UpdateCommandState(); 579 UpdateCommandState();
567 } 580 }
568 } 581 }
569 582
570 void ChromeToMobileService::HandleSubmitResponse( 583 void ChromeToMobileService::HandleSubmitResponse(
571 const net::URLFetcher* source) { 584 const net::URLFetcher* source) {
572 // Get the observer for this response; bail if there is none or it is NULL. 585 // Get the observer for this response; bail if there is none or it is NULL.
(...skipping 24 matching lines...) Expand all
597 610
598 // Ensure a second response is not sent after reporting failure below. 611 // Ensure a second response is not sent after reporting failure below.
599 request_observer_map_.erase(other); 612 request_observer_map_.erase(other);
600 break; 613 break;
601 } 614 }
602 } 615 }
603 616
604 LogMetric(success ? SEND_SUCCESS : SEND_ERROR); 617 LogMetric(success ? SEND_SUCCESS : SEND_ERROR);
605 observer->OnSendComplete(success); 618 observer->OnSendComplete(success);
606 } 619 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698