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

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: Sync and rebase; merge invalidation API changes. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 9d47a68d23b428c55a88d1f8ec925d8ebb7feb61..e311f2e4b6c188bc587949107e7119df889079b6 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,6 +38,8 @@
#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"
@@ -59,19 +61,15 @@ 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.
+// 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";
@@ -178,44 +176,59 @@ 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),
cloud_print_url_(new CloudPrintURL(profile)),
- cloud_print_accessible_(false) {
- // Skip initialization if constructed without a profile.
+ request_search_when_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())
- RefreshAccessToken();
+ ProfileSyncService* profile_sync_service =
+ ProfileSyncServiceFactory::GetForProfile(profile_);
+ profile_sync_service->RegisterInvalidationHandler(this);
+ syncer::ObjectIdSet ids;
+ ids.insert(invalidation::ObjectId(
+ ipc::invalidation::ObjectSource::CHROME_COMPONENTS,
+ kSyncInvalidationObjectIdChromeToMobileDeviceList));
+ profile_sync_service->UpdateRegisteredInvalidationIds(this, ids);
akalin 2012/08/13 22:23:58 what's the code path where chrome to phone is disa
msw 2012/08/16 02:41:51 It's tied to sync invalidation (presuming commandl
+ // TODO(msw): Use IsSyncEnabled? Is OnNotificationsEnabled called now?
akalin 2012/08/13 22:23:58 don't use IsSyncEnabled. I plan to have OnNotific
msw 2012/08/16 02:41:51 Done. OnNotificationsEnabled seems to be called al
+ sync_invalidation_enabled_ = profile_sync_service->IsSyncEnabled();
}
+ UpdateCommandState();
}
ChromeToMobileService::~ChromeToMobileService() {
while (!snapshots_.empty())
DeleteSnapshot(*snapshots_.begin());
+ if (profile_)
akalin 2012/08/13 22:23:58 i think you can omit braces only if the 'then' sta
msw 2012/08/16 02:41:51 Done.
+ ProfileSyncServiceFactory::GetForProfile(profile_)->
+ UnregisterInvalidationHandler(this);
}
-bool ChromeToMobileService::HasMobiles() {
- return !GetMobiles()->empty();
+bool ChromeToMobileService::HasMobiles() const {
+ return sync_invalidation_enabled_ && !GetMobiles()->empty();
}
const base::ListValue* ChromeToMobileService::GetMobiles() const {
+ if (!sync_invalidation_enabled_)
+ return NULL;
+
return profile_->GetPrefs()->GetList(prefs::kChromeToMobileDeviceList);
}
void ChromeToMobileService::RequestMobileListUpdate() {
- if (access_token_.empty())
+ if (!sync_invalidation_enabled_)
+ return;
+
+ if (access_token_.empty()) {
+ request_search_when_accessible_ = true;
RefreshAccessToken();
- else if (cloud_print_accessible_)
+ } else {
RequestSearch();
+ }
}
void ChromeToMobileService::GenerateSnapshot(Browser* browser,
@@ -292,11 +305,8 @@ 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())
+void ChromeToMobileService::OnURLFetchComplete(const net::URLFetcher* source) {
+ if (source == search_request_.get())
HandleSearchResponse();
else
HandleSubmitResponse(source);
@@ -309,6 +319,7 @@ void ChromeToMobileService::Observe(
DCHECK_EQ(type, chrome::NOTIFICATION_TOKEN_AVAILABLE);
TokenService::TokenAvailableDetails* token_details =
content::Details<TokenService::TokenAvailableDetails>(details).ptr();
+ // Update the cloud print access token on Gaia login refresh token updates.
if (token_details->service() == GaiaConstants::kGaiaOAuth2LoginRefreshToken)
RefreshAccessToken();
}
@@ -320,7 +331,11 @@ void ChromeToMobileService::OnGetTokenSuccess(
access_token_fetcher_.reset();
auth_retry_timer_.Stop();
access_token_ = access_token;
- RequestAccountInfo();
+
+ if (request_search_when_accessible_) {
+ request_search_when_accessible_ = false;
+ RequestSearch();
+ }
}
void ChromeToMobileService::OnGetTokenFailure(
@@ -332,6 +347,45 @@ void ChromeToMobileService::OnGetTokenFailure(
this, &ChromeToMobileService::RefreshAccessToken);
}
+void ChromeToMobileService::OnNotificationsEnabled() {
+ // Only enable Chrome To Mobile if Sync Invalidation Notification are enabled.
+ // Otherwise, the device list may be out of date and result in send failures.
+ sync_invalidation_enabled_ = true;
+ UpdateCommandState();
+}
+
+void ChromeToMobileService::OnNotificationsDisabled(
+ syncer::NotificationsDisabledReason reason) {
+ // Only enable Chrome To Mobile if Sync Invalidation Notification are enabled.
+ // Otherwise, the device list may be out of date and result in send failures.
+ sync_invalidation_enabled_ = false;
+ UpdateCommandState();
+}
+
+void ChromeToMobileService::OnIncomingNotification(
+ const syncer::ObjectIdPayloadMap& id_payloads,
+ syncer::IncomingNotificationSource source) {
+ DCHECK(sync_invalidation_enabled_);
akalin 2012/08/13 22:23:58 i don't know if this should be a DCHECK. The API
msw 2012/08/16 02:41:51 Odd; then I'll just use it to gate the feature w/[
+ DCHECK_EQ(id_payloads.size(), 1U);
+ DCHECK_EQ(id_payloads.count(invalidation::ObjectId(
+ ipc::invalidation::ObjectSource::CHROME_COMPONENTS,
+ kSyncInvalidationObjectIdChromeToMobileDeviceList)), 1U);
+ RequestMobileListUpdate();
+}
+
+// TODO(msw): Audit location bar code that checks enabled/disabled...
+void ChromeToMobileService::UpdateCommandState() const {
+ // Ensure the feature is not disabled by commandline options.
+ DCHECK(IsChromeToMobileEnabled());
+ const bool has_mobiles = HasMobiles();
+ for (BrowserList::const_iterator i = BrowserList::begin();
+ i != BrowserList::end(); ++i) {
+ Browser* browser = *i;
+ if (browser->profile() == profile_)
+ browser->command_controller()->SendToMobileStateChanged(has_mobiles);
+ }
+}
+
void ChromeToMobileService::SnapshotFileCreated(
base::WeakPtr<Observer> observer,
SessionID::id_type browser_id,
@@ -413,66 +467,32 @@ void ChromeToMobileService::SendRequest(net::URLFetcher* request,
}
void ChromeToMobileService::RefreshAccessToken() {
- if (access_token_fetcher_.get())
- return;
+ // 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));
- std::string token = TokenServiceFactory::GetForProfile(profile_)->
- GetOAuth2LoginRefreshToken();
- if (token.empty())
+ // Deny concurrent requests and bail without a valid Gaia login refresh token.
+ if (access_token_fetcher_.get() || !token_service->HasOAuthLoginToken())
return;
auth_retry_timer_.Stop();
access_token_fetcher_.reset(
new OAuth2AccessTokenFetcher(this, profile_->GetRequestContext()));
- std::vector<std::string> scopes(1, kCloudPrintAuth);
GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
access_token_fetcher_->Start(gaia_urls->oauth2_chrome_client_id(),
- gaia_urls->oauth2_chrome_client_secret(), token, scopes);
-}
-
-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();
+ gaia_urls->oauth2_chrome_client_secret(),
+ token_service->GetOAuth2LoginRefreshToken(),
+ std::vector<std::string>(1, kCloudPrintAuth));
}
void ChromeToMobileService::RequestSearch() {
+ DCHECK(sync_invalidation_enabled_);
DCHECK(!access_token_.empty());
- // 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)
+ // Deny concurrent requests.
+ if (search_request_.get())
return;
LogMetric(DEVICES_REQUESTED);
@@ -484,25 +504,6 @@ void ChromeToMobileService::RequestSearch() {
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();
- }
-}
-
void ChromeToMobileService::HandleSearchResponse() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
@@ -510,6 +511,10 @@ void ChromeToMobileService::HandleSearchResponse() {
search_request_->GetResponseAsString(&data);
search_request_.reset();
+ // TODO(msw): Ackowledge the sync invalidation when API exists.
+ // TODO(msw): Detect, log, potentially retry on failure / bad responses.
+ // TODO(msw): Handle removing all devices or cloud print account altogether.
+
ListValue* list = NULL;
DictionaryValue* dictionary = NULL;
scoped_ptr<Value> json(base::JSONReader::Read(data));
@@ -537,22 +542,12 @@ 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);
- const bool has_mobiles = HasMobiles();
- if (has_mobiles)
+ if (HasMobiles())
LogMetric(DEVICES_AVAILABLE);
-
- for (BrowserList::const_iterator i = BrowserList::begin();
- i != BrowserList::end(); ++i) {
- Browser* browser = *i;
- if (browser->profile() == profile_)
- browser->command_controller()->SendToMobileStateChanged(has_mobiles);
- }
+ UpdateCommandState();
}
}

Powered by Google App Engine
This is Rietveld 408576698