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

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: Sync and rebase; merge invalidation API changes. 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"
45 47
46 namespace { 48 namespace {
47 49
48 // The default enabled/disabled state of the Chrome To Mobile feature. 50 // The default enabled/disabled state of the Chrome To Mobile feature.
49 const bool kChromeToMobileEnabled = true; 51 const bool kChromeToMobileEnabled = true;
50 52
51 // The maximum number of retries for the URLFetcher requests. 53 // The maximum number of retries for the URLFetcher requests.
52 const size_t kMaxRetries = 1; 54 const size_t kMaxRetries = 1;
53 55
54 // The number of hours to delay before retrying authentication on failure. 56 // The number of hours to delay before retrying authentication on failure.
55 const size_t kAuthRetryDelayHours = 6; 57 const size_t kAuthRetryDelayHours = 6;
56 58
57 // The number of hours before subsequent search requests are allowed. 59 // The number of hours before subsequent search requests are allowed.
58 // This value is used to throttle expensive cloud print search requests. 60 // This value is used to throttle expensive cloud print search requests.
59 // Note that this limitation does not hold across application restarts. 61 // Note that this limitation does not hold across application restarts.
60 const int kSearchRequestDelayHours = 24; 62 const int kSearchRequestDelayHours = 24;
61 63
64 // The sync invalidation object ID for Chrome to Mobile's mobile device list.
65 // Meaning: "U" == "User", "CM" == "Chrome to Mobile", "MLST" == "Mobile LiST".
66 const char kSyncInvalidationObjectIdChromeToMobileDeviceList[] = "UCMMLST";
67
62 // The cloud print OAuth2 scope and 'printer' type of compatible mobile devices. 68 // The cloud print OAuth2 scope and 'printer' type of compatible mobile devices.
63 const char kCloudPrintAuth[] = "https://www.googleapis.com/auth/cloudprint"; 69 const char kCloudPrintAuth[] = "https://www.googleapis.com/auth/cloudprint";
64 const char kTypeAndroid[] = "ANDROID_CHROME_SNAPSHOT"; 70 const char kTypeAndroid[] = "ANDROID_CHROME_SNAPSHOT";
65 const char kTypeIOS[] = "IOS_CHROME_SNAPSHOT"; 71 const char kTypeIOS[] = "IOS_CHROME_SNAPSHOT";
66 72
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. 73 // The Chrome To Mobile requestor type; used by services for filtering.
76 const char kChromeToMobileRequestor[] = "requestor=chrome-to-mobile"; 74 const char kChromeToMobileRequestor[] = "requestor=chrome-to-mobile";
77 75
78 // Get the job type string for a cloud print job submission. 76 // Get the job type string for a cloud print job submission.
79 std::string GetType(const ChromeToMobileService::JobData& data) { 77 std::string GetType(const ChromeToMobileService::JobData& data) {
80 if (data.type == ChromeToMobileService::URL) 78 if (data.type == ChromeToMobileService::URL)
81 return "url"; 79 return "url";
82 if (data.type == ChromeToMobileService::DELAYED_SNAPSHOT) 80 if (data.type == ChromeToMobileService::DELAYED_SNAPSHOT)
83 return "url_with_delayed_snapshot"; 81 return "url_with_delayed_snapshot";
84 DCHECK_EQ(data.type, ChromeToMobileService::SNAPSHOT); 82 DCHECK_EQ(data.type, ChromeToMobileService::SNAPSHOT);
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
171 if (command_line->HasSwitch(switches::kEnableChromeToMobile)) 169 if (command_line->HasSwitch(switches::kEnableChromeToMobile))
172 return true; 170 return true;
173 171
174 return kChromeToMobileEnabled; 172 return kChromeToMobileEnabled;
175 } 173 }
176 174
177 // static 175 // static
178 void ChromeToMobileService::RegisterUserPrefs(PrefService* prefs) { 176 void ChromeToMobileService::RegisterUserPrefs(PrefService* prefs) {
179 prefs->RegisterListPref(prefs::kChromeToMobileDeviceList, 177 prefs->RegisterListPref(prefs::kChromeToMobileDeviceList,
180 PrefService::UNSYNCABLE_PREF); 178 PrefService::UNSYNCABLE_PREF);
181 prefs->RegisterInt64Pref(prefs::kChromeToMobileTimestamp, 0,
182 PrefService::UNSYNCABLE_PREF);
183 } 179 }
184 180
185 ChromeToMobileService::ChromeToMobileService(Profile* profile) 181 ChromeToMobileService::ChromeToMobileService(Profile* profile)
186 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), 182 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)),
187 profile_(profile), 183 profile_(profile),
184 sync_invalidation_enabled_(false),
188 cloud_print_url_(new CloudPrintURL(profile)), 185 cloud_print_url_(new CloudPrintURL(profile)),
189 cloud_print_accessible_(false) { 186 request_search_when_accessible_(false) {
190 // Skip initialization if constructed without a profile. 187 // TODO(msw): Fix GMock tests, which lack profiles (http://crbug.com/122183).
191 if (profile_) { 188 if (profile_) {
192 // Get an access token as soon as the Gaia login refresh token is available. 189 ProfileSyncService* profile_sync_service =
193 TokenService* service = TokenServiceFactory::GetForProfile(profile_); 190 ProfileSyncServiceFactory::GetForProfile(profile_);
194 registrar_.Add(this, chrome::NOTIFICATION_TOKEN_AVAILABLE, 191 profile_sync_service->RegisterInvalidationHandler(this);
195 content::Source<TokenService>(service)); 192 syncer::ObjectIdSet ids;
196 if (service->HasOAuthLoginToken()) 193 ids.insert(invalidation::ObjectId(
197 RefreshAccessToken(); 194 ipc::invalidation::ObjectSource::CHROME_COMPONENTS,
195 kSyncInvalidationObjectIdChromeToMobileDeviceList));
196 profile_sync_service->UpdateRegisteredInvalidationIds(this, ids);
akalin 2012/08/13 22:23:58 what's the code path where chrome to phone is disa
msw 2012/08/16 02:41:51 It's tied to sync invalidation (presuming commandl
197 // TODO(msw): Use IsSyncEnabled? Is OnNotificationsEnabled called now?
akalin 2012/08/13 22:23:58 don't use IsSyncEnabled. I plan to have OnNotific
msw 2012/08/16 02:41:51 Done. OnNotificationsEnabled seems to be called al
198 sync_invalidation_enabled_ = profile_sync_service->IsSyncEnabled();
198 } 199 }
200 UpdateCommandState();
199 } 201 }
200 202
201 ChromeToMobileService::~ChromeToMobileService() { 203 ChromeToMobileService::~ChromeToMobileService() {
202 while (!snapshots_.empty()) 204 while (!snapshots_.empty())
203 DeleteSnapshot(*snapshots_.begin()); 205 DeleteSnapshot(*snapshots_.begin());
206 if (profile_)
akalin 2012/08/13 22:23:58 i think you can omit braces only if the 'then' sta
msw 2012/08/16 02:41:51 Done.
207 ProfileSyncServiceFactory::GetForProfile(profile_)->
208 UnregisterInvalidationHandler(this);
204 } 209 }
205 210
206 bool ChromeToMobileService::HasMobiles() { 211 bool ChromeToMobileService::HasMobiles() const {
207 return !GetMobiles()->empty(); 212 return sync_invalidation_enabled_ && !GetMobiles()->empty();
208 } 213 }
209 214
210 const base::ListValue* ChromeToMobileService::GetMobiles() const { 215 const base::ListValue* ChromeToMobileService::GetMobiles() const {
216 if (!sync_invalidation_enabled_)
217 return NULL;
218
211 return profile_->GetPrefs()->GetList(prefs::kChromeToMobileDeviceList); 219 return profile_->GetPrefs()->GetList(prefs::kChromeToMobileDeviceList);
212 } 220 }
213 221
214 void ChromeToMobileService::RequestMobileListUpdate() { 222 void ChromeToMobileService::RequestMobileListUpdate() {
215 if (access_token_.empty()) 223 if (!sync_invalidation_enabled_)
224 return;
225
226 if (access_token_.empty()) {
227 request_search_when_accessible_ = true;
216 RefreshAccessToken(); 228 RefreshAccessToken();
217 else if (cloud_print_accessible_) 229 } else {
218 RequestSearch(); 230 RequestSearch();
231 }
219 } 232 }
220 233
221 void ChromeToMobileService::GenerateSnapshot(Browser* browser, 234 void ChromeToMobileService::GenerateSnapshot(Browser* browser,
222 base::WeakPtr<Observer> observer) { 235 base::WeakPtr<Observer> observer) {
223 // Callback SnapshotFileCreated from CreateSnapshotFile to continue. 236 // Callback SnapshotFileCreated from CreateSnapshotFile to continue.
224 CreateSnapshotFileCallback callback = 237 CreateSnapshotFileCallback callback =
225 base::Bind(&ChromeToMobileService::SnapshotFileCreated, 238 base::Bind(&ChromeToMobileService::SnapshotFileCreated,
226 weak_ptr_factory_.GetWeakPtr(), observer, 239 weak_ptr_factory_.GetWeakPtr(), observer,
227 browser->session_id().id()); 240 browser->session_id().id());
228 // Create a temporary file via the blocking pool for snapshot storage. 241 // Create a temporary file via the blocking pool for snapshot storage.
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
285 } 298 }
286 299
287 void ChromeToMobileService::LearnMore(Browser* browser) const { 300 void ChromeToMobileService::LearnMore(Browser* browser) const {
288 LogMetric(LEARN_MORE_CLICKED); 301 LogMetric(LEARN_MORE_CLICKED);
289 chrome::NavigateParams params(browser, 302 chrome::NavigateParams params(browser,
290 GURL(chrome::kChromeToMobileLearnMoreURL), content::PAGE_TRANSITION_LINK); 303 GURL(chrome::kChromeToMobileLearnMoreURL), content::PAGE_TRANSITION_LINK);
291 params.disposition = NEW_FOREGROUND_TAB; 304 params.disposition = NEW_FOREGROUND_TAB;
292 chrome::Navigate(&params); 305 chrome::Navigate(&params);
293 } 306 }
294 307
295 void ChromeToMobileService::OnURLFetchComplete( 308 void ChromeToMobileService::OnURLFetchComplete(const net::URLFetcher* source) {
296 const net::URLFetcher* source) { 309 if (source == search_request_.get())
297 if (source == account_info_request_.get())
298 HandleAccountInfoResponse();
299 else if (source == search_request_.get())
300 HandleSearchResponse(); 310 HandleSearchResponse();
301 else 311 else
302 HandleSubmitResponse(source); 312 HandleSubmitResponse(source);
303 } 313 }
304 314
305 void ChromeToMobileService::Observe( 315 void ChromeToMobileService::Observe(
306 int type, 316 int type,
307 const content::NotificationSource& source, 317 const content::NotificationSource& source,
308 const content::NotificationDetails& details) { 318 const content::NotificationDetails& details) {
309 DCHECK_EQ(type, chrome::NOTIFICATION_TOKEN_AVAILABLE); 319 DCHECK_EQ(type, chrome::NOTIFICATION_TOKEN_AVAILABLE);
310 TokenService::TokenAvailableDetails* token_details = 320 TokenService::TokenAvailableDetails* token_details =
311 content::Details<TokenService::TokenAvailableDetails>(details).ptr(); 321 content::Details<TokenService::TokenAvailableDetails>(details).ptr();
322 // Update the cloud print access token on Gaia login refresh token updates.
312 if (token_details->service() == GaiaConstants::kGaiaOAuth2LoginRefreshToken) 323 if (token_details->service() == GaiaConstants::kGaiaOAuth2LoginRefreshToken)
313 RefreshAccessToken(); 324 RefreshAccessToken();
314 } 325 }
315 326
316 void ChromeToMobileService::OnGetTokenSuccess( 327 void ChromeToMobileService::OnGetTokenSuccess(
317 const std::string& access_token, 328 const std::string& access_token,
318 const base::Time& expiration_time) { 329 const base::Time& expiration_time) {
319 DCHECK(!access_token.empty()); 330 DCHECK(!access_token.empty());
320 access_token_fetcher_.reset(); 331 access_token_fetcher_.reset();
321 auth_retry_timer_.Stop(); 332 auth_retry_timer_.Stop();
322 access_token_ = access_token; 333 access_token_ = access_token;
323 RequestAccountInfo(); 334
335 if (request_search_when_accessible_) {
336 request_search_when_accessible_ = false;
337 RequestSearch();
338 }
324 } 339 }
325 340
326 void ChromeToMobileService::OnGetTokenFailure( 341 void ChromeToMobileService::OnGetTokenFailure(
327 const GoogleServiceAuthError& error) { 342 const GoogleServiceAuthError& error) {
328 access_token_fetcher_.reset(); 343 access_token_fetcher_.reset();
329 auth_retry_timer_.Stop(); 344 auth_retry_timer_.Stop();
330 auth_retry_timer_.Start( 345 auth_retry_timer_.Start(
331 FROM_HERE, base::TimeDelta::FromHours(kAuthRetryDelayHours), 346 FROM_HERE, base::TimeDelta::FromHours(kAuthRetryDelayHours),
332 this, &ChromeToMobileService::RefreshAccessToken); 347 this, &ChromeToMobileService::RefreshAccessToken);
333 } 348 }
334 349
350 void ChromeToMobileService::OnNotificationsEnabled() {
351 // Only enable Chrome To Mobile if Sync Invalidation Notification are enabled.
352 // Otherwise, the device list may be out of date and result in send failures.
353 sync_invalidation_enabled_ = true;
354 UpdateCommandState();
355 }
356
357 void ChromeToMobileService::OnNotificationsDisabled(
358 syncer::NotificationsDisabledReason reason) {
359 // Only enable Chrome To Mobile if Sync Invalidation Notification are enabled.
360 // Otherwise, the device list may be out of date and result in send failures.
361 sync_invalidation_enabled_ = false;
362 UpdateCommandState();
363 }
364
365 void ChromeToMobileService::OnIncomingNotification(
366 const syncer::ObjectIdPayloadMap& id_payloads,
367 syncer::IncomingNotificationSource source) {
368 DCHECK(sync_invalidation_enabled_);
akalin 2012/08/13 22:23:58 i don't know if this should be a DCHECK. The API
msw 2012/08/16 02:41:51 Odd; then I'll just use it to gate the feature w/[
369 DCHECK_EQ(id_payloads.size(), 1U);
370 DCHECK_EQ(id_payloads.count(invalidation::ObjectId(
371 ipc::invalidation::ObjectSource::CHROME_COMPONENTS,
372 kSyncInvalidationObjectIdChromeToMobileDeviceList)), 1U);
373 RequestMobileListUpdate();
374 }
375
376 // TODO(msw): Audit location bar code that checks enabled/disabled...
377 void ChromeToMobileService::UpdateCommandState() const {
378 // Ensure the feature is not disabled by commandline options.
379 DCHECK(IsChromeToMobileEnabled());
380 const bool has_mobiles = HasMobiles();
381 for (BrowserList::const_iterator i = BrowserList::begin();
382 i != BrowserList::end(); ++i) {
383 Browser* browser = *i;
384 if (browser->profile() == profile_)
385 browser->command_controller()->SendToMobileStateChanged(has_mobiles);
386 }
387 }
388
335 void ChromeToMobileService::SnapshotFileCreated( 389 void ChromeToMobileService::SnapshotFileCreated(
336 base::WeakPtr<Observer> observer, 390 base::WeakPtr<Observer> observer,
337 SessionID::id_type browser_id, 391 SessionID::id_type browser_id,
338 const FilePath& path, 392 const FilePath& path,
339 bool success) { 393 bool success) {
340 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 394 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
341 // Track the set of temporary files to be deleted later. 395 // Track the set of temporary files to be deleted later.
342 snapshots_.insert(path); 396 snapshots_.insert(path);
343 397
344 Browser* browser = browser::FindBrowserWithID(browser_id); 398 Browser* browser = browser::FindBrowserWithID(browser_id);
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
406 } 460 }
407 cloud_print::AddMultipartValueForUpload("content", file, bound, 461 cloud_print::AddMultipartValueForUpload("content", file, bound,
408 "text/mhtml", &post); 462 "text/mhtml", &post);
409 463
410 post.append("--" + bound + "--\r\n"); 464 post.append("--" + bound + "--\r\n");
411 request->SetUploadData("multipart/form-data; boundary=" + bound, post); 465 request->SetUploadData("multipart/form-data; boundary=" + bound, post);
412 request->Start(); 466 request->Start();
413 } 467 }
414 468
415 void ChromeToMobileService::RefreshAccessToken() { 469 void ChromeToMobileService::RefreshAccessToken() {
416 if (access_token_fetcher_.get()) 470 // Register to observe Gaia login refresh token updates.
417 return; 471 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
472 if (registrar_.IsEmpty())
473 registrar_.Add(this, chrome::NOTIFICATION_TOKEN_AVAILABLE,
474 content::Source<TokenService>(token_service));
418 475
419 std::string token = TokenServiceFactory::GetForProfile(profile_)-> 476 // Deny concurrent requests and bail without a valid Gaia login refresh token.
420 GetOAuth2LoginRefreshToken(); 477 if (access_token_fetcher_.get() || !token_service->HasOAuthLoginToken())
421 if (token.empty())
422 return; 478 return;
423 479
424 auth_retry_timer_.Stop(); 480 auth_retry_timer_.Stop();
425 access_token_fetcher_.reset( 481 access_token_fetcher_.reset(
426 new OAuth2AccessTokenFetcher(this, profile_->GetRequestContext())); 482 new OAuth2AccessTokenFetcher(this, profile_->GetRequestContext()));
427 std::vector<std::string> scopes(1, kCloudPrintAuth);
428 GaiaUrls* gaia_urls = GaiaUrls::GetInstance(); 483 GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
429 access_token_fetcher_->Start(gaia_urls->oauth2_chrome_client_id(), 484 access_token_fetcher_->Start(gaia_urls->oauth2_chrome_client_id(),
430 gaia_urls->oauth2_chrome_client_secret(), token, scopes); 485 gaia_urls->oauth2_chrome_client_secret(),
431 } 486 token_service->GetOAuth2LoginRefreshToken(),
432 487 std::vector<std::string>(1, kCloudPrintAuth));
433 void ChromeToMobileService::RequestAccountInfo() {
434 // Deny concurrent requests.
435 if (account_info_request_.get())
436 return;
437
438 std::string url_string = StringPrintf(kAccountInfoURL,
439 base::GenerateGUID().c_str(), kChromeToMobileRequestor);
440 GURL url(url_string);
441
442 // Account information is read from the profile's cookie. If cookies are
443 // blocked, access cloud print directly to list any potential devices.
444 scoped_refptr<CookieSettings> cookie_settings =
445 CookieSettings::Factory::GetForProfile(profile_);
446 if (cookie_settings && !cookie_settings->IsReadingCookieAllowed(url, url)) {
447 cloud_print_accessible_ = true;
448 RequestMobileListUpdate();
449 return;
450 }
451
452 account_info_request_.reset(
453 net::URLFetcher::Create(url, net::URLFetcher::GET, this));
454 account_info_request_->SetRequestContext(profile_->GetRequestContext());
455 account_info_request_->SetMaxRetries(kMaxRetries);
456 // This request sends the user's cookie to check the cloud print service flag.
457 account_info_request_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES);
458 account_info_request_->Start();
459 } 488 }
460 489
461 void ChromeToMobileService::RequestSearch() { 490 void ChromeToMobileService::RequestSearch() {
491 DCHECK(sync_invalidation_enabled_);
462 DCHECK(!access_token_.empty()); 492 DCHECK(!access_token_.empty());
463 493
464 // Deny requests if cloud print is inaccessible, and deny concurrent requests. 494 // Deny concurrent requests.
465 if (!cloud_print_accessible_ || search_request_.get()) 495 if (search_request_.get())
466 return;
467
468 PrefService* prefs = profile_->GetPrefs();
469 base::TimeTicks previous_search_time = base::TimeTicks::FromInternalValue(
470 prefs->GetInt64(prefs::kChromeToMobileTimestamp));
471
472 // Deny requests before the delay period has passed since the last request.
473 base::TimeDelta elapsed_time = base::TimeTicks::Now() - previous_search_time;
474 if (!previous_search_time.is_null() &&
475 elapsed_time.InHours() < kSearchRequestDelayHours)
476 return; 496 return;
477 497
478 LogMetric(DEVICES_REQUESTED); 498 LogMetric(DEVICES_REQUESTED);
479 499
480 const GURL service_url(cloud_print_url_->GetCloudPrintServiceURL()); 500 const GURL service_url(cloud_print_url_->GetCloudPrintServiceURL());
481 search_request_.reset(net::URLFetcher::Create(GetSearchURL(service_url), 501 search_request_.reset(net::URLFetcher::Create(GetSearchURL(service_url),
482 net::URLFetcher::GET, this)); 502 net::URLFetcher::GET, this));
483 InitRequest(search_request_.get()); 503 InitRequest(search_request_.get());
484 search_request_->Start(); 504 search_request_->Start();
485 } 505 }
486 506
487 void ChromeToMobileService::HandleAccountInfoResponse() {
488 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
489
490 std::string data;
491 account_info_request_->GetResponseAsString(&data);
492 account_info_request_.reset();
493
494 ListValue* services = NULL;
495 DictionaryValue* dictionary = NULL;
496 scoped_ptr<Value> json(base::JSONReader::Read(data));
497 StringValue cloud_print_service(kCloudPrintSerivceValue);
498 if (json.get() && json->GetAsDictionary(&dictionary) && dictionary &&
499 dictionary->GetList(kAccountServicesKey, &services) && services &&
500 services->Find(cloud_print_service) != services->end()) {
501 cloud_print_accessible_ = true;
502 RequestMobileListUpdate();
503 }
504 }
505
506 void ChromeToMobileService::HandleSearchResponse() { 507 void ChromeToMobileService::HandleSearchResponse() {
507 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 508 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
508 509
509 std::string data; 510 std::string data;
510 search_request_->GetResponseAsString(&data); 511 search_request_->GetResponseAsString(&data);
511 search_request_.reset(); 512 search_request_.reset();
512 513
514 // TODO(msw): Ackowledge the sync invalidation when API exists.
515 // TODO(msw): Detect, log, potentially retry on failure / bad responses.
516 // TODO(msw): Handle removing all devices or cloud print account altogether.
517
513 ListValue* list = NULL; 518 ListValue* list = NULL;
514 DictionaryValue* dictionary = NULL; 519 DictionaryValue* dictionary = NULL;
515 scoped_ptr<Value> json(base::JSONReader::Read(data)); 520 scoped_ptr<Value> json(base::JSONReader::Read(data));
516 if (json.get() && json->GetAsDictionary(&dictionary) && dictionary && 521 if (json.get() && json->GetAsDictionary(&dictionary) && dictionary &&
517 dictionary->GetList(cloud_print::kPrinterListValue, &list)) { 522 dictionary->GetList(cloud_print::kPrinterListValue, &list)) {
518 ListValue mobiles; 523 ListValue mobiles;
519 std::string type, name, id; 524 std::string type, name, id;
520 DictionaryValue* printer = NULL; 525 DictionaryValue* printer = NULL;
521 DictionaryValue* mobile = NULL; 526 DictionaryValue* mobile = NULL;
522 for (size_t index = 0; index < list->GetSize(); ++index) { 527 for (size_t index = 0; index < list->GetSize(); ++index) {
523 if (list->GetDictionary(index, &printer) && 528 if (list->GetDictionary(index, &printer) &&
524 printer->GetString("type", &type) && 529 printer->GetString("type", &type) &&
525 (type.compare(kTypeAndroid) == 0 || type.compare(kTypeIOS) == 0)) { 530 (type.compare(kTypeAndroid) == 0 || type.compare(kTypeIOS) == 0)) {
526 // Copy just the requisite values from the full |printer| definition. 531 // Copy just the requisite values from the full |printer| definition.
527 if (printer->GetString("name", &name) && 532 if (printer->GetString("name", &name) &&
528 printer->GetString("id", &id)) { 533 printer->GetString("id", &id)) {
529 mobile = new DictionaryValue(); 534 mobile = new DictionaryValue();
530 mobile->SetString("type", type); 535 mobile->SetString("type", type);
531 mobile->SetString("name", name); 536 mobile->SetString("name", name);
532 mobile->SetString("id", id); 537 mobile->SetString("id", id);
533 mobiles.Append(mobile); 538 mobiles.Append(mobile);
534 } else { 539 } else {
535 NOTREACHED(); 540 NOTREACHED();
536 } 541 }
537 } 542 }
538 } 543 }
539 544
540 // Update the mobile list and timestamp in prefs. 545 // Update the cached mobile device list in profile prefs.
541 PrefService* prefs = profile_->GetPrefs(); 546 profile_->GetPrefs()->Set(prefs::kChromeToMobileDeviceList, mobiles);
542 prefs->Set(prefs::kChromeToMobileDeviceList, mobiles);
543 prefs->SetInt64(prefs::kChromeToMobileTimestamp,
544 base::TimeTicks::Now().ToInternalValue());
545 547
546 const bool has_mobiles = HasMobiles(); 548 if (HasMobiles())
547 if (has_mobiles)
548 LogMetric(DEVICES_AVAILABLE); 549 LogMetric(DEVICES_AVAILABLE);
549 550 UpdateCommandState();
550 for (BrowserList::const_iterator i = BrowserList::begin();
551 i != BrowserList::end(); ++i) {
552 Browser* browser = *i;
553 if (browser->profile() == profile_)
554 browser->command_controller()->SendToMobileStateChanged(has_mobiles);
555 }
556 } 551 }
557 } 552 }
558 553
559 void ChromeToMobileService::HandleSubmitResponse( 554 void ChromeToMobileService::HandleSubmitResponse(
560 const net::URLFetcher* source) { 555 const net::URLFetcher* source) {
561 // Get the observer for this response; bail if there is none or it is NULL. 556 // Get the observer for this response; bail if there is none or it is NULL.
562 RequestObserverMap::iterator i = request_observer_map_.find(source); 557 RequestObserverMap::iterator i = request_observer_map_.find(source);
563 if (i == request_observer_map_.end()) 558 if (i == request_observer_map_.end())
564 return; 559 return;
565 base::WeakPtr<Observer> observer = i->second; 560 base::WeakPtr<Observer> observer = i->second;
(...skipping 20 matching lines...) Expand all
586 581
587 // Ensure a second response is not sent after reporting failure below. 582 // Ensure a second response is not sent after reporting failure below.
588 request_observer_map_.erase(other); 583 request_observer_map_.erase(other);
589 break; 584 break;
590 } 585 }
591 } 586 }
592 587
593 LogMetric(success ? SEND_SUCCESS : SEND_ERROR); 588 LogMetric(success ? SEND_SUCCESS : SEND_ERROR);
594 observer->OnSendComplete(success); 589 observer->OnSendComplete(success);
595 } 590 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698