summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormsw@chromium.org <msw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-21 20:01:31 +0000
committermsw@chromium.org <msw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-21 20:01:31 +0000
commit7911431b57acda42db3ec127aef6a5714854edab (patch)
tree83076a1e7b026a71b270c265b8b20f2c8bd3b8ad
parentdda29c94364d6dd8896f64032dcc2561a8a217c9 (diff)
downloadchromium_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/DEPS2
-rw-r--r--chrome/browser/chrome_to_mobile_service.cc239
-rw-r--r--chrome/browser/chrome_to_mobile_service.h49
-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, 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(&params);
}
-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[];