diff options
author | msw@chromium.org <msw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-21 20:01:31 +0000 |
---|---|---|
committer | msw@chromium.org <msw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-21 20:01:31 +0000 |
commit | 7911431b57acda42db3ec127aef6a5714854edab (patch) | |
tree | 83076a1e7b026a71b270c265b8b20f2c8bd3b8ad | |
parent | dda29c94364d6dd8896f64032dcc2561a8a217c9 (diff) | |
download | chromium_src-7911431b57acda42db3ec127aef6a5714854edab.zip chromium_src-7911431b57acda42db3ec127aef6a5714854edab.tar.gz chromium_src-7911431b57acda42db3ec127aef6a5714854edab.tar.bz2 |
Revert 152609 - Integrate invalidation API into ChromeToMobileService.
Failed? Win7 Tests (dbg)(6) browser_tests InProcessBrowserTest.Empty:
http://build.chromium.org/p/chromium/builders/Win7%20Tests%20%28dbg%29%286%29/builds/10278/steps/browser_tests/logs/stdio
Update chrome/browser/DEPS with new dependencies:
(google/cacheinvalidation and sync/notifier)
Observe Sync Notifier invalidation notifications:
(depend on this service for mobile list updates)
(refresh the device list on cloud print invalidation)
Remove RequestMobileListUpdate, timestamp, & account info:
(no longer needed with invalidation integration)
(just set command state and icon visibility w/HasMobiles)
Lazily init the access token, queue search/send operations:
(only get an access token as needed, add |task_queue_|)
Allow concurrent cloud print device search requests:
(handle user-triggered updates while fetching the list)
Misc cleanup (CloudPrintUrl handling, tests, etc.)
TODO(followup): Additional logging, tests, invalidation ack.
BUG=102709,137086
Review URL: https://chromiumcodereview.appspot.com/10834203
TBR=msw@chromium.org
Review URL: https://chromiumcodereview.appspot.com/10861038
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@152613 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/DEPS | 2 | ||||
-rw-r--r-- | chrome/browser/chrome_to_mobile_service.cc | 239 | ||||
-rw-r--r-- | chrome/browser/chrome_to_mobile_service.h | 49 | ||||
-rw-r--r-- | chrome/browser/chrome_to_mobile_service_factory.cc | 4 | ||||
-rw-r--r-- | chrome/browser/chrome_to_mobile_service_factory.h | 1 | ||||
-rw-r--r-- | chrome/browser/chrome_to_mobile_service_unittest.cc | 19 | ||||
-rw-r--r-- | chrome/browser/ui/cocoa/chrome_to_mobile_bubble_controller.mm | 5 | ||||
-rw-r--r-- | chrome/browser/ui/cocoa/chrome_to_mobile_bubble_controller_unittest.mm | 16 | ||||
-rw-r--r-- | chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm | 3 | ||||
-rw-r--r-- | chrome/browser/ui/gtk/chrome_to_mobile_bubble_gtk.cc | 8 | ||||
-rw-r--r-- | chrome/browser/ui/gtk/location_bar_view_gtk.cc | 5 | ||||
-rw-r--r-- | chrome/browser/ui/views/chrome_to_mobile_bubble_view.cc | 5 | ||||
-rw-r--r-- | chrome/browser/ui/views/location_bar/location_bar_view.cc | 8 | ||||
-rw-r--r-- | chrome/common/pref_names.cc | 3 | ||||
-rw-r--r-- | chrome/common/pref_names.h | 1 |
15 files changed, 182 insertions, 186 deletions
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS index e0a75e7..775f092 100644 --- a/chrome/browser/DEPS +++ b/chrome/browser/DEPS @@ -5,7 +5,6 @@ include_rules = [ "+chrome/tools/profiles", # For history unit tests. "+chromeos", "+content/public/browser", - "+google/cacheinvalidation", # Sync invalidation API protobuf files. "+google_update", "+grit", # For generated headers "+installer_util_strings", # For generated headers @@ -21,7 +20,6 @@ include_rules = [ "+skia/ext", "+skia/include", "+sync/api", # Sync API files. - "+sync/notifier", # Sync invalidation API files. "+sync/protocol", # Sync protobuf files. "+third_party/cros_system_api", "+webkit/database", diff --git a/chrome/browser/chrome_to_mobile_service.cc b/chrome/browser/chrome_to_mobile_service.cc index 17d7d32..bc80c39 100644 --- a/chrome/browser/chrome_to_mobile_service.cc +++ b/chrome/browser/chrome_to_mobile_service.cc @@ -11,15 +11,15 @@ #include "base/json/json_reader.h" #include "base/json/json_writer.h" #include "base/metrics/histogram.h" +#include "base/stringprintf.h" #include "base/utf_string_conversions.h" #include "chrome/app/chrome_command_ids.h" +#include "chrome/browser/content_settings/cookie_settings.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/printing/cloud_print/cloud_print_url.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/signin/token_service.h" #include "chrome/browser/signin/token_service_factory.h" -#include "chrome/browser/sync/profile_sync_service.h" -#include "chrome/browser/sync/profile_sync_service_factory.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_command_controller.h" #include "chrome/browser/ui/browser_finder.h" @@ -38,13 +38,10 @@ #include "content/public/browser/notification_details.h" #include "content/public/browser/notification_source.h" #include "content/public/browser/web_contents.h" -#include "google/cacheinvalidation/include/types.h" -#include "google/cacheinvalidation/types.pb.h" #include "net/base/escape.h" #include "net/base/load_flags.h" #include "net/url_request/url_fetcher.h" #include "net/url_request/url_request_context_getter.h" -#include "sync/notifier/invalidation_util.h" namespace { @@ -62,16 +59,19 @@ const size_t kAuthRetryDelayHours = 6; // Note that this limitation does not hold across application restarts. const int kSearchRequestDelayHours = 24; -// The sync invalidation object ID for Chrome to Mobile's mobile device list. -// This corresponds with cloud print's server-side invalidation object ID. -// Meaning: "U" == "User", "CM" == "Chrome to Mobile", "MLST" == "Mobile LiST". -const char kSyncInvalidationObjectIdChromeToMobileDeviceList[] = "UCMMLST"; - // The cloud print OAuth2 scope and 'printer' type of compatible mobile devices. const char kCloudPrintAuth[] = "https://www.googleapis.com/auth/cloudprint"; const char kTypeAndroid[] = "ANDROID_CHROME_SNAPSHOT"; const char kTypeIOS[] = "IOS_CHROME_SNAPSHOT"; +// The account info URL pattern and strings to check for cloud print access. +// The 'key=' query parameter is used for caching; supply a random number. +// The 'rv=2' query parameter requests a JSON response; use 'rv=1' for XML. +const char kAccountInfoURL[] = + "https://clients1.google.com/tbproxy/getaccountinfo?key=%s&rv=2&%s"; +const char kAccountServicesKey[] = "services"; +const char kCloudPrintSerivceValue[] = "cprt"; + // The Chrome To Mobile requestor type; used by services for filtering. const char kChromeToMobileRequestor[] = "requestor=chrome-to-mobile"; @@ -125,8 +125,8 @@ void AddValue(const std::string& value_name, } // Get the URL for cloud print device search; appends a requestor query param. -GURL GetSearchURL(const GURL& cloud_print_url) { - GURL search_url = cloud_print::GetUrlForSearch(cloud_print_url); +GURL GetSearchURL(const GURL& service_url) { + GURL search_url = cloud_print::GetUrlForSearch(service_url); GURL::Replacements replacements; std::string query(kChromeToMobileRequestor); replacements.SetQueryStr(query); @@ -180,48 +180,44 @@ bool ChromeToMobileService::IsChromeToMobileEnabled() { void ChromeToMobileService::RegisterUserPrefs(PrefService* prefs) { prefs->RegisterListPref(prefs::kChromeToMobileDeviceList, PrefService::UNSYNCABLE_PREF); + prefs->RegisterInt64Pref(prefs::kChromeToMobileTimestamp, 0, + PrefService::UNSYNCABLE_PREF); } ChromeToMobileService::ChromeToMobileService(Profile* profile) : ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), profile_(profile), - sync_invalidation_enabled_(false) { - // TODO(msw): Unit tests do not provide profiles; see http://crbug.com/122183 - ProfileSyncService* profile_sync_service = - profile_ ? ProfileSyncServiceFactory::GetForProfile(profile_) : NULL; - if (profile_sync_service) { - CloudPrintURL cloud_print_url(profile_); - cloud_print_url_ = cloud_print_url.GetCloudPrintServiceURL(); - // Register for cloud print device list invalidation notifications. - // TODO(msw|akalin): Initialize |sync_invalidation_enabled_| properly. - profile_sync_service->RegisterInvalidationHandler(this); - syncer::ObjectIdSet ids; - ids.insert(invalidation::ObjectId( - ipc::invalidation::ObjectSource::CHROME_COMPONENTS, - kSyncInvalidationObjectIdChromeToMobileDeviceList)); - profile_sync_service->UpdateRegisteredInvalidationIds(this, ids); + cloud_print_url_(new CloudPrintURL(profile)), + cloud_print_accessible_(false) { + // TODO(msw): Fix GMock tests, which lack profiles (http://crbug.com/122183). + if (profile_) { + // Get an access token as soon as the Gaia login refresh token is available. + TokenService* service = TokenServiceFactory::GetForProfile(profile_); + registrar_.Add(this, chrome::NOTIFICATION_TOKEN_AVAILABLE, + content::Source<TokenService>(service)); + if (service->HasOAuthLoginToken()) + RequestAccessToken(); } } ChromeToMobileService::~ChromeToMobileService() { while (!snapshots_.empty()) DeleteSnapshot(*snapshots_.begin()); - // TODO(msw): Unit tests do not provide profiles; see http://crbug.com/122183 - // Unregister for cloud print device list invalidation notifications. - ProfileSyncService* profile_sync_service = - profile_ ? ProfileSyncServiceFactory::GetForProfile(profile_) : NULL; - if (profile_sync_service) - profile_sync_service->UnregisterInvalidationHandler(this); } bool ChromeToMobileService::HasMobiles() const { - const base::ListValue* mobiles = GetMobiles(); - return mobiles && !mobiles->empty(); + return !GetMobiles()->empty(); } const base::ListValue* ChromeToMobileService::GetMobiles() const { - return sync_invalidation_enabled_ ? - profile_->GetPrefs()->GetList(prefs::kChromeToMobileDeviceList) : NULL; + return profile_->GetPrefs()->GetList(prefs::kChromeToMobileDeviceList); +} + +void ChromeToMobileService::RequestMobileListUpdate() { + if (access_token_.empty()) + RequestAccessToken(); + else if (cloud_print_accessible_) + RequestDeviceSearch(); } void ChromeToMobileService::GenerateSnapshot(Browser* browser, @@ -238,28 +234,19 @@ void ChromeToMobileService::GenerateSnapshot(Browser* browser, } } -void ChromeToMobileService::SendToMobile(const base::DictionaryValue* mobile, +void ChromeToMobileService::SendToMobile(const base::DictionaryValue& mobile, const FilePath& snapshot, Browser* browser, base::WeakPtr<Observer> observer) { - if (access_token_.empty()) { - // Enqueue this task to perform after obtaining an access token. - task_queue_.push(base::Bind(&ChromeToMobileService::SendToMobile, - weak_ptr_factory_.GetWeakPtr(), base::Owned(mobile->DeepCopy()), - snapshot, browser, observer)); - RequestAccessToken(); - return; - } - LogMetric(SENDING_URL); JobData data; std::string mobile_os; - if (!mobile->GetString("type", &mobile_os)) + if (!mobile.GetString("type", &mobile_os)) NOTREACHED(); data.mobile_os = (mobile_os.compare(kTypeAndroid) == 0) ? ChromeToMobileService::ANDROID : ChromeToMobileService::IOS; - if (!mobile->GetString("id", &data.mobile_id)) + if (!mobile.GetString("id", &data.mobile_id)) NOTREACHED(); content::WebContents* web_contents = chrome::GetActiveWebContents(browser); data.url = web_contents->GetURL(); @@ -314,9 +301,12 @@ void ChromeToMobileService::LearnMore(Browser* browser) const { chrome::Navigate(¶ms); } -void ChromeToMobileService::OnURLFetchComplete(const net::URLFetcher* source) { - if (source->GetURL() == GetSearchURL(cloud_print_url_)) - HandleSearchResponse(source); +void ChromeToMobileService::OnURLFetchComplete( + const net::URLFetcher* source) { + if (source == account_info_request_.get()) + HandleAccountInfoResponse(); + else if (source == search_request_.get()) + HandleSearchResponse(); else HandleSubmitResponse(source); } @@ -328,9 +318,8 @@ void ChromeToMobileService::Observe( DCHECK_EQ(type, chrome::NOTIFICATION_TOKEN_AVAILABLE); TokenService::TokenAvailableDetails* token_details = content::Details<TokenService::TokenAvailableDetails>(details).ptr(); - // Invalidate the cloud print access token on Gaia login token updates. if (token_details->service() == GaiaConstants::kGaiaOAuth2LoginRefreshToken) - access_token_.clear(); + RequestAccessToken(); } void ChromeToMobileService::OnGetTokenSuccess( @@ -340,57 +329,18 @@ void ChromeToMobileService::OnGetTokenSuccess( access_token_fetcher_.reset(); auth_retry_timer_.Stop(); access_token_ = access_token; - - while (!task_queue_.empty()) { - // Post all tasks that were queued and waiting on a valid access token. - if (!content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - task_queue_.front())) { - NOTREACHED(); - } - task_queue_.pop(); - } + RequestAccountInfo(); } void ChromeToMobileService::OnGetTokenFailure( const GoogleServiceAuthError& error) { access_token_fetcher_.reset(); auth_retry_timer_.Stop(); - auth_retry_timer_.Start( FROM_HERE, base::TimeDelta::FromHours(kAuthRetryDelayHours), this, &ChromeToMobileService::RequestAccessToken); } -void ChromeToMobileService::OnNotificationsEnabled() { - sync_invalidation_enabled_ = true; - UpdateCommandState(); -} - -void ChromeToMobileService::OnNotificationsDisabled( - syncer::NotificationsDisabledReason reason) { - sync_invalidation_enabled_ = false; - UpdateCommandState(); -} - -void ChromeToMobileService::OnIncomingNotification( - const syncer::ObjectIdPayloadMap& id_payloads, - syncer::IncomingNotificationSource source) { - DCHECK_EQ(id_payloads.size(), 1U); - DCHECK_EQ(id_payloads.count(invalidation::ObjectId( - ipc::invalidation::ObjectSource::CHROME_COMPONENTS, - kSyncInvalidationObjectIdChromeToMobileDeviceList)), 1U); - RequestDeviceSearch(); -} - -const std::string& ChromeToMobileService::GetAccessTokenForTest() const { - return access_token_; -} - -void ChromeToMobileService::SetAccessTokenForTest( - const std::string& access_token) { - access_token_ = access_token; -} - void ChromeToMobileService::UpdateCommandState() const { // Ensure the feature is not disabled by commandline options. DCHECK(IsChromeToMobileEnabled()); @@ -424,9 +374,9 @@ void ChromeToMobileService::SnapshotFileCreated( } net::URLFetcher* ChromeToMobileService::CreateRequest(const JobData& data) { + const GURL service_url(cloud_print_url_->GetCloudPrintServiceURL()); net::URLFetcher* request = net::URLFetcher::Create( - cloud_print::GetUrlForSubmit(cloud_print_url_), - net::URLFetcher::POST, this); + cloud_print::GetUrlForSubmit(service_url), net::URLFetcher::POST, this); InitRequest(request); return request; } @@ -485,13 +435,8 @@ void ChromeToMobileService::SendRequest(net::URLFetcher* request, } void ChromeToMobileService::RequestAccessToken() { - // Register to observe Gaia login refresh token updates. - TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); - if (registrar_.IsEmpty()) - registrar_.Add(this, chrome::NOTIFICATION_TOKEN_AVAILABLE, - content::Source<TokenService>(token_service)); - // Deny concurrent requests and bail without a valid Gaia login refresh token. + TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); if (access_token_fetcher_.get() || !token_service->HasOAuthLoginToken()) return; @@ -505,33 +450,86 @@ void ChromeToMobileService::RequestAccessToken() { std::vector<std::string>(1, kCloudPrintAuth)); } -void ChromeToMobileService::RequestDeviceSearch() { - DCHECK(sync_invalidation_enabled_); - if (access_token_.empty()) { - // Enqueue this task to perform after obtaining an access token. - task_queue_.push(base::Bind(&ChromeToMobileService::RequestDeviceSearch, - weak_ptr_factory_.GetWeakPtr())); - RequestAccessToken(); +void ChromeToMobileService::RequestAccountInfo() { + // Deny concurrent requests. + if (account_info_request_.get()) + return; + + std::string url_string = StringPrintf(kAccountInfoURL, + base::GenerateGUID().c_str(), kChromeToMobileRequestor); + GURL url(url_string); + + // Account information is read from the profile's cookie. If cookies are + // blocked, access cloud print directly to list any potential devices. + scoped_refptr<CookieSettings> cookie_settings = + CookieSettings::Factory::GetForProfile(profile_); + if (cookie_settings && !cookie_settings->IsReadingCookieAllowed(url, url)) { + cloud_print_accessible_ = true; + RequestMobileListUpdate(); return; } + account_info_request_.reset( + net::URLFetcher::Create(url, net::URLFetcher::GET, this)); + account_info_request_->SetRequestContext(profile_->GetRequestContext()); + account_info_request_->SetMaxRetries(kMaxRetries); + // This request sends the user's cookie to check the cloud print service flag. + account_info_request_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES); + account_info_request_->Start(); +} + +void ChromeToMobileService::RequestDeviceSearch() { + // Deny requests if cloud print is inaccessible, and deny concurrent requests. + if (!cloud_print_accessible_ || search_request_.get()) + return; + + PrefService* prefs = profile_->GetPrefs(); + base::TimeTicks previous_search_time = base::TimeTicks::FromInternalValue( + prefs->GetInt64(prefs::kChromeToMobileTimestamp)); + + // Deny requests before the delay period has passed since the last request. + base::TimeDelta elapsed_time = base::TimeTicks::Now() - previous_search_time; + if (!previous_search_time.is_null() && + elapsed_time.InHours() < kSearchRequestDelayHours) + return; + LogMetric(DEVICES_REQUESTED); - net::URLFetcher* search_request = net::URLFetcher::Create( - GetSearchURL(cloud_print_url_), net::URLFetcher::GET, this); - InitRequest(search_request); - search_request->Start(); + const GURL service_url(cloud_print_url_->GetCloudPrintServiceURL()); + search_request_.reset(net::URLFetcher::Create(GetSearchURL(service_url), + net::URLFetcher::GET, this)); + InitRequest(search_request_.get()); + search_request_->Start(); } -void ChromeToMobileService::HandleSearchResponse( - const net::URLFetcher* source) { +void ChromeToMobileService::HandleAccountInfoResponse() { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + + std::string data; + account_info_request_->GetResponseAsString(&data); + account_info_request_.reset(); + + ListValue* services = NULL; + DictionaryValue* dictionary = NULL; + scoped_ptr<Value> json(base::JSONReader::Read(data)); + StringValue cloud_print_service(kCloudPrintSerivceValue); + if (json.get() && json->GetAsDictionary(&dictionary) && dictionary && + dictionary->GetList(kAccountServicesKey, &services) && services && + services->Find(cloud_print_service) != services->end()) { + cloud_print_accessible_ = true; + RequestMobileListUpdate(); + } +} + +void ChromeToMobileService::HandleSearchResponse() { DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - DCHECK_EQ(source->GetURL(), GetSearchURL(cloud_print_url_)); std::string data; + search_request_->GetResponseAsString(&data); + search_request_.reset(); + ListValue* list = NULL; DictionaryValue* dictionary = NULL; - source->GetResponseAsString(&data); scoped_ptr<Value> json(base::JSONReader::Read(data)); if (json.get() && json->GetAsDictionary(&dictionary) && dictionary && dictionary->GetList(cloud_print::kPrinterListValue, &list)) { @@ -557,8 +555,11 @@ void ChromeToMobileService::HandleSearchResponse( } } - // Update the cached mobile device list in profile prefs. - profile_->GetPrefs()->Set(prefs::kChromeToMobileDeviceList, mobiles); + // Update the mobile list and timestamp in prefs. + PrefService* prefs = profile_->GetPrefs(); + prefs->Set(prefs::kChromeToMobileDeviceList, mobiles); + prefs->SetInt64(prefs::kChromeToMobileTimestamp, + base::TimeTicks::Now().ToInternalValue()); if (HasMobiles()) LogMetric(DEVICES_AVAILABLE); diff --git a/chrome/browser/chrome_to_mobile_service.h b/chrome/browser/chrome_to_mobile_service.h index e39b50c..3613396 100644 --- a/chrome/browser/chrome_to_mobile_service.h +++ b/chrome/browser/chrome_to_mobile_service.h @@ -6,12 +6,10 @@ #define CHROME_BROWSER_CHROME_TO_MOBILE_SERVICE_H_ #include <map> -#include <queue> #include <set> #include <string> #include <vector> -#include "base/compiler_specific.h" #include "base/file_path.h" #include "base/memory/weak_ptr.h" #include "base/string16.h" @@ -24,7 +22,6 @@ #include "content/public/browser/notification_registrar.h" #include "googleurl/src/gurl.h" #include "net/url_request/url_fetcher_delegate.h" -#include "sync/notifier/sync_notifier_observer.h" class OAuth2AccessTokenFetcher; class Browser; @@ -42,8 +39,7 @@ class URLFetcher; class ChromeToMobileService : public ProfileKeyedService, public net::URLFetcherDelegate, public content::NotificationObserver, - public OAuth2AccessTokenConsumer, - public syncer::SyncNotifierObserver { + public OAuth2AccessTokenConsumer { public: class Observer { public: @@ -116,6 +112,10 @@ class ChromeToMobileService : public ProfileKeyedService, // Virtual for unit test mocking. virtual const base::ListValue* GetMobiles() const; + // Request an updated mobile device list, request auth first if needed. + // Virtual for unit test mocking. + virtual void RequestMobileListUpdate(); + // Callback with an MHTML snapshot of the browser's selected WebContents. // Virtual for unit test mocking. virtual void GenerateSnapshot(Browser* browser, @@ -123,7 +123,7 @@ class ChromeToMobileService : public ProfileKeyedService, // Send the browser's selected WebContents to the specified mobile device. // Virtual for unit test mocking. - virtual void SendToMobile(const base::DictionaryValue* mobile, + virtual void SendToMobile(const base::DictionaryValue& mobile, const FilePath& snapshot, Browser* browser, base::WeakPtr<Observer> observer); @@ -152,18 +152,6 @@ class ChromeToMobileService : public ProfileKeyedService, const base::Time& expiration_time) OVERRIDE; virtual void OnGetTokenFailure(const GoogleServiceAuthError& error) OVERRIDE; - // syncer::SyncNotifierObserver implementation. - virtual void OnNotificationsEnabled() OVERRIDE; - virtual void OnNotificationsDisabled( - syncer::NotificationsDisabledReason reason) OVERRIDE; - virtual void OnIncomingNotification( - const syncer::ObjectIdPayloadMap& id_payloads, - syncer::IncomingNotificationSource source) OVERRIDE; - - // Expose access token accessors for test purposes. - const std::string& GetAccessTokenForTest() const; - void SetAccessTokenForTest(const std::string& access_token); - private: friend class MockChromeToMobileService; @@ -191,26 +179,25 @@ class ChromeToMobileService : public ProfileKeyedService, // Virtual for unit test mocking. virtual void RequestAccessToken(); + // Request account information to limit cloud print access to existing users. + void RequestAccountInfo(); + // Send the cloud print URLFetcher device search request. - // Virtual for unit test mocking. - virtual void RequestDeviceSearch(); + void RequestDeviceSearch(); - void HandleSearchResponse(const net::URLFetcher* source); + void HandleAccountInfoResponse(); + void HandleSearchResponse(); void HandleSubmitResponse(const net::URLFetcher* source); base::WeakPtrFactory<ChromeToMobileService> weak_ptr_factory_; Profile* profile_; - // Sync invalidation service state. Chrome To Mobile requires this service to - // to keep the mobile device list up to date and prevent page send failures. - bool sync_invalidation_enabled_; - // Used to recieve TokenService notifications for GaiaOAuth2LoginRefreshToken. content::NotificationRegistrar registrar_; - // The cloud print service URL and auth access token. - GURL cloud_print_url_; + // Cloud print helper class and auth token. + scoped_ptr<CloudPrintURL> cloud_print_url_; std::string access_token_; // The set of snapshots currently available. @@ -225,8 +212,12 @@ class ChromeToMobileService : public ProfileKeyedService, scoped_ptr<OAuth2AccessTokenFetcher> access_token_fetcher_; base::OneShotTimer<ChromeToMobileService> auth_retry_timer_; - // A queue of tasks to perform after an access token is lazily initialized. - std::queue<base::Closure> task_queue_; + // The pending account information request and the cloud print access flag. + scoped_ptr<net::URLFetcher> account_info_request_; + bool cloud_print_accessible_; + + // The pending mobile device search request. + scoped_ptr<net::URLFetcher> search_request_; DISALLOW_COPY_AND_ASSIGN(ChromeToMobileService); }; diff --git a/chrome/browser/chrome_to_mobile_service_factory.cc b/chrome/browser/chrome_to_mobile_service_factory.cc index d2c6601..1058917 100644 --- a/chrome/browser/chrome_to_mobile_service_factory.cc +++ b/chrome/browser/chrome_to_mobile_service_factory.cc @@ -5,9 +5,9 @@ #include "chrome/browser/chrome_to_mobile_service_factory.h" #include "chrome/browser/chrome_to_mobile_service.h" +#include "chrome/browser/content_settings/cookie_settings.h" #include "chrome/browser/profiles/profile_dependency_manager.h" #include "chrome/browser/signin/token_service_factory.h" -#include "chrome/browser/sync/profile_sync_service_factory.h" // static ChromeToMobileServiceFactory* ChromeToMobileServiceFactory::GetInstance() { @@ -33,8 +33,8 @@ ProfileKeyedService* ChromeToMobileServiceFactory::BuildServiceInstanceFor( ChromeToMobileServiceFactory::ChromeToMobileServiceFactory() : ProfileKeyedServiceFactory("ChromeToMobileService", ProfileDependencyManager::GetInstance()) { - DependsOn(ProfileSyncServiceFactory::GetInstance()); DependsOn(TokenServiceFactory::GetInstance()); + DependsOn(CookieSettings::Factory::GetInstance()); // TODO(msw): Uncomment this once it exists. // DependsOn(PrefServiceFactory::GetInstance()); } diff --git a/chrome/browser/chrome_to_mobile_service_factory.h b/chrome/browser/chrome_to_mobile_service_factory.h index 5232a7f..c3f62c6 100644 --- a/chrome/browser/chrome_to_mobile_service_factory.h +++ b/chrome/browser/chrome_to_mobile_service_factory.h @@ -5,7 +5,6 @@ #ifndef CHROME_BROWSER_CHROME_TO_MOBILE_SERVICE_FACTORY_H_ #define CHROME_BROWSER_CHROME_TO_MOBILE_SERVICE_FACTORY_H_ -#include "base/compiler_specific.h" #include "base/memory/singleton.h" #include "chrome/browser/profiles/profile_keyed_service_factory.h" diff --git a/chrome/browser/chrome_to_mobile_service_unittest.cc b/chrome/browser/chrome_to_mobile_service_unittest.cc index 8cff191..d1e6d41 100644 --- a/chrome/browser/chrome_to_mobile_service_unittest.cc +++ b/chrome/browser/chrome_to_mobile_service_unittest.cc @@ -17,6 +17,7 @@ const char kDummyString[] = "dummy"; class DummyNotificationSource {}; +// A mock ChromeToMobileService with a mocked out RequestAccessToken method. class MockChromeToMobileService : public ChromeToMobileService { public: MockChromeToMobileService(); @@ -49,37 +50,29 @@ ChromeToMobileServiceTest::ChromeToMobileServiceTest() {} ChromeToMobileServiceTest::~ChromeToMobileServiceTest() {} -// Ensure that irrelevant notifications do not invalidate the access token. +// Ensure that RequestAccessToken is not called for irrelevant notifications. TEST_F(ChromeToMobileServiceTest, IgnoreIrrelevantNotifications) { EXPECT_CALL(service_, RequestAccessToken()).Times(0); - service_.SetAccessTokenForTest(kDummyString); - ASSERT_FALSE(service_.GetAccessTokenForTest().empty()); - - // Send dummy service/token details (should not request token). + // Send dummy service/token details (should not refresh token). DummyNotificationSource dummy_source; TokenService::TokenAvailableDetails dummy_details(kDummyString, kDummyString); service_.Observe(chrome::NOTIFICATION_TOKEN_AVAILABLE, content::Source<DummyNotificationSource>(&dummy_source), content::Details<TokenService::TokenAvailableDetails>(&dummy_details)); - EXPECT_FALSE(service_.GetAccessTokenForTest().empty()); } -// Ensure that proper notifications invalidate the access token. +// Ensure that RequestAccessToken is called on the proper notification. TEST_F(ChromeToMobileServiceTest, AuthenticateOnTokenAvailable) { - EXPECT_CALL(service_, RequestAccessToken()).Times(0); - - service_.SetAccessTokenForTest(kDummyString); - ASSERT_FALSE(service_.GetAccessTokenForTest().empty()); + EXPECT_CALL(service_, RequestAccessToken()).Times(1); - // Send a Gaia OAuth2 Login service dummy token (should request token). + // Send a Gaia OAuth2 Login service dummy token (should refresh token). DummyNotificationSource dummy_source; TokenService::TokenAvailableDetails login_details( GaiaConstants::kGaiaOAuth2LoginRefreshToken, kDummyString); service_.Observe(chrome::NOTIFICATION_TOKEN_AVAILABLE, content::Source<DummyNotificationSource>(&dummy_source), content::Details<TokenService::TokenAvailableDetails>(&login_details)); - EXPECT_TRUE(service_.GetAccessTokenForTest().empty()); } } // namespace diff --git a/chrome/browser/ui/cocoa/chrome_to_mobile_bubble_controller.mm b/chrome/browser/ui/cocoa/chrome_to_mobile_bubble_controller.mm index 61eb57a..f8de658 100644 --- a/chrome/browser/ui/cocoa/chrome_to_mobile_bubble_controller.mm +++ b/chrome/browser/ui/cocoa/chrome_to_mobile_bubble_controller.mm @@ -165,6 +165,9 @@ void ChromeToMobileBubbleNotificationBridge::OnSendComplete(bool success) { // Generate the MHTML snapshot now to report its size in the bubble. service_->GenerateSnapshot(browser_, bridge_->AsWeakPtr()); + // Request a mobile device list update. + service_->RequestMobileListUpdate(); + [super showWindow:sender]; } @@ -184,7 +187,7 @@ void ChromeToMobileBubbleNotificationBridge::OnSendComplete(bool success) { const DictionaryValue* mobile = NULL; if (mobiles->GetDictionary(selected_index, &mobile)) { - service_->SendToMobile(mobile, + service_->SendToMobile(*mobile, ([sendCopy_ state] == NSOnState) ? snapshotPath_ : FilePath(), browser_, bridge_->AsWeakPtr()); } else { diff --git a/chrome/browser/ui/cocoa/chrome_to_mobile_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/chrome_to_mobile_bubble_controller_unittest.mm index 534a42f..c1efcb2 100644 --- a/chrome/browser/ui/cocoa/chrome_to_mobile_bubble_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/chrome_to_mobile_bubble_controller_unittest.mm @@ -19,9 +19,10 @@ class MockChromeToMobileService : public ChromeToMobileService { // ChromeToMobileService overrides: virtual const base::ListValue* GetMobiles() const OVERRIDE; + MOCK_METHOD0(RequestMobileListUpdate, void()); MOCK_METHOD2(GenerateSnapshot, void(Browser* browser, base::WeakPtr<Observer> observer)); - MOCK_METHOD4(SendToMobile, void(const base::DictionaryValue* mobile, + MOCK_METHOD4(SendToMobile, void(const base::DictionaryValue& mobile, const FilePath& snapshot, Browser* browser, base::WeakPtr<Observer> observer)); @@ -35,9 +36,7 @@ class MockChromeToMobileService : public ChromeToMobileService { void MockChromeToMobileService::AddDevices(size_t count) { for(size_t i = 0; i < count; i++) { base::DictionaryValue* device = new base::DictionaryValue(); - device->SetString("type", "Device Type"); device->SetString("name", "Device Name"); - device->SetString("id", "Device ID"); mobiles_.Append(device); } } @@ -116,9 +115,8 @@ class ChromeToMobileBubbleControllerTest : public CocoaTest { }; TEST_F(ChromeToMobileBubbleControllerTest, OneDevice) { + EXPECT_CALL(service_, RequestMobileListUpdate()); EXPECT_CALL(service_, GenerateSnapshot(NULL, testing::_)); - EXPECT_CALL(service_, SendToMobile(testing::_, testing::_, - testing::_, testing::_)).Times(0); EXPECT_CALL(service_, DeleteSnapshot(testing::_)); EXPECT_CALL(service_, LogMetric(ChromeToMobileService::BUBBLE_SHOWN)); @@ -128,9 +126,8 @@ TEST_F(ChromeToMobileBubbleControllerTest, OneDevice) { } TEST_F(ChromeToMobileBubbleControllerTest, TwoDevices) { + EXPECT_CALL(service_, RequestMobileListUpdate()); EXPECT_CALL(service_, GenerateSnapshot(NULL, testing::_)); - EXPECT_CALL(service_, SendToMobile(testing::_, testing::_, - testing::_, testing::_)).Times(0); EXPECT_CALL(service_, DeleteSnapshot(testing::_)); EXPECT_CALL(service_, LogMetric(ChromeToMobileService::BUBBLE_SHOWN)); @@ -140,9 +137,8 @@ TEST_F(ChromeToMobileBubbleControllerTest, TwoDevices) { } TEST_F(ChromeToMobileBubbleControllerTest, ThreeDevices) { + EXPECT_CALL(service_, RequestMobileListUpdate()); EXPECT_CALL(service_, GenerateSnapshot(NULL, testing::_)); - EXPECT_CALL(service_, SendToMobile(testing::_, testing::_, - testing::_, testing::_)).Times(0); EXPECT_CALL(service_, DeleteSnapshot(testing::_)); EXPECT_CALL(service_, LogMetric(ChromeToMobileService::BUBBLE_SHOWN)); @@ -153,6 +149,7 @@ TEST_F(ChromeToMobileBubbleControllerTest, ThreeDevices) { TEST_F(ChromeToMobileBubbleControllerTest, SendWithoutSnapshot) { FilePath path; + EXPECT_CALL(service_, RequestMobileListUpdate()); EXPECT_CALL(service_, GenerateSnapshot(NULL, testing::_)); EXPECT_CALL(service_, SendToMobile(testing::_, path, NULL, testing::_)); EXPECT_CALL(service_, DeleteSnapshot(testing::_)); @@ -165,6 +162,7 @@ TEST_F(ChromeToMobileBubbleControllerTest, SendWithoutSnapshot) { TEST_F(ChromeToMobileBubbleControllerTest, SendWithSnapshot) { FilePath path("path.mht"); + EXPECT_CALL(service_, RequestMobileListUpdate()); EXPECT_CALL(service_, GenerateSnapshot(NULL, testing::_)); EXPECT_CALL(service_, SendToMobile(testing::_, path, NULL, testing::_)); EXPECT_CALL(service_, DeleteSnapshot(testing::_)); diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm index e668251..54c85c5 100644 --- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm +++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm @@ -118,7 +118,8 @@ LocationBarViewMac::LocationBarViewMac( command_updater_->AddCommandObserver(IDC_CHROME_TO_MOBILE_PAGE, this); chrome_to_mobile_decoration_.reset( new ChromeToMobileDecoration(profile, command_updater)); - UpdateChromeToMobileEnabled(); + ChromeToMobileServiceFactory::GetForProfile(profile)-> + RequestMobileListUpdate(); } if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableActionBox)) { diff --git a/chrome/browser/ui/gtk/chrome_to_mobile_bubble_gtk.cc b/chrome/browser/ui/gtk/chrome_to_mobile_bubble_gtk.cc index ced3212..92a678b 100644 --- a/chrome/browser/ui/gtk/chrome_to_mobile_bubble_gtk.cc +++ b/chrome/browser/ui/gtk/chrome_to_mobile_bubble_gtk.cc @@ -160,12 +160,16 @@ ChromeToMobileBubbleGtk::ChromeToMobileBubbleGtk(GtkImage* anchor_image, // Generate the MHTML snapshot now to report its size in the bubble. service_->GenerateSnapshot(browser_, weak_ptr_factory_.GetWeakPtr()); + // Request a mobile device list update. + service_->RequestMobileListUpdate(); + + const ListValue* mobiles = service_->GetMobiles(); + GtkWidget* content = gtk_vbox_new(FALSE, 5); gtk_container_set_border_width(GTK_CONTAINER(content), kContentBorder); // Create and pack the title label; init the selected mobile device. GtkWidget* title = NULL; - const ListValue* mobiles = service_->GetMobiles(); if (mobiles->GetSize() == 1) { string16 name; const DictionaryValue* mobile = NULL; @@ -320,7 +324,7 @@ void ChromeToMobileBubbleGtk::OnSendClicked(GtkWidget* widget) { const DictionaryValue* mobile = NULL; if (mobiles->GetDictionary(selected_index, &mobile)) { bool snapshot = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(send_copy_)); - service_->SendToMobile(mobile, snapshot ? snapshot_path_ : FilePath(), + service_->SendToMobile(*mobile, snapshot ? snapshot_path_ : FilePath(), browser_, weak_ptr_factory_.GetWeakPtr()); } else { NOTREACHED(); diff --git a/chrome/browser/ui/gtk/location_bar_view_gtk.cc b/chrome/browser/ui/gtk/location_bar_view_gtk.cc index 64add46..5522b9e 100644 --- a/chrome/browser/ui/gtk/location_bar_view_gtk.cc +++ b/chrome/browser/ui/gtk/location_bar_view_gtk.cc @@ -560,7 +560,7 @@ void LocationBarViewGtk::Init(bool popup_window_mode) { CreateStarButton(); gtk_box_pack_end(GTK_BOX(hbox_.get()), star_.get(), FALSE, FALSE, 0); - // Disable Chrome To Mobile for off-the-record and non-synced profiles, + // Also disable Chrome To Mobile for off-the-record and non-synced profiles, // or if the feature is disabled by a command line flag or chrome://flags. if (!profile->IsOffTheRecord() && profile->IsSyncAccessible() && ChromeToMobileService::IsChromeToMobileEnabled()) { @@ -568,7 +568,8 @@ void LocationBarViewGtk::Init(bool popup_window_mode) { gtk_box_pack_end(GTK_BOX(hbox_.get()), chrome_to_mobile_view_.get(), FALSE, FALSE, 0); command_updater_->AddCommandObserver(IDC_CHROME_TO_MOBILE_PAGE, this); - UpdateChromeToMobileIcon(); + ChromeToMobileServiceFactory::GetForProfile(browser_->profile())-> + RequestMobileListUpdate(); } } diff --git a/chrome/browser/ui/views/chrome_to_mobile_bubble_view.cc b/chrome/browser/ui/views/chrome_to_mobile_bubble_view.cc index 52aebb7..135c2c2 100644 --- a/chrome/browser/ui/views/chrome_to_mobile_bubble_view.cc +++ b/chrome/browser/ui/views/chrome_to_mobile_bubble_view.cc @@ -329,6 +329,9 @@ ChromeToMobileBubbleView::ChromeToMobileBubbleView(views::View* anchor_view, // Generate the MHTML snapshot now to report its size in the bubble. service_->GenerateSnapshot(browser_, weak_ptr_factory_.GetWeakPtr()); + + // Request a mobile device list update. + service_->RequestMobileListUpdate(); } void ChromeToMobileBubbleView::LinkClicked(views::Link* source, @@ -361,7 +364,7 @@ void ChromeToMobileBubbleView::Send() { const DictionaryValue* mobile = NULL; if (mobiles->GetDictionary(selected_index, &mobile)) { FilePath snapshot = send_copy_->checked() ? snapshot_path_ : FilePath(); - service_->SendToMobile(mobile, snapshot, browser_, + service_->SendToMobile(*mobile, snapshot, browser_, weak_ptr_factory_.GetWeakPtr()); } else { NOTREACHED(); diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc index 584cd68..d146449 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.cc +++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc @@ -295,14 +295,16 @@ void LocationBarView::Init(views::View* popup_parent_view) { AddChildView(star_view_); star_view_->SetVisible(true); - // Disable Chrome To Mobile for off-the-record and non-synced profiles, + // Also disable Chrome To Mobile for off-the-record and non-synced profiles, // or if the feature is disabled by a command line flag or chrome://flags. if (!profile_->IsOffTheRecord() && profile_->IsSyncAccessible() && ChromeToMobileService::IsChromeToMobileEnabled()) { chrome_to_mobile_view_ = new ChromeToMobileView(this, command_updater_); AddChildView(chrome_to_mobile_view_); - chrome_to_mobile_view_->SetVisible( - ChromeToMobileServiceFactory::GetForProfile(profile_)->HasMobiles()); + ChromeToMobileService* service = + ChromeToMobileServiceFactory::GetForProfile(profile_); + service->RequestMobileListUpdate(); + chrome_to_mobile_view_->SetVisible(service->HasMobiles()); } } diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index ff25e2e..92dc37a 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -1745,8 +1745,9 @@ const char kCloudPrintSigninDialogHeight[] = "cloud_print.signin_dialog_size.height"; #if !defined(OS_ANDROID) -// The Chrome To Mobile service mobile device list pref. +// The Chrome To Mobile service prefs; the device list and last update time. const char kChromeToMobileDeviceList[] = "chrome_to_mobile.device_list"; +const char kChromeToMobileTimestamp[] = "chrome_to_mobile.timestamp"; #endif // The list of BackgroundContents that should be loaded when the browser diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 5d3731f..fa411c9 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -636,6 +636,7 @@ extern const char kCloudPrintSubmitEnabled[]; #if !defined(OS_ANDROID) extern const char kChromeToMobileDeviceList[]; +extern const char kChromeToMobileTimestamp[]; #endif extern const char kProxy[]; |