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

Unified Diff: chrome/browser/chrome_to_mobile_service.cc

Issue 10834203: Integrate invalidation API into ChromeToMobileService. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Update comment; sync and rebase. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/chrome_to_mobile_service.h ('k') | chrome/browser/chrome_to_mobile_service_factory.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/chrome_to_mobile_service.cc
diff --git a/chrome/browser/chrome_to_mobile_service.cc b/chrome/browser/chrome_to_mobile_service.cc
index bc80c393f6f95ba6a41815d2b1f899944d7746f0..17d7d32fed58d02444d32af92853ad429ce5bf93 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,44 +180,48 @@ 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);
}
}
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 {
- 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 +238,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 +314,9 @@ 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::OnURLFetchComplete(const net::URLFetcher* source) {
+ if (source->GetURL() == GetSearchURL(cloud_print_url_))
+ HandleSearchResponse(source);
else
HandleSubmitResponse(source);
}
@@ -318,8 +328,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 +340,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 +424,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 +485,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 +505,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 +557,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);
« no previous file with comments | « chrome/browser/chrome_to_mobile_service.h ('k') | chrome/browser/chrome_to_mobile_service_factory.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698