Commit 33227920 authored by derat@chromium.org's avatar derat@chromium.org

contacts: Add GDataContactsService.

This adds a class for fetching a user's Google contacts via
the Contacts API.

BUG=128805
TEST=added
TBR=ben@chromium.org

Review URL: https://chromiumcodereview.appspot.com/10818017

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@149005 0039d316-1c4b-4281-b951-d872f2087c98
parent ba00db9f
...@@ -19,7 +19,8 @@ message Contact { ...@@ -19,7 +19,8 @@ message Contact {
// Provider-assigned unique identifier. // Provider-assigned unique identifier.
optional string provider_id = 1; optional string provider_id = 1;
// Last time at which this contact was updated within the upstream provider. // Last time at which this contact was updated within the upstream provider,
// as given by base::Time::ToInternalValue().
optional int64 update_time = 2; optional int64 update_time = 2;
// Has the contact been deleted recently within the upstream provider? // Has the contact been deleted recently within the upstream provider?
......
This diff is collapsed.
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_GDATA_GDATA_CONTACTS_SERVICE_H_
#define CHROME_BROWSER_CHROMEOS_GDATA_GDATA_CONTACTS_SERVICE_H_
#include <set>
#include <vector>
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/time.h"
#include "chrome/browser/chromeos/gdata/gdata_errorcode.h"
#include "googleurl/src/gurl.h"
class Profile;
namespace base {
class Value;
}
namespace contacts {
class Contact;
}
namespace gdata {
class GDataAuthService;
class GDataOperationRunner;
// Interface for fetching a user's Google contacts via the Contacts API
// (described at https://developers.google.com/google-apps/contacts/v3/).
class GDataContactsServiceInterface {
public:
typedef base::Callback<void(scoped_ptr<ScopedVector<contacts::Contact> >)>
SuccessCallback;
typedef base::Closure FailureCallback;
virtual ~GDataContactsServiceInterface() {}
virtual void Initialize() = 0;
// Downloads all contacts changed at or after |min_update_time| and invokes
// the appropriate callback asynchronously on the UI thread when complete. If
// min_update_time.is_null() is true, all contacts will be returned.
virtual void DownloadContacts(SuccessCallback success_callback,
FailureCallback failure_callback,
const base::Time& min_update_time) = 0;
protected:
GDataContactsServiceInterface() {}
private:
DISALLOW_COPY_AND_ASSIGN(GDataContactsServiceInterface);
};
class GDataContactsService : public GDataContactsServiceInterface {
public:
typedef base::Callback<std::string(const std::string&)>
RewritePhotoUrlCallback;
explicit GDataContactsService(Profile* profile);
virtual ~GDataContactsService();
GDataAuthService* auth_service_for_testing();
void set_max_simultaneous_photo_downloads_for_testing(int max_downloads) {
max_simultaneous_photo_downloads_ = max_downloads;
}
void set_feed_url_for_testing(const GURL& url) {
feed_url_for_testing_ = url;
}
void set_rewrite_photo_url_callback_for_testing(RewritePhotoUrlCallback cb) {
rewrite_photo_url_callback_for_testing_ = cb;
}
// Overridden from GDataContactsServiceInterface:
virtual void Initialize() OVERRIDE;
virtual void DownloadContacts(SuccessCallback success_callback,
FailureCallback failure_callback,
const base::Time& min_update_time) OVERRIDE;
private:
class DownloadContactsRequest;
// Invoked by a download request once it's finished (either successfully or
// unsuccessfully).
void OnRequestComplete(DownloadContactsRequest* request);
Profile* profile_; // not owned
scoped_ptr<GDataOperationRunner> runner_;
// In-progress download requests. Pointers are owned by this class.
std::set<DownloadContactsRequest*> requests_;
// If non-empty, URL that will be used to fetch the feed. URLs contained
// within the feed will also be modified to use the host and port from this
// member.
GURL feed_url_for_testing_;
// Maximum number of photos we'll try to download at once (per
// DownloadContacts() request).
int max_simultaneous_photo_downloads_;
// Callback that's invoked to rewrite photo URLs for tests.
// This is needed for tests that serve static feed data from a host/port
// that's only known at runtime.
RewritePhotoUrlCallback rewrite_photo_url_callback_for_testing_;
DISALLOW_COPY_AND_ASSIGN(GDataContactsService);
};
} // namespace gdata
#endif // CHROME_BROWSER_CHROMEOS_GDATA_GDATA_CONTACTS_SERVICE_H_
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/string_number_conversions.h" #include "base/string_number_conversions.h"
#include "base/stringprintf.h" #include "base/stringprintf.h"
#include "base/values.h" #include "base/values.h"
#include "chrome/browser/chromeos/gdata/gdata_util.h"
#include "chrome/browser/chromeos/gdata/gdata_wapi_parser.h" #include "chrome/browser/chromeos/gdata/gdata_wapi_parser.h"
#include "chrome/common/net/url_util.h" #include "chrome/common/net/url_util.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
...@@ -48,6 +49,18 @@ const char kGetDocumentEntryURLFormat[] = ...@@ -48,6 +49,18 @@ const char kGetDocumentEntryURLFormat[] =
const char kAccountMetadataURL[] = const char kAccountMetadataURL[] =
"https://docs.google.com/feeds/metadata/default"; "https://docs.google.com/feeds/metadata/default";
// URL requesting all contacts.
// TODO(derat): Per https://goo.gl/AufHP, "The feed may not contain all of the
// user's contacts, because there's a default limit on the number of results
// returned." Decide if 10000 is reasonable or not.
const char kGetContactsURL[] =
"https://www.google.com/m8/feeds/contacts/default/full"
"?alt=json&showdeleted=true&max-results=10000";
// Query parameter optionally appended to |kGetContactsURL| to return only
// recently-updated contacts.
const char kGetContactsUpdatedMinParam[] = "updated-min";
const char kUploadContentRange[] = "Content-Range: bytes "; const char kUploadContentRange[] = "Content-Range: bytes ";
const char kUploadContentType[] = "X-Upload-Content-Type: "; const char kUploadContentType[] = "X-Upload-Content-Type: ";
const char kUploadContentLength[] = "X-Upload-Content-Length: "; const char kUploadContentLength[] = "X-Upload-Content-Length: ";
...@@ -875,4 +888,62 @@ void ResumeUploadOperation::OnURLFetchUploadProgress( ...@@ -875,4 +888,62 @@ void ResumeUploadOperation::OnURLFetchUploadProgress(
NotifyProgress(params_.start_range + current, params_.content_length); NotifyProgress(params_.start_range + current, params_.content_length);
} }
//============================ GetContactsOperation ============================
GetContactsOperation::GetContactsOperation(GDataOperationRegistry* registry,
Profile* profile,
const base::Time& min_update_time,
const GetDataCallback& callback)
: GetDataOperation(registry, profile, callback),
min_update_time_(min_update_time) {
}
GetContactsOperation::~GetContactsOperation() {}
GURL GetContactsOperation::GetURL() const {
if (!feed_url_for_testing_.is_empty())
return GURL(feed_url_for_testing_);
GURL url(kGetContactsURL);
if (!min_update_time_.is_null()) {
std::string time_rfc3339 = util::FormatTimeAsString(min_update_time_);
url = chrome_common_net::AppendQueryParameter(
url, kGetContactsUpdatedMinParam, time_rfc3339);
}
return url;
}
//========================== GetContactPhotoOperation ==========================
GetContactPhotoOperation::GetContactPhotoOperation(
GDataOperationRegistry* registry,
Profile* profile,
const GURL& photo_url,
const GetDownloadDataCallback& callback)
: UrlFetchOperationBase(registry, profile),
photo_url_(photo_url),
callback_(callback) {
}
GetContactPhotoOperation::~GetContactPhotoOperation() {}
GURL GetContactPhotoOperation::GetURL() const {
return photo_url_;
}
bool GetContactPhotoOperation::ProcessURLFetchResults(
const net::URLFetcher* source) {
GDataErrorCode code = static_cast<GDataErrorCode>(source->GetResponseCode());
scoped_ptr<std::string> data(new std::string);
source->GetResponseAsString(data.get());
callback_.Run(code, data.Pass());
return code == HTTP_SUCCESS;
}
void GetContactPhotoOperation::RunCallbackOnPrematureFailure(
GDataErrorCode code) {
scoped_ptr<std::string> data(new std::string);
callback_.Run(code, data.Pass());
}
} // namespace gdata } // namespace gdata
...@@ -383,6 +383,63 @@ class ResumeUploadOperation : public UrlFetchOperationBase { ...@@ -383,6 +383,63 @@ class ResumeUploadOperation : public UrlFetchOperationBase {
DISALLOW_COPY_AND_ASSIGN(ResumeUploadOperation); DISALLOW_COPY_AND_ASSIGN(ResumeUploadOperation);
}; };
//============================ GetContactsOperation ============================
// This class fetches a user's contacts.
class GetContactsOperation : public GetDataOperation {
public:
GetContactsOperation(GDataOperationRegistry* registry,
Profile* profile,
const base::Time& min_update_time,
const GetDataCallback& callback);
virtual ~GetContactsOperation();
void set_feed_url_for_testing(const GURL& url) {
feed_url_for_testing_ = url;
}
protected:
// Overridden from GetDataOperation.
virtual GURL GetURL() const OVERRIDE;
private:
// If non-empty, URL of the feed to fetch.
GURL feed_url_for_testing_;
// If is_null() is false, contains a minimum last-updated time that will be
// used to filter contacts.
base::Time min_update_time_;
DISALLOW_COPY_AND_ASSIGN(GetContactsOperation);
};
//========================== GetContactPhotoOperation ==========================
// This class fetches a contact's photo.
class GetContactPhotoOperation : public UrlFetchOperationBase {
public:
GetContactPhotoOperation(GDataOperationRegistry* registry,
Profile* profile,
const GURL& photo_url,
const GetDownloadDataCallback& callback);
virtual ~GetContactPhotoOperation();
protected:
// Overridden from UrlFetchOperationBase.
virtual GURL GetURL() const OVERRIDE;
virtual bool ProcessURLFetchResults(const net::URLFetcher* source) OVERRIDE;
virtual void RunCallbackOnPrematureFailure(GDataErrorCode code) OVERRIDE;
private:
// Location of the photo to fetch.
GURL photo_url_;
// Callback to which the photo data is passed.
GetDownloadDataCallback callback_;
DISALLOW_COPY_AND_ASSIGN(GetContactPhotoOperation);
};
} // namespace gdata } // namespace gdata
#endif // CHROME_BROWSER_CHROMEOS_GDATA_GDATA_OPERATIONS_H_ #endif // CHROME_BROWSER_CHROMEOS_GDATA_GDATA_OPERATIONS_H_
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/bind_helpers.h" #include "base/bind_helpers.h"
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/gdata/drive_webapps_registry.h" #include "chrome/browser/chromeos/gdata/drive_webapps_registry.h"
#include "chrome/browser/chromeos/gdata/gdata_contacts_service.h"
#include "chrome/browser/chromeos/gdata/gdata_documents_service.h" #include "chrome/browser/chromeos/gdata/gdata_documents_service.h"
#include "chrome/browser/chromeos/gdata/gdata_download_observer.h" #include "chrome/browser/chromeos/gdata/gdata_download_observer.h"
#include "chrome/browser/chromeos/gdata/gdata_file_system.h" #include "chrome/browser/chromeos/gdata/gdata_file_system.h"
...@@ -70,6 +71,7 @@ void GDataSystemService::Initialize( ...@@ -70,6 +71,7 @@ void GDataSystemService::Initialize(
download_observer_.reset(new GDataDownloadObserver(uploader(), download_observer_.reset(new GDataDownloadObserver(uploader(),
file_system())); file_system()));
sync_client_.reset(new GDataSyncClient(profile_, file_system(), cache())); sync_client_.reset(new GDataSyncClient(profile_, file_system(), cache()));
contacts_service_.reset(new GDataContactsService(profile_));
sync_client_->Initialize(); sync_client_->Initialize();
file_system_->Initialize(); file_system_->Initialize();
...@@ -84,6 +86,7 @@ void GDataSystemService::Initialize( ...@@ -84,6 +86,7 @@ void GDataSystemService::Initialize(
GDataCache::CACHE_TYPE_TMP_DOWNLOADS)); GDataCache::CACHE_TYPE_TMP_DOWNLOADS));
AddDriveMountPoint(); AddDriveMountPoint();
contacts_service_->Initialize();
} }
void GDataSystemService::Shutdown() { void GDataSystemService::Shutdown() {
...@@ -91,6 +94,7 @@ void GDataSystemService::Shutdown() { ...@@ -91,6 +94,7 @@ void GDataSystemService::Shutdown() {
RemoveDriveMountPoint(); RemoveDriveMountPoint();
// Shut down the member objects in the reverse order of creation. // Shut down the member objects in the reverse order of creation.
contacts_service_.reset();
sync_client_.reset(); sync_client_.reset();
download_observer_.reset(); download_observer_.reset();
file_system_.reset(); file_system_.reset();
......
...@@ -20,6 +20,7 @@ namespace gdata { ...@@ -20,6 +20,7 @@ namespace gdata {
class DocumentsServiceInterface; class DocumentsServiceInterface;
class DriveWebAppsRegistry; class DriveWebAppsRegistry;
class GDataCache; class GDataCache;
class GDataContactsService;
class GDataDownloadObserver; class GDataDownloadObserver;
class GDataFileSystemInterface; class GDataFileSystemInterface;
class GDataSyncClient; class GDataSyncClient;
...@@ -33,19 +34,11 @@ class GDataUploader; ...@@ -33,19 +34,11 @@ class GDataUploader;
// created per-profile. // created per-profile.
class GDataSystemService : public ProfileKeyedService { class GDataSystemService : public ProfileKeyedService {
public: public:
// Returns the documents service instance.
DocumentsServiceInterface* docs_service() { return documents_service_.get(); } DocumentsServiceInterface* docs_service() { return documents_service_.get(); }
// Returns the cache instance.
GDataCache* cache() { return cache_; } GDataCache* cache() { return cache_; }
// Returns the file system instance.
GDataFileSystemInterface* file_system() { return file_system_.get(); } GDataFileSystemInterface* file_system() { return file_system_.get(); }
// Returns the uploader instance.
GDataUploader* uploader() { return uploader_.get(); } GDataUploader* uploader() { return uploader_.get(); }
GDataContactsService* contacts_service() { return contacts_service_.get(); }
// Returns the file system instance.
DriveWebAppsRegistry* webapps_registry() { return webapps_registry_.get(); } DriveWebAppsRegistry* webapps_registry() { return webapps_registry_.get(); }
// ProfileKeyedService override: // ProfileKeyedService override:
...@@ -76,6 +69,7 @@ class GDataSystemService : public ProfileKeyedService { ...@@ -76,6 +69,7 @@ class GDataSystemService : public ProfileKeyedService {
scoped_ptr<GDataFileSystemInterface> file_system_; scoped_ptr<GDataFileSystemInterface> file_system_;
scoped_ptr<GDataDownloadObserver> download_observer_; scoped_ptr<GDataDownloadObserver> download_observer_;
scoped_ptr<GDataSyncClient> sync_client_; scoped_ptr<GDataSyncClient> sync_client_;
scoped_ptr<GDataContactsService> contacts_service_;
DISALLOW_COPY_AND_ASSIGN(GDataSystemService); DISALLOW_COPY_AND_ASSIGN(GDataSystemService);
}; };
......
...@@ -46,6 +46,9 @@ const char kDocsListScope[] = "https://docs.google.com/feeds/"; ...@@ -46,6 +46,9 @@ const char kDocsListScope[] = "https://docs.google.com/feeds/";
const char kSpreadsheetsScope[] = "https://spreadsheets.google.com/feeds/"; const char kSpreadsheetsScope[] = "https://spreadsheets.google.com/feeds/";
const char kUserContentScope[] = "https://docs.googleusercontent.com/"; const char kUserContentScope[] = "https://docs.googleusercontent.com/";
// OAuth scope for the Contacts API.
const char kContactsScope[] = "https://www.google.com/m8/feeds/";
// OAuth scope for Drive API. // OAuth scope for Drive API.
const char kDriveAppsScope[] = "https://www.googleapis.com/auth/drive.apps"; const char kDriveAppsScope[] = "https://www.googleapis.com/auth/drive.apps";
...@@ -71,6 +74,7 @@ void AuthOperation::Start() { ...@@ -71,6 +74,7 @@ void AuthOperation::Start() {
scopes.push_back(kDocsListScope); scopes.push_back(kDocsListScope);
scopes.push_back(kSpreadsheetsScope); scopes.push_back(kSpreadsheetsScope);
scopes.push_back(kUserContentScope); scopes.push_back(kUserContentScope);
scopes.push_back(kContactsScope);
if (gdata::util::IsDriveV2ApiEnabled()) if (gdata::util::IsDriveV2ApiEnabled())
scopes.push_back(kDriveAppsScope); scopes.push_back(kDriveAppsScope);
oauth2_access_token_fetcher_.reset(new OAuth2AccessTokenFetcher( oauth2_access_token_fetcher_.reset(new OAuth2AccessTokenFetcher(
......
...@@ -549,6 +549,8 @@ ...@@ -549,6 +549,8 @@
'browser/chromeos/gdata/gdata_cache.h', 'browser/chromeos/gdata/gdata_cache.h',
'browser/chromeos/gdata/gdata_cache_metadata.cc', 'browser/chromeos/gdata/gdata_cache_metadata.cc',
'browser/chromeos/gdata/gdata_cache_metadata.h', 'browser/chromeos/gdata/gdata_cache_metadata.h',
'browser/chromeos/gdata/gdata_contacts_service.cc',
'browser/chromeos/gdata/gdata_contacts_service.h',
'browser/chromeos/gdata/gdata_db.h', 'browser/chromeos/gdata/gdata_db.h',
'browser/chromeos/gdata/gdata_db_factory.cc', 'browser/chromeos/gdata/gdata_db_factory.cc',
'browser/chromeos/gdata/gdata_db_factory.h', 'browser/chromeos/gdata/gdata_db_factory.h',
......
...@@ -2633,6 +2633,7 @@ ...@@ -2633,6 +2633,7 @@
'browser/chromeos/bluetooth/test/mock_bluetooth_adapter.h', 'browser/chromeos/bluetooth/test/mock_bluetooth_adapter.h',
'browser/chromeos/bluetooth/test/mock_bluetooth_device.cc', 'browser/chromeos/bluetooth/test/mock_bluetooth_device.cc',
'browser/chromeos/bluetooth/test/mock_bluetooth_device.h', 'browser/chromeos/bluetooth/test/mock_bluetooth_device.h',
'browser/chromeos/contacts/contact_test_util.cc',
'browser/chromeos/cros/cros_in_process_browser_test.cc', 'browser/chromeos/cros/cros_in_process_browser_test.cc',
'browser/chromeos/cros/cros_in_process_browser_test.h', 'browser/chromeos/cros/cros_in_process_browser_test.h',
'browser/chromeos/cros/cros_mock.cc', 'browser/chromeos/cros/cros_mock.cc',
...@@ -2644,6 +2645,7 @@ ...@@ -2644,6 +2645,7 @@
'browser/chromeos/extensions/file_browser_private_apitest.cc', 'browser/chromeos/extensions/file_browser_private_apitest.cc',
'browser/chromeos/extensions/echo_private_apitest.cc', 'browser/chromeos/extensions/echo_private_apitest.cc',
'browser/chromeos/extensions/external_filesystem_apitest.cc', 'browser/chromeos/extensions/external_filesystem_apitest.cc',
'browser/chromeos/gdata/gdata_contacts_service_browsertest.cc',
'browser/chromeos/gdata/gdata_documents_service_browsertest.cc', 'browser/chromeos/gdata/gdata_documents_service_browsertest.cc',
'browser/chromeos/gdata/mock_gdata_documents_service.cc', 'browser/chromeos/gdata/mock_gdata_documents_service.cc',
'browser/chromeos/gdata/mock_gdata_documents_service.h', 'browser/chromeos/gdata/mock_gdata_documents_service.h',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment