summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/DEPS2
-rw-r--r--chrome/browser/chrome_to_mobile_service.cc242
-rw-r--r--chrome/browser/chrome_to_mobile_service.h52
-rw-r--r--chrome/browser/chrome_to_mobile_service_factory.cc4
-rw-r--r--chrome/browser/chrome_to_mobile_service_factory.h1
-rw-r--r--chrome/browser/chrome_to_mobile_service_unittest.cc19
-rw-r--r--chrome/browser/ui/cocoa/chrome_to_mobile_bubble_controller.mm5
-rw-r--r--chrome/browser/ui/cocoa/chrome_to_mobile_bubble_controller_unittest.mm16
-rw-r--r--chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm3
-rw-r--r--chrome/browser/ui/gtk/chrome_to_mobile_bubble_gtk.cc8
-rw-r--r--chrome/browser/ui/gtk/location_bar_view_gtk.cc5
-rw-r--r--chrome/browser/ui/views/chrome_to_mobile_bubble_view.cc5
-rw-r--r--chrome/browser/ui/views/location_bar/location_bar_view.cc8
-rw-r--r--chrome/common/pref_names.cc3
-rw-r--r--chrome/common/pref_names.h1
15 files changed, 192 insertions, 182 deletions
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 775f092..e0a75e7 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -5,6 +5,7 @@ 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
@@ -20,6 +21,7 @@ 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 bc80c39..34afa32 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,10 +38,13 @@
#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 {
@@ -59,19 +62,16 @@ 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& service_url) {
- GURL search_url = cloud_print::GetUrlForSearch(service_url);
+GURL GetSearchURL(const GURL& cloud_print_url) {
+ GURL search_url = cloud_print::GetUrlForSearch(cloud_print_url);
GURL::Replacements replacements;
std::string query(kChromeToMobileRequestor);
replacements.SetQueryStr(query);
@@ -180,23 +180,26 @@ 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),
- 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();
+ 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);
}
}
@@ -206,18 +209,13 @@ ChromeToMobileService::~ChromeToMobileService() {
}
bool ChromeToMobileService::HasMobiles() const {
- return !GetMobiles()->empty();
+ const base::ListValue* mobiles = GetMobiles();
+ return mobiles && !mobiles->empty();
}
const base::ListValue* ChromeToMobileService::GetMobiles() const {
- return profile_->GetPrefs()->GetList(prefs::kChromeToMobileDeviceList);
-}
-
-void ChromeToMobileService::RequestMobileListUpdate() {
- if (access_token_.empty())
- RequestAccessToken();
- else if (cloud_print_accessible_)
- RequestDeviceSearch();
+ return sync_invalidation_enabled_ ?
+ profile_->GetPrefs()->GetList(prefs::kChromeToMobileDeviceList) : NULL;
}
void ChromeToMobileService::GenerateSnapshot(Browser* browser,
@@ -234,19 +232,28 @@ 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();
@@ -301,12 +308,18 @@ void ChromeToMobileService::LearnMore(Browser* browser) const {
chrome::Navigate(&params);
}
-void ChromeToMobileService::OnURLFetchComplete(
- const net::URLFetcher* source) {
- if (source == account_info_request_.get())
- HandleAccountInfoResponse();
- else if (source == search_request_.get())
- HandleSearchResponse();
+void ChromeToMobileService::Shutdown() {
+ // 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);
+}
+
+void ChromeToMobileService::OnURLFetchComplete(const net::URLFetcher* source) {
+ if (source->GetURL() == GetSearchURL(cloud_print_url_))
+ HandleSearchResponse(source);
else
HandleSubmitResponse(source);
}
@@ -318,8 +331,9 @@ 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)
- RequestAccessToken();
+ access_token_.clear();
}
void ChromeToMobileService::OnGetTokenSuccess(
@@ -329,18 +343,57 @@ void ChromeToMobileService::OnGetTokenSuccess(
access_token_fetcher_.reset();
auth_retry_timer_.Stop();
access_token_ = access_token;
- RequestAccountInfo();
+
+ 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();
+ }
}
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());
@@ -374,9 +427,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(service_url), net::URLFetcher::POST, this);
+ cloud_print::GetUrlForSubmit(cloud_print_url_),
+ net::URLFetcher::POST, this);
InitRequest(request);
return request;
}
@@ -435,8 +488,13 @@ void ChromeToMobileService::SendRequest(net::URLFetcher* request,
}
void ChromeToMobileService::RequestAccessToken() {
- // Deny concurrent requests and bail without a valid Gaia login refresh token.
+ // 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.
if (access_token_fetcher_.get() || !token_service->HasOAuthLoginToken())
return;
@@ -450,86 +508,33 @@ void ChromeToMobileService::RequestAccessToken() {
std::vector<std::string>(1, kCloudPrintAuth));
}
-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)
+ 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();
return;
+ }
LogMetric(DEVICES_REQUESTED);
- 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::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();
- }
+ net::URLFetcher* search_request = net::URLFetcher::Create(
+ GetSearchURL(cloud_print_url_), net::URLFetcher::GET, this);
+ InitRequest(search_request);
+ search_request->Start();
}
-void ChromeToMobileService::HandleSearchResponse() {
+void ChromeToMobileService::HandleSearchResponse(
+ const net::URLFetcher* source) {
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)) {
@@ -555,11 +560,8 @@ void ChromeToMobileService::HandleSearchResponse() {
}
}
- // 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());
+ // Update the cached mobile device list in profile prefs.
+ profile_->GetPrefs()->Set(prefs::kChromeToMobileDeviceList, mobiles);
if (HasMobiles())
LogMetric(DEVICES_AVAILABLE);
diff --git a/chrome/browser/chrome_to_mobile_service.h b/chrome/browser/chrome_to_mobile_service.h
index 3613396..37a1b25 100644
--- a/chrome/browser/chrome_to_mobile_service.h
+++ b/chrome/browser/chrome_to_mobile_service.h
@@ -6,10 +6,12 @@
#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"
@@ -22,6 +24,7 @@
#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;
@@ -39,7 +42,8 @@ class URLFetcher;
class ChromeToMobileService : public ProfileKeyedService,
public net::URLFetcherDelegate,
public content::NotificationObserver,
- public OAuth2AccessTokenConsumer {
+ public OAuth2AccessTokenConsumer,
+ public syncer::SyncNotifierObserver {
public:
class Observer {
public:
@@ -112,10 +116,6 @@ 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);
@@ -139,6 +139,9 @@ class ChromeToMobileService : public ProfileKeyedService,
// Opens the "Learn More" help article link in the supplied |browser|.
void LearnMore(Browser* browser) const;
+ // ProfileKeyedService method.
+ virtual void Shutdown() OVERRIDE;
+
// net::URLFetcherDelegate method.
virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
@@ -152,6 +155,18 @@ 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;
@@ -179,25 +194,26 @@ 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.
- void RequestDeviceSearch();
+ // Virtual for unit test mocking.
+ virtual void RequestDeviceSearch();
- void HandleAccountInfoResponse();
- void HandleSearchResponse();
+ void HandleSearchResponse(const net::URLFetcher* source);
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_;
- // Cloud print helper class and auth token.
- scoped_ptr<CloudPrintURL> cloud_print_url_;
+ // The cloud print service URL and auth access token.
+ GURL cloud_print_url_;
std::string access_token_;
// The set of snapshots currently available.
@@ -212,12 +228,8 @@ class ChromeToMobileService : public ProfileKeyedService,
scoped_ptr<OAuth2AccessTokenFetcher> access_token_fetcher_;
base::OneShotTimer<ChromeToMobileService> auth_retry_timer_;
- // 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_;
+ // A queue of tasks to perform after an access token is lazily initialized.
+ std::queue<base::Closure> task_queue_;
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 1058917..d2c6601 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 c3f62c6..5232a7f 100644
--- a/chrome/browser/chrome_to_mobile_service_factory.h
+++ b/chrome/browser/chrome_to_mobile_service_factory.h
@@ -5,6 +5,7 @@
#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 d1e6d41..8cff191 100644
--- a/chrome/browser/chrome_to_mobile_service_unittest.cc
+++ b/chrome/browser/chrome_to_mobile_service_unittest.cc
@@ -17,7 +17,6 @@ const char kDummyString[] = "dummy";
class DummyNotificationSource {};
-// A mock ChromeToMobileService with a mocked out RequestAccessToken method.
class MockChromeToMobileService : public ChromeToMobileService {
public:
MockChromeToMobileService();
@@ -50,29 +49,37 @@ ChromeToMobileServiceTest::ChromeToMobileServiceTest() {}
ChromeToMobileServiceTest::~ChromeToMobileServiceTest() {}
-// Ensure that RequestAccessToken is not called for irrelevant notifications.
+// Ensure that irrelevant notifications do not invalidate the access token.
TEST_F(ChromeToMobileServiceTest, IgnoreIrrelevantNotifications) {
EXPECT_CALL(service_, RequestAccessToken()).Times(0);
- // Send dummy service/token details (should not refresh token).
+ service_.SetAccessTokenForTest(kDummyString);
+ ASSERT_FALSE(service_.GetAccessTokenForTest().empty());
+
+ // Send dummy service/token details (should not request 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 RequestAccessToken is called on the proper notification.
+// Ensure that proper notifications invalidate the access token.
TEST_F(ChromeToMobileServiceTest, AuthenticateOnTokenAvailable) {
- EXPECT_CALL(service_, RequestAccessToken()).Times(1);
+ EXPECT_CALL(service_, RequestAccessToken()).Times(0);
+
+ service_.SetAccessTokenForTest(kDummyString);
+ ASSERT_FALSE(service_.GetAccessTokenForTest().empty());
- // Send a Gaia OAuth2 Login service dummy token (should refresh token).
+ // Send a Gaia OAuth2 Login service dummy token (should request 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 f8de658..61eb57a 100644
--- a/chrome/browser/ui/cocoa/chrome_to_mobile_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/chrome_to_mobile_bubble_controller.mm
@@ -165,9 +165,6 @@ 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];
}
@@ -187,7 +184,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 c1efcb2..534a42f 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,10 +19,9 @@ 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));
@@ -36,7 +35,9 @@ 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);
}
}
@@ -115,8 +116,9 @@ 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));
@@ -126,8 +128,9 @@ 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));
@@ -137,8 +140,9 @@ 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));
@@ -149,7 +153,6 @@ 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::_));
@@ -162,7 +165,6 @@ 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 54c85c5..e668251 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,8 +118,7 @@ LocationBarViewMac::LocationBarViewMac(
command_updater_->AddCommandObserver(IDC_CHROME_TO_MOBILE_PAGE, this);
chrome_to_mobile_decoration_.reset(
new ChromeToMobileDecoration(profile, command_updater));
- ChromeToMobileServiceFactory::GetForProfile(profile)->
- RequestMobileListUpdate();
+ UpdateChromeToMobileEnabled();
}
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 92a678b..ced3212 100644
--- a/chrome/browser/ui/gtk/chrome_to_mobile_bubble_gtk.cc
+++ b/chrome/browser/ui/gtk/chrome_to_mobile_bubble_gtk.cc
@@ -160,16 +160,12 @@ 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;
@@ -324,7 +320,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 5522b9e..64add46 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);
- // Also disable Chrome To Mobile for off-the-record and non-synced profiles,
+ // 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,8 +568,7 @@ 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);
- ChromeToMobileServiceFactory::GetForProfile(browser_->profile())->
- RequestMobileListUpdate();
+ UpdateChromeToMobileIcon();
}
}
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 135c2c2..52aebb7 100644
--- a/chrome/browser/ui/views/chrome_to_mobile_bubble_view.cc
+++ b/chrome/browser/ui/views/chrome_to_mobile_bubble_view.cc
@@ -329,9 +329,6 @@ 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,
@@ -364,7 +361,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 9cc41ee..484c2e8 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -296,16 +296,14 @@ void LocationBarView::Init(views::View* popup_parent_view) {
AddChildView(star_view_);
star_view_->SetVisible(true);
- // Also disable Chrome To Mobile for off-the-record and non-synced profiles,
+ // 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_);
- ChromeToMobileService* service =
- ChromeToMobileServiceFactory::GetForProfile(profile_);
- service->RequestMobileListUpdate();
- chrome_to_mobile_view_->SetVisible(service->HasMobiles());
+ chrome_to_mobile_view_->SetVisible(
+ ChromeToMobileServiceFactory::GetForProfile(profile_)->HasMobiles());
}
}
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 92dc37a..ff25e2e 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1745,9 +1745,8 @@ const char kCloudPrintSigninDialogHeight[] =
"cloud_print.signin_dialog_size.height";
#if !defined(OS_ANDROID)
-// The Chrome To Mobile service prefs; the device list and last update time.
+// The Chrome To Mobile service mobile device list pref.
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 fa411c9..5d3731f 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -636,7 +636,6 @@ extern const char kCloudPrintSubmitEnabled[];
#if !defined(OS_ANDROID)
extern const char kChromeToMobileDeviceList[];
-extern const char kChromeToMobileTimestamp[];
#endif
extern const char kProxy[];