summaryrefslogtreecommitdiffstats
path: root/chrome/browser/chromeos
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/chromeos')
-rw-r--r--chrome/browser/chromeos/chrome_browser_main_chromeos.cc9
-rw-r--r--chrome/browser/chromeos/chrome_browser_main_chromeos.h5
-rw-r--r--chrome/browser/chromeos/contacts/OWNERS2
-rw-r--r--chrome/browser/chromeos/contacts/contact.proto116
-rw-r--r--chrome/browser/chromeos/contacts/contact_database.cc343
-rw-r--r--chrome/browser/chromeos/contacts/contact_database.h139
-rw-r--r--chrome/browser/chromeos/contacts/contact_database_unittest.cc417
-rw-r--r--chrome/browser/chromeos/contacts/contact_manager.cc216
-rw-r--r--chrome/browser/chromeos/contacts/contact_manager.h135
-rw-r--r--chrome/browser/chromeos/contacts/contact_manager_observer.h29
-rw-r--r--chrome/browser/chromeos/contacts/contact_manager_stub.cc81
-rw-r--r--chrome/browser/chromeos/contacts/contact_manager_stub.h57
-rw-r--r--chrome/browser/chromeos/contacts/contact_manager_unittest.cc171
-rw-r--r--chrome/browser/chromeos/contacts/contact_map.cc62
-rw-r--r--chrome/browser/chromeos/contacts/contact_map.h71
-rw-r--r--chrome/browser/chromeos/contacts/contact_map_unittest.cc105
-rw-r--r--chrome/browser/chromeos/contacts/contact_store.h67
-rw-r--r--chrome/browser/chromeos/contacts/contact_store_observer.h29
-rw-r--r--chrome/browser/chromeos/contacts/contact_test_util.cc255
-rw-r--r--chrome/browser/chromeos/contacts/contact_test_util.h94
-rw-r--r--chrome/browser/chromeos/contacts/fake_contact_database.cc87
-rw-r--r--chrome/browser/chromeos/contacts/fake_contact_database.h73
-rw-r--r--chrome/browser/chromeos/contacts/fake_contact_store.cc112
-rw-r--r--chrome/browser/chromeos/contacts/fake_contact_store.h103
-rw-r--r--chrome/browser/chromeos/contacts/gdata_contacts_service.cc894
-rw-r--r--chrome/browser/chromeos/contacts/gdata_contacts_service.h139
-rw-r--r--chrome/browser/chromeos/contacts/gdata_contacts_service_stub.cc64
-rw-r--r--chrome/browser/chromeos/contacts/gdata_contacts_service_stub.h69
-rw-r--r--chrome/browser/chromeos/contacts/gdata_contacts_service_unittest.cc331
-rw-r--r--chrome/browser/chromeos/contacts/google_contact_store.cc434
-rw-r--r--chrome/browser/chromeos/contacts/google_contact_store.h203
-rw-r--r--chrome/browser/chromeos/contacts/google_contact_store_unittest.cc540
32 files changed, 0 insertions, 5452 deletions
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index ca8a9e8..46d57b6 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -30,7 +30,6 @@
#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
#include "chrome/browser/chromeos/app_mode/kiosk_mode_idle_app_name_notification.h"
#include "chrome/browser/chromeos/boot_times_loader.h"
-#include "chrome/browser/chromeos/contacts/contact_manager.h"
#include "chrome/browser/chromeos/dbus/cros_dbus_service.h"
#include "chrome/browser/chromeos/events/event_rewriter.h"
#include "chrome/browser/chromeos/events/system_key_event_listener.h"
@@ -492,11 +491,6 @@ void ChromeBrowserMainPartsChromeos::PreProfileInit() {
if (parsed_command_line().HasSwitch(::switches::kAllowFileAccess))
ChromeNetworkDelegate::AllowAccessToAllFiles();
- if (parsed_command_line().HasSwitch(::switches::kEnableContacts)) {
- contact_manager_.reset(new contacts::ContactManager());
- contact_manager_->Init();
- }
-
// There are two use cases for kLoginUser:
// 1) if passed in tandem with kLoginPassword, to drive a "StubLogin"
// 2) if passed alone, to signal that the indicated user has already
@@ -816,9 +810,6 @@ void ChromeBrowserMainPartsChromeos::PostMainMessageLoopRun() {
power_button_observer_.reset();
idle_action_warning_observer_.reset();
- // Delete ContactManager while |g_browser_process| is still alive.
- contact_manager_.reset();
-
MagnificationManager::Shutdown();
AccessibilityManager::Shutdown();
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.h b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
index 462d319..c9bc75e 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.h
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
@@ -10,10 +10,6 @@
#include "chrome/browser/chrome_browser_main_linux.h"
#include "chrome/browser/chromeos/version_loader.h"
-namespace contacts {
-class ContactManager;
-}
-
namespace content {
class PowerSaveBlocker;
}
@@ -61,7 +57,6 @@ class ChromeBrowserMainPartsChromeos : public ChromeBrowserMainPartsLinux {
virtual void PostDestroyThreads() OVERRIDE;
private:
- scoped_ptr<contacts::ContactManager> contact_manager_;
scoped_ptr<default_app_order::ExternalLoader> app_order_loader_;
scoped_ptr<ExtensionSystemEventObserver> extension_system_event_observer_;
scoped_ptr<PeripheralBatteryObserver> peripheral_battery_observer_;
diff --git a/chrome/browser/chromeos/contacts/OWNERS b/chrome/browser/chromeos/contacts/OWNERS
deleted file mode 100644
index 503e24c..0000000
--- a/chrome/browser/chromeos/contacts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-derat@chromium.org
-satorux@chromium.org
diff --git a/chrome/browser/chromeos/contacts/contact.proto b/chrome/browser/chromeos/contacts/contact.proto
deleted file mode 100644
index 2926b43..0000000
--- a/chrome/browser/chromeos/contacts/contact.proto
+++ /dev/null
@@ -1,116 +0,0 @@
-// 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.
-//
-// Protocol buffer definitions for the user's contacts.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-
-package contacts;
-
-// A contact, roughly based on the GData Contact kind:
-// https://developers.google.com/gdata/docs/2.0/elements#gdContactKind
-// All strings are UTF-8 with Unicode byte order marks stripped out.
-message Contact {
- // Next ID to use: 16
-
- // Provider-assigned unique identifier.
- optional string contact_id = 1;
-
- // Last time at which this contact was updated within the upstream provider,
- // as given by base::Time::ToInternalValue().
- optional int64 update_time = 2;
-
- // Has the contact been deleted recently within the upstream provider?
- optional bool deleted = 3 [default = false];
-
- // Affinity between the user and this contact, in the range [0.0, 1.0].
- // Unset if the affinity is unknown.
- optional float affinity = 15;
-
- // Taken from https://developers.google.com/gdata/docs/2.0/elements#gdName.
- optional string full_name = 4;
- optional string given_name = 5;
- optional string additional_name = 6;
- optional string family_name = 7;
- optional string name_prefix = 8;
- optional string name_suffix = 9;
-
- // Raw photo data as supplied by the provider. This data is untrusted and
- // must be decoded within a sandbox by e.g. ImageDecoder before being used.
- // Unset if no photo is available.
- optional bytes raw_untrusted_photo = 10;
-
- // Describes an address-like message's type.
- message AddressType {
- // Next ID to use: 3
- enum Relation {
- HOME = 0;
- WORK = 1;
- MOBILE = 2;
- OTHER = 3;
- }
- optional Relation relation = 1 [default = OTHER];
- optional string label = 2;
- }
-
- message EmailAddress {
- // Next ID to use: 4
- optional string address = 1;
- optional AddressType type = 2;
- optional bool primary = 3 [default = false];
- }
- repeated EmailAddress email_addresses = 11;
-
- message PhoneNumber {
- // Next ID to use: 4
- optional string number = 1;
- optional AddressType type = 2;
- optional bool primary = 3 [default = false];
- }
- repeated PhoneNumber phone_numbers = 12;
-
- message PostalAddress {
- // Next ID to use: 4
- optional string address = 1;
- optional AddressType type = 2;
- optional bool primary = 3 [default = false];
- }
- repeated PostalAddress postal_addresses = 13;
-
- message InstantMessagingAddress {
- // Next ID to use: 5
- optional string address = 1;
- // Taken from https://developers.google.com/gdata/docs/2.0/elements#gdIm.
- enum Protocol {
- AIM = 0;
- MSN = 1;
- YAHOO = 2;
- SKYPE = 3;
- QQ = 4;
- GOOGLE_TALK = 5;
- ICQ = 6;
- JABBER = 7;
- OTHER = 8;
- }
- optional Protocol protocol = 2 [default = OTHER];
- optional AddressType type = 3;
- optional bool primary = 4 [default = false];
- }
- repeated InstantMessagingAddress instant_messaging_addresses = 14;
-}
-
-// Singleton message used by ContactDatabase to store update-related metadata.
-message UpdateMetadata {
- // Next ID to use: 3
-
- // Time at which the last successful update was started, as given by
- // base::Time::ToInternalValue().
- optional int64 last_update_start_time = 1;
-
- // Latest time that we've seen in a contact's |update_time| field. Note that
- // the time may have come from a deleted contact that has been discarded.
- optional int64 last_contact_update_time = 2;
-}
diff --git a/chrome/browser/chromeos/contacts/contact_database.cc b/chrome/browser/chromeos/contacts/contact_database.cc
deleted file mode 100644
index 04eb2e8..0000000
--- a/chrome/browser/chromeos/contacts/contact_database.cc
+++ /dev/null
@@ -1,343 +0,0 @@
-// 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.
-
-#include "chrome/browser/chromeos/contacts/contact_database.h"
-
-#include <set>
-
-#include "base/file_util.h"
-#include "base/metrics/histogram.h"
-#include "base/sequenced_task_runner.h"
-#include "base/threading/sequenced_worker_pool.h"
-#include "chrome/browser/chromeos/contacts/contact.pb.h"
-#include "content/public/browser/browser_thread.h"
-#include "third_party/leveldatabase/src/include/leveldb/db.h"
-#include "third_party/leveldatabase/src/include/leveldb/iterator.h"
-#include "third_party/leveldatabase/src/include/leveldb/options.h"
-#include "third_party/leveldatabase/src/include/leveldb/slice.h"
-#include "third_party/leveldatabase/src/include/leveldb/status.h"
-#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
-
-using content::BrowserThread;
-
-namespace contacts {
-
-namespace {
-
-// Initialization results reported via the "Contacts.DatabaseInitResult"
-// histogram.
-enum HistogramInitResult {
- HISTOGRAM_INIT_RESULT_SUCCESS = 0,
- HISTOGRAM_INIT_RESULT_FAILURE = 1,
- HISTOGRAM_INIT_RESULT_DELETED_CORRUPTED = 2,
- HISTOGRAM_INIT_RESULT_MAX_VALUE = 3,
-};
-
-// Save results reported via the "Contacts.DatabaseSaveResult" histogram.
-enum HistogramSaveResult {
- HISTOGRAM_SAVE_RESULT_SUCCESS = 0,
- HISTOGRAM_SAVE_RESULT_FAILURE = 1,
- HISTOGRAM_SAVE_RESULT_MAX_VALUE = 2,
-};
-
-// Load results reported via the "Contacts.DatabaseLoadResult" histogram.
-enum HistogramLoadResult {
- HISTOGRAM_LOAD_RESULT_SUCCESS = 0,
- HISTOGRAM_LOAD_RESULT_METADATA_PARSE_FAILURE = 1,
- HISTOGRAM_LOAD_RESULT_CONTACT_PARSE_FAILURE = 2,
- HISTOGRAM_LOAD_RESULT_MAX_VALUE = 3,
-};
-
-// LevelDB key used for storing UpdateMetadata messages.
-const char kUpdateMetadataKey[] = "__chrome_update_metadata__";
-
-} // namespace
-
-ContactDatabase::ContactDatabase()
- : weak_ptr_factory_(this) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
- task_runner_ = pool->GetSequencedTaskRunner(pool->GetSequenceToken());
-}
-
-void ContactDatabase::DestroyOnUIThread() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- weak_ptr_factory_.InvalidateWeakPtrs();
- task_runner_->PostNonNestableTask(
- FROM_HERE,
- base::Bind(&ContactDatabase::DestroyFromTaskRunner,
- base::Unretained(this)));
-}
-
-void ContactDatabase::Init(const base::FilePath& database_dir,
- InitCallback callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- bool* success = new bool(false);
- task_runner_->PostTaskAndReply(
- FROM_HERE,
- base::Bind(&ContactDatabase::InitFromTaskRunner,
- base::Unretained(this),
- database_dir,
- success),
- base::Bind(&ContactDatabase::RunInitCallback,
- weak_ptr_factory_.GetWeakPtr(),
- callback,
- base::Owned(success)));
-}
-
-void ContactDatabase::SaveContacts(scoped_ptr<ContactPointers> contacts_to_save,
- scoped_ptr<ContactIds> contact_ids_to_delete,
- scoped_ptr<UpdateMetadata> metadata,
- bool is_full_update,
- SaveCallback callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- bool* success = new bool(false);
- task_runner_->PostTaskAndReply(
- FROM_HERE,
- base::Bind(&ContactDatabase::SaveContactsFromTaskRunner,
- base::Unretained(this),
- base::Passed(&contacts_to_save),
- base::Passed(&contact_ids_to_delete),
- base::Passed(&metadata),
- is_full_update,
- success),
- base::Bind(&ContactDatabase::RunSaveCallback,
- weak_ptr_factory_.GetWeakPtr(),
- callback,
- base::Owned(success)));
-}
-
-void ContactDatabase::LoadContacts(LoadCallback callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- bool* success = new bool(false);
- scoped_ptr<ScopedVector<Contact> > contacts(new ScopedVector<Contact>);
- scoped_ptr<UpdateMetadata> metadata(new UpdateMetadata);
-
- // Extract pointers before we calling Pass() so we can use them below.
- ScopedVector<Contact>* contacts_ptr = contacts.get();
- UpdateMetadata* metadata_ptr = metadata.get();
-
- task_runner_->PostTaskAndReply(
- FROM_HERE,
- base::Bind(&ContactDatabase::LoadContactsFromTaskRunner,
- base::Unretained(this),
- success,
- contacts_ptr,
- metadata_ptr),
- base::Bind(&ContactDatabase::RunLoadCallback,
- weak_ptr_factory_.GetWeakPtr(),
- callback,
- base::Owned(success),
- base::Passed(&contacts),
- base::Passed(&metadata)));
-}
-
-ContactDatabase::~ContactDatabase() {
- DCHECK(IsRunByTaskRunner());
-}
-
-bool ContactDatabase::IsRunByTaskRunner() const {
- return BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread();
-}
-
-void ContactDatabase::DestroyFromTaskRunner() {
- DCHECK(IsRunByTaskRunner());
- delete this;
-}
-
-void ContactDatabase::RunInitCallback(InitCallback callback,
- const bool* success) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- callback.Run(*success);
-}
-
-void ContactDatabase::RunSaveCallback(SaveCallback callback,
- const bool* success) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- callback.Run(*success);
-}
-
-void ContactDatabase::RunLoadCallback(
- LoadCallback callback,
- const bool* success,
- scoped_ptr<ScopedVector<Contact> > contacts,
- scoped_ptr<UpdateMetadata> metadata) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- callback.Run(*success, contacts.Pass(), metadata.Pass());
-}
-
-void ContactDatabase::InitFromTaskRunner(const base::FilePath& database_dir,
- bool* success) {
- DCHECK(IsRunByTaskRunner());
- DCHECK(success);
-
- VLOG(1) << "Opening " << database_dir.value();
- UMA_HISTOGRAM_MEMORY_KB("Contacts.DatabaseSizeBytes",
- base::ComputeDirectorySize(database_dir));
- *success = false;
- HistogramInitResult histogram_result = HISTOGRAM_INIT_RESULT_SUCCESS;
-
- leveldb::Options options;
- options.create_if_missing = true;
- options.max_open_files = 0; // Use minimum.
- bool delete_and_retry_on_corruption = true;
-
- while (true) {
- leveldb::DB* db = NULL;
- leveldb::Status status =
- leveldb::DB::Open(options, database_dir.value(), &db);
- if (status.ok()) {
- CHECK(db);
- db_.reset(db);
- *success = true;
- return;
- }
-
- LOG(WARNING) << "Unable to open " << database_dir.value() << ": "
- << status.ToString();
-
- // Delete the existing database and try again (just once, though).
- if (status.IsCorruption() && delete_and_retry_on_corruption) {
- LOG(WARNING) << "Deleting possibly-corrupt database";
- base::DeleteFile(database_dir, true);
- delete_and_retry_on_corruption = false;
- histogram_result = HISTOGRAM_INIT_RESULT_DELETED_CORRUPTED;
- } else {
- histogram_result = HISTOGRAM_INIT_RESULT_FAILURE;
- break;
- }
- }
-
- UMA_HISTOGRAM_ENUMERATION("Contacts.DatabaseInitResult",
- histogram_result,
- HISTOGRAM_INIT_RESULT_MAX_VALUE);
-}
-
-void ContactDatabase::SaveContactsFromTaskRunner(
- scoped_ptr<ContactPointers> contacts_to_save,
- scoped_ptr<ContactIds> contact_ids_to_delete,
- scoped_ptr<UpdateMetadata> metadata,
- bool is_full_update,
- bool* success) {
- DCHECK(IsRunByTaskRunner());
- DCHECK(success);
- VLOG(1) << "Saving " << contacts_to_save->size() << " contact(s) to database "
- << "and deleting " << contact_ids_to_delete->size() << " as "
- << (is_full_update ? "full" : "incremental") << " update";
-
- *success = false;
-
- // If we're doing a full update, find all of the existing keys first so we can
- // delete ones that aren't present in the new set of contacts.
- std::set<std::string> keys_to_delete;
- if (is_full_update) {
- leveldb::ReadOptions options;
- scoped_ptr<leveldb::Iterator> db_iterator(db_->NewIterator(options));
- db_iterator->SeekToFirst();
- while (db_iterator->Valid()) {
- std::string key = db_iterator->key().ToString();
- if (key != kUpdateMetadataKey)
- keys_to_delete.insert(key);
- db_iterator->Next();
- }
- } else {
- for (ContactIds::const_iterator it = contact_ids_to_delete->begin();
- it != contact_ids_to_delete->end(); ++it) {
- keys_to_delete.insert(*it);
- }
- }
-
- // TODO(derat): Serializing all of the contacts and so we can write them in a
- // single batch may be expensive, memory-wise. Consider writing them in
- // several batches instead. (To avoid using partial writes in the event of a
- // crash, maybe add a dummy "write completed" contact that's removed in the
- // first batch and added in the last.)
- leveldb::WriteBatch updates;
- for (ContactPointers::const_iterator it = contacts_to_save->begin();
- it != contacts_to_save->end(); ++it) {
- const contacts::Contact& contact = **it;
- if (contact.contact_id() == kUpdateMetadataKey) {
- LOG(WARNING) << "Skipping contact with reserved ID "
- << contact.contact_id();
- continue;
- }
- updates.Put(leveldb::Slice(contact.contact_id()),
- leveldb::Slice(contact.SerializeAsString()));
- if (is_full_update)
- keys_to_delete.erase(contact.contact_id());
- }
-
- for (std::set<std::string>::const_iterator it = keys_to_delete.begin();
- it != keys_to_delete.end(); ++it) {
- updates.Delete(leveldb::Slice(*it));
- }
-
- updates.Put(leveldb::Slice(kUpdateMetadataKey),
- leveldb::Slice(metadata->SerializeAsString()));
-
- leveldb::WriteOptions options;
- options.sync = true;
- leveldb::Status status = db_->Write(options, &updates);
- if (status.ok())
- *success = true;
- else
- LOG(WARNING) << "Failed writing contacts: " << status.ToString();
-
- UMA_HISTOGRAM_ENUMERATION("Contacts.DatabaseSaveResult",
- *success ?
- HISTOGRAM_SAVE_RESULT_SUCCESS :
- HISTOGRAM_SAVE_RESULT_FAILURE,
- HISTOGRAM_SAVE_RESULT_MAX_VALUE);
-}
-
-void ContactDatabase::LoadContactsFromTaskRunner(
- bool* success,
- ScopedVector<Contact>* contacts,
- UpdateMetadata* metadata) {
- DCHECK(IsRunByTaskRunner());
- DCHECK(success);
- DCHECK(contacts);
- DCHECK(metadata);
-
- *success = false;
- contacts->clear();
- metadata->Clear();
-
- leveldb::ReadOptions options;
- scoped_ptr<leveldb::Iterator> db_iterator(db_->NewIterator(options));
- db_iterator->SeekToFirst();
- while (db_iterator->Valid()) {
- leveldb::Slice value_slice = db_iterator->value();
-
- if (db_iterator->key().ToString() == kUpdateMetadataKey) {
- if (!metadata->ParseFromArray(value_slice.data(), value_slice.size())) {
- LOG(WARNING) << "Unable to parse metadata";
- UMA_HISTOGRAM_ENUMERATION("Contacts.DatabaseLoadResult",
- HISTOGRAM_LOAD_RESULT_METADATA_PARSE_FAILURE,
- HISTOGRAM_LOAD_RESULT_MAX_VALUE);
- return;
- }
- } else {
- scoped_ptr<Contact> contact(new Contact);
- if (!contact->ParseFromArray(value_slice.data(), value_slice.size())) {
- LOG(WARNING) << "Unable to parse contact "
- << db_iterator->key().ToString();
- UMA_HISTOGRAM_ENUMERATION("Contacts.DatabaseLoadResult",
- HISTOGRAM_LOAD_RESULT_CONTACT_PARSE_FAILURE,
- HISTOGRAM_LOAD_RESULT_MAX_VALUE);
- return;
- }
- contacts->push_back(contact.release());
- }
- db_iterator->Next();
- }
-
- *success = true;
- UMA_HISTOGRAM_ENUMERATION("Contacts.DatabaseLoadResult",
- HISTOGRAM_LOAD_RESULT_SUCCESS,
- HISTOGRAM_LOAD_RESULT_MAX_VALUE);
-}
-
-} // namespace contacts
diff --git a/chrome/browser/chromeos/contacts/contact_database.h b/chrome/browser/chromeos/contacts/contact_database.h
deleted file mode 100644
index d4074df..0000000
--- a/chrome/browser/chromeos/contacts/contact_database.h
+++ /dev/null
@@ -1,139 +0,0 @@
-// 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_CONTACTS_CONTACT_DATABASE_H_
-#define CHROME_BROWSER_CHROMEOS_CONTACTS_CONTACT_DATABASE_H_
-
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/files/file_path.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "base/memory/weak_ptr.h"
-
-namespace base {
-class SequencedTaskRunner;
-}
-
-namespace leveldb {
-class DB;
-}
-
-namespace contacts {
-
-class Contact;
-class UpdateMetadata;
-typedef std::vector<const Contact*> ContactPointers;
-
-// Interface for classes providing persistent storage of Contact objects.
-class ContactDatabaseInterface {
- public:
- typedef std::vector<std::string> ContactIds;
- typedef base::Callback<void(bool success)> InitCallback;
- typedef base::Callback<void(bool success)> SaveCallback;
- typedef base::Callback<void(bool success,
- scoped_ptr<ScopedVector<Contact> >,
- scoped_ptr<UpdateMetadata>)>
- LoadCallback;
-
- // Asynchronously destroys the object after all in-progress file operations
- // have completed.
- virtual void DestroyOnUIThread() {}
-
- // Asynchronously initializes the object. |callback| will be invoked on the
- // UI thread when complete.
- virtual void Init(const base::FilePath& database_dir,
- InitCallback callback) = 0;
-
- // Asynchronously saves |contacts_to_save| and |metadata| to the database and
- // removes contacts with IDs contained in |contact_ids_to_delete|. If
- // |is_full_update| is true, all existing contacts in the database not present
- // in |contacts_to_save| will be removed. |callback| will be invoked on the
- // UI thread when complete. The caller must not make changes to the
- // underlying passed-in Contact objects until the callback has been invoked.
- virtual void SaveContacts(scoped_ptr<ContactPointers> contacts_to_save,
- scoped_ptr<ContactIds> contact_ids_to_delete,
- scoped_ptr<UpdateMetadata> metadata,
- bool is_full_update,
- SaveCallback callback) = 0;
-
- // Asynchronously loads all contacts from the database and invokes |callback|
- // when complete.
- virtual void LoadContacts(LoadCallback callback) = 0;
-
- protected:
- virtual ~ContactDatabaseInterface() {}
-};
-
-class ContactDatabase : public ContactDatabaseInterface {
- public:
- ContactDatabase();
-
- // ContactDatabaseInterface implementation.
- virtual void DestroyOnUIThread() OVERRIDE;
- virtual void Init(const base::FilePath& database_dir,
- InitCallback callback) OVERRIDE;
- virtual void SaveContacts(scoped_ptr<ContactPointers> contacts_to_save,
- scoped_ptr<ContactIds> contact_ids_to_delete,
- scoped_ptr<UpdateMetadata> metadata,
- bool is_full_update,
- SaveCallback callback) OVERRIDE;
- virtual void LoadContacts(LoadCallback callback) OVERRIDE;
-
- protected:
- virtual ~ContactDatabase();
-
- private:
- // Are we currently being run by |task_runner_|?
- bool IsRunByTaskRunner() const;
-
- // Deletes |this|.
- void DestroyFromTaskRunner();
-
- // Passes the supplied parameters to |callback| after being called on the UI
- // thread. Used for replies sent in response to |task_runner_|'s tasks, so
- // that weak_ptrs can be used to avoid running the replies after the
- // ContactDatabase has been deleted.
- void RunInitCallback(InitCallback callback, const bool* success);
- void RunSaveCallback(SaveCallback callback, const bool* success);
- void RunLoadCallback(LoadCallback callback,
- const bool* success,
- scoped_ptr<ScopedVector<Contact> > contacts,
- scoped_ptr<UpdateMetadata> metadata);
-
- // Initializes the database in |database_dir| and updates |success|.
- void InitFromTaskRunner(const base::FilePath& database_dir, bool* success);
-
- // Saves data to disk and updates |success|.
- void SaveContactsFromTaskRunner(scoped_ptr<ContactPointers> contacts_to_save,
- scoped_ptr<ContactIds> contact_ids_to_delete,
- scoped_ptr<UpdateMetadata> metadata,
- bool is_full_update,
- bool* success);
-
- // Loads contacts from disk and updates |success|.
- void LoadContactsFromTaskRunner(bool* success,
- ScopedVector<Contact>* contacts,
- UpdateMetadata* metadata);
-
- // Used to run blocking tasks in-order.
- scoped_refptr<base::SequencedTaskRunner> task_runner_;
-
- scoped_ptr<leveldb::DB> db_;
-
- // Note: This should remain the last member so it'll be destroyed and
- // invalidate its weak pointers before any other members are destroyed.
- base::WeakPtrFactory<ContactDatabase> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ContactDatabase);
-};
-
-} // namespace contacts
-
-#endif // CHROME_BROWSER_CHROMEOS_CONTACTS_CONTACT_DATABASE_H_
diff --git a/chrome/browser/chromeos/contacts/contact_database_unittest.cc b/chrome/browser/chromeos/contacts/contact_database_unittest.cc
deleted file mode 100644
index 8942da0..0000000
--- a/chrome/browser/chromeos/contacts/contact_database_unittest.cc
+++ /dev/null
@@ -1,417 +0,0 @@
-// 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.
-
-#include "chrome/browser/chromeos/contacts/contact_database.h"
-
-#include <string>
-
-#include "base/bind.h"
-#include "base/file_util.h"
-#include "base/files/file_enumerator.h"
-#include "base/files/file_path.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "base/message_loop/message_loop.h"
-#include "chrome/browser/chromeos/contacts/contact.pb.h"
-#include "chrome/browser/chromeos/contacts/contact_test_util.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/test/test_browser_thread.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/size.h"
-
-using content::BrowserThread;
-
-namespace contacts {
-namespace test {
-
-// Name of the directory created within a temporary directory to store the
-// contacts database.
-const base::FilePath::CharType kDatabaseDirectoryName[] =
- FILE_PATH_LITERAL("contacts");
-
-class ContactDatabaseTest : public testing::Test {
- public:
- ContactDatabaseTest()
- : ui_thread_(BrowserThread::UI, &message_loop_),
- db_(NULL) {
- }
-
- virtual ~ContactDatabaseTest() {
- }
-
- protected:
- // testing::Test implementation.
- virtual void SetUp() OVERRIDE {
- CHECK(temp_dir_.CreateUniqueTempDir());
- CreateDatabase();
- }
-
- virtual void TearDown() OVERRIDE {
- DestroyDatabase();
- }
-
- protected:
- base::FilePath database_path() const {
- return temp_dir_.path().Append(kDatabaseDirectoryName);
- }
-
- void CreateDatabase() {
- DestroyDatabase();
- db_ = new ContactDatabase;
- db_->Init(database_path(),
- base::Bind(&ContactDatabaseTest::OnDatabaseInitialized,
- base::Unretained(this)));
-
- // The database will be initialized on the file thread; run the message loop
- // until that happens.
- message_loop_.Run();
- }
-
- void DestroyDatabase() {
- if (db_) {
- db_->DestroyOnUIThread();
- db_ = NULL;
- }
- }
-
- // Calls ContactDatabase::SaveContacts() and blocks until the operation is
- // complete.
- void SaveContacts(scoped_ptr<ContactPointers> contacts_to_save,
- scoped_ptr<ContactDatabaseInterface::ContactIds>
- contact_ids_to_delete,
- scoped_ptr<UpdateMetadata> metadata,
- bool is_full_update) {
- CHECK(db_);
- db_->SaveContacts(contacts_to_save.Pass(),
- contact_ids_to_delete.Pass(),
- metadata.Pass(),
- is_full_update,
- base::Bind(&ContactDatabaseTest::OnContactsSaved,
- base::Unretained(this)));
- message_loop_.Run();
- }
-
- // Calls ContactDatabase::LoadContacts() and blocks until the operation is
- // complete.
- void LoadContacts(scoped_ptr<ScopedVector<Contact> >* contacts_out,
- scoped_ptr<UpdateMetadata>* metadata_out) {
- CHECK(db_);
- db_->LoadContacts(base::Bind(&ContactDatabaseTest::OnContactsLoaded,
- base::Unretained(this)));
- message_loop_.Run();
- contacts_out->swap(loaded_contacts_);
- metadata_out->swap(loaded_metadata_);
- }
-
- private:
- void OnDatabaseInitialized(bool success) {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- CHECK(success);
- // TODO(derat): Move google_apis::test::RunBlockingPoolTask() to a shared
- // location and use it for these tests.
- message_loop_.Quit();
- }
-
- void OnContactsSaved(bool success) {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- CHECK(success);
- message_loop_.Quit();
- }
-
- void OnContactsLoaded(bool success,
- scoped_ptr<ScopedVector<Contact> > contacts,
- scoped_ptr<UpdateMetadata> metadata) {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- CHECK(success);
- loaded_contacts_.swap(contacts);
- loaded_metadata_.swap(metadata);
- message_loop_.Quit();
- }
-
- base::MessageLoopForUI message_loop_;
- content::TestBrowserThread ui_thread_;
-
- // Temporary directory where the database is saved.
- base::ScopedTempDir temp_dir_;
-
- // This class retains ownership of this object.
- ContactDatabase* db_;
-
- // Contacts and metadata returned by the most-recent
- // ContactDatabase::LoadContacts() call. Used to pass returned values from
- // OnContactsLoaded() to LoadContacts().
- scoped_ptr<ScopedVector<Contact> > loaded_contacts_;
- scoped_ptr<UpdateMetadata> loaded_metadata_;
-
- DISALLOW_COPY_AND_ASSIGN(ContactDatabaseTest);
-};
-
-TEST_F(ContactDatabaseTest, SaveAndReload) {
- // Save a contact to the database and check that we get the same data back
- // when loading it.
- const std::string kContactId = "contact_id_1";
- scoped_ptr<Contact> contact(new Contact);
- InitContact(kContactId, "1", false, contact.get());
- AddEmailAddress("email_1", Contact_AddressType_Relation_HOME,
- "email_label_1", true, contact.get());
- AddEmailAddress("email_2", Contact_AddressType_Relation_WORK,
- "", false, contact.get());
- AddPhoneNumber("123-456-7890", Contact_AddressType_Relation_HOME,
- "phone_label", true, contact.get());
- AddPostalAddress("postal_1", Contact_AddressType_Relation_HOME,
- "postal_label_1", true, contact.get());
- AddPostalAddress("postal_2", Contact_AddressType_Relation_OTHER,
- "postal_label_2", false, contact.get());
- AddInstantMessagingAddress("im_1",
- Contact_InstantMessagingAddress_Protocol_AIM,
- Contact_AddressType_Relation_HOME,
- "im_label_1", true, contact.get());
- SetPhoto(gfx::Size(20, 20), contact.get());
- scoped_ptr<ContactPointers> contacts_to_save(new ContactPointers);
- contacts_to_save->push_back(contact.get());
- scoped_ptr<ContactDatabaseInterface::ContactIds> contact_ids_to_delete(
- new ContactDatabaseInterface::ContactIds);
-
- const int64 kLastUpdateTime = 1234;
- scoped_ptr<UpdateMetadata> metadata_to_save(new UpdateMetadata);
- metadata_to_save->set_last_update_start_time(kLastUpdateTime);
-
- SaveContacts(contacts_to_save.Pass(),
- contact_ids_to_delete.Pass(),
- metadata_to_save.Pass(),
- true);
- scoped_ptr<ScopedVector<Contact> > loaded_contacts;
- scoped_ptr<UpdateMetadata> loaded_metadata;
- LoadContacts(&loaded_contacts, &loaded_metadata);
- EXPECT_EQ(VarContactsToString(1, contact.get()),
- ContactsToString(*loaded_contacts));
- EXPECT_EQ(kLastUpdateTime, loaded_metadata->last_update_start_time());
-
- // Modify the contact, save it, and check that the loaded contact is also
- // updated.
- InitContact(kContactId, "2", false, contact.get());
- AddEmailAddress("email_3", Contact_AddressType_Relation_OTHER,
- "email_label_2", true, contact.get());
- AddPhoneNumber("phone_2", Contact_AddressType_Relation_OTHER,
- "phone_label_2", false, contact.get());
- AddPostalAddress("postal_3", Contact_AddressType_Relation_HOME,
- "postal_label_3", true, contact.get());
- SetPhoto(gfx::Size(64, 64), contact.get());
- contacts_to_save.reset(new ContactPointers);
- contacts_to_save->push_back(contact.get());
- contact_ids_to_delete.reset(new ContactDatabaseInterface::ContactIds);
- metadata_to_save.reset(new UpdateMetadata);
- const int64 kNewLastUpdateTime = 5678;
- metadata_to_save->set_last_update_start_time(kNewLastUpdateTime);
- SaveContacts(contacts_to_save.Pass(),
- contact_ids_to_delete.Pass(),
- metadata_to_save.Pass(),
- true);
-
- LoadContacts(&loaded_contacts, &loaded_metadata);
- EXPECT_EQ(VarContactsToString(1, contact.get()),
- ContactsToString(*loaded_contacts));
- EXPECT_EQ(kNewLastUpdateTime, loaded_metadata->last_update_start_time());
-}
-
-TEST_F(ContactDatabaseTest, FullAndIncrementalUpdates) {
- // Do a full update that inserts two contacts into the database.
- const std::string kContactId1 = "contact_id_1";
- const std::string kSharedEmail = "foo@example.org";
- scoped_ptr<Contact> contact1(new Contact);
- InitContact(kContactId1, "1", false, contact1.get());
- AddEmailAddress(kSharedEmail, Contact_AddressType_Relation_HOME,
- "", true, contact1.get());
-
- const std::string kContactId2 = "contact_id_2";
- scoped_ptr<Contact> contact2(new Contact);
- InitContact(kContactId2, "2", false, contact2.get());
- AddEmailAddress(kSharedEmail, Contact_AddressType_Relation_WORK,
- "", true, contact2.get());
-
- scoped_ptr<ContactPointers> contacts_to_save(new ContactPointers);
- contacts_to_save->push_back(contact1.get());
- contacts_to_save->push_back(contact2.get());
- scoped_ptr<ContactDatabaseInterface::ContactIds> contact_ids_to_delete(
- new ContactDatabaseInterface::ContactIds);
- scoped_ptr<UpdateMetadata> metadata_to_save(new UpdateMetadata);
- SaveContacts(contacts_to_save.Pass(),
- contact_ids_to_delete.Pass(),
- metadata_to_save.Pass(),
- true);
-
- scoped_ptr<ScopedVector<Contact> > loaded_contacts;
- scoped_ptr<UpdateMetadata> loaded_metadata;
- LoadContacts(&loaded_contacts, &loaded_metadata);
- EXPECT_EQ(VarContactsToString(2, contact1.get(), contact2.get()),
- ContactsToString(*loaded_contacts));
-
- // Do an incremental update including just the second contact.
- InitContact(kContactId2, "2b", false, contact2.get());
- AddPostalAddress("postal_1", Contact_AddressType_Relation_HOME,
- "", true, contact2.get());
- contacts_to_save.reset(new ContactPointers);
- contacts_to_save->push_back(contact2.get());
- contact_ids_to_delete.reset(new ContactDatabaseInterface::ContactIds);
- metadata_to_save.reset(new UpdateMetadata);
- SaveContacts(contacts_to_save.Pass(),
- contact_ids_to_delete.Pass(),
- metadata_to_save.Pass(),
- false);
- LoadContacts(&loaded_contacts, &loaded_metadata);
- EXPECT_EQ(VarContactsToString(2, contact1.get(), contact2.get()),
- ContactsToString(*loaded_contacts));
-
- // Do an empty incremental update and check that the metadata is still
- // updated.
- contacts_to_save.reset(new ContactPointers);
- contact_ids_to_delete.reset(new ContactDatabaseInterface::ContactIds);
- metadata_to_save.reset(new UpdateMetadata);
- const int64 kLastUpdateTime = 1234;
- metadata_to_save->set_last_update_start_time(kLastUpdateTime);
- SaveContacts(contacts_to_save.Pass(),
- contact_ids_to_delete.Pass(),
- metadata_to_save.Pass(),
- false);
- LoadContacts(&loaded_contacts, &loaded_metadata);
- EXPECT_EQ(VarContactsToString(2, contact1.get(), contact2.get()),
- ContactsToString(*loaded_contacts));
- EXPECT_EQ(kLastUpdateTime, loaded_metadata->last_update_start_time());
-
- // Do a full update including just the first contact. The second contact
- // should be removed from the database.
- InitContact(kContactId1, "1b", false, contact1.get());
- AddPostalAddress("postal_2", Contact_AddressType_Relation_WORK,
- "", true, contact1.get());
- AddPhoneNumber("phone", Contact_AddressType_Relation_HOME,
- "", true, contact1.get());
- contacts_to_save.reset(new ContactPointers);
- contacts_to_save->push_back(contact1.get());
- contact_ids_to_delete.reset(new ContactDatabaseInterface::ContactIds);
- metadata_to_save.reset(new UpdateMetadata);
- SaveContacts(contacts_to_save.Pass(),
- contact_ids_to_delete.Pass(),
- metadata_to_save.Pass(),
- true);
- LoadContacts(&loaded_contacts, &loaded_metadata);
- EXPECT_EQ(VarContactsToString(1, contact1.get()),
- ContactsToString(*loaded_contacts));
-
- // Do a full update including no contacts. The database should be cleared.
- contacts_to_save.reset(new ContactPointers);
- contact_ids_to_delete.reset(new ContactDatabaseInterface::ContactIds);
- metadata_to_save.reset(new UpdateMetadata);
- SaveContacts(contacts_to_save.Pass(),
- contact_ids_to_delete.Pass(),
- metadata_to_save.Pass(),
- true);
- LoadContacts(&loaded_contacts, &loaded_metadata);
- EXPECT_TRUE(loaded_contacts->empty());
-}
-
-// Test that we create a new database when we encounter a corrupted one.
-TEST_F(ContactDatabaseTest, DeleteWhenCorrupt) {
- DestroyDatabase();
- // Overwrite all of the files in the database with a space character.
- base::FileEnumerator enumerator(
- database_path(), false, base::FileEnumerator::FILES);
- for (base::FilePath path = enumerator.Next(); !path.empty();
- path = enumerator.Next()) {
- base::WriteFile(path, " ", 1);
- }
- CreateDatabase();
-
- // Make sure that the resulting database is usable.
- scoped_ptr<Contact> contact(new Contact);
- InitContact("1", "1", false, contact.get());
- scoped_ptr<ContactPointers> contacts_to_save(new ContactPointers);
- contacts_to_save->push_back(contact.get());
- scoped_ptr<ContactDatabaseInterface::ContactIds> contact_ids_to_delete(
- new ContactDatabaseInterface::ContactIds);
- scoped_ptr<UpdateMetadata> metadata_to_save(new UpdateMetadata);
- SaveContacts(contacts_to_save.Pass(),
- contact_ids_to_delete.Pass(),
- metadata_to_save.Pass(),
- true);
-
- scoped_ptr<ScopedVector<Contact> > loaded_contacts;
- scoped_ptr<UpdateMetadata> loaded_metadata;
- LoadContacts(&loaded_contacts, &loaded_metadata);
- EXPECT_EQ(VarContactsToString(1, contact.get()),
- ContactsToString(*loaded_contacts));
-}
-
-TEST_F(ContactDatabaseTest, DeleteRequestedContacts) {
- // Insert two contacts into the database with a full update.
- const std::string kContactId1 = "contact_id_1";
- scoped_ptr<Contact> contact1(new Contact);
- InitContact(kContactId1, "1", false, contact1.get());
- const std::string kContactId2 = "contact_id_2";
- scoped_ptr<Contact> contact2(new Contact);
- InitContact(kContactId2, "2", false, contact2.get());
-
- scoped_ptr<ContactPointers> contacts_to_save(new ContactPointers);
- contacts_to_save->push_back(contact1.get());
- contacts_to_save->push_back(contact2.get());
- scoped_ptr<ContactDatabaseInterface::ContactIds> contact_ids_to_delete(
- new ContactDatabaseInterface::ContactIds);
- scoped_ptr<UpdateMetadata> metadata_to_save(new UpdateMetadata);
- SaveContacts(contacts_to_save.Pass(),
- contact_ids_to_delete.Pass(),
- metadata_to_save.Pass(),
- true);
-
- // Do an incremental update that inserts a third contact and deletes the first
- // contact.
- const std::string kContactId3 = "contact_id_3";
- scoped_ptr<Contact> contact3(new Contact);
- InitContact(kContactId3, "3", false, contact3.get());
-
- contacts_to_save.reset(new ContactPointers);
- contacts_to_save->push_back(contact3.get());
- contact_ids_to_delete.reset(new ContactDatabaseInterface::ContactIds);
- contact_ids_to_delete->push_back(kContactId1);
- metadata_to_save.reset(new UpdateMetadata);
- SaveContacts(contacts_to_save.Pass(),
- contact_ids_to_delete.Pass(),
- metadata_to_save.Pass(),
- false);
-
- // LoadContacts() should return only the second and third contacts.
- scoped_ptr<ScopedVector<Contact> > loaded_contacts;
- scoped_ptr<UpdateMetadata> loaded_metadata;
- LoadContacts(&loaded_contacts, &loaded_metadata);
- EXPECT_EQ(VarContactsToString(2, contact2.get(), contact3.get()),
- ContactsToString(*loaded_contacts));
-
- // Do another incremental update that deletes the second contact.
- contacts_to_save.reset(new ContactPointers);
- contact_ids_to_delete.reset(new ContactDatabaseInterface::ContactIds);
- contact_ids_to_delete->push_back(kContactId2);
- metadata_to_save.reset(new UpdateMetadata);
- SaveContacts(contacts_to_save.Pass(),
- contact_ids_to_delete.Pass(),
- metadata_to_save.Pass(),
- false);
- LoadContacts(&loaded_contacts, &loaded_metadata);
- EXPECT_EQ(VarContactsToString(1, contact3.get()),
- ContactsToString(*loaded_contacts));
-
- // Deleting a contact that isn't present should be a no-op.
- contacts_to_save.reset(new ContactPointers);
- contact_ids_to_delete.reset(new ContactDatabaseInterface::ContactIds);
- contact_ids_to_delete->push_back("bogus_id");
- metadata_to_save.reset(new UpdateMetadata);
- SaveContacts(contacts_to_save.Pass(),
- contact_ids_to_delete.Pass(),
- metadata_to_save.Pass(),
- false);
- LoadContacts(&loaded_contacts, &loaded_metadata);
- EXPECT_EQ(VarContactsToString(1, contact3.get()),
- ContactsToString(*loaded_contacts));
-}
-
-} // namespace test
-} // namespace contacts
diff --git a/chrome/browser/chromeos/contacts/contact_manager.cc b/chrome/browser/chromeos/contacts/contact_manager.cc
deleted file mode 100644
index 76694e0..0000000
--- a/chrome/browser/chromeos/contacts/contact_manager.cc
+++ /dev/null
@@ -1,216 +0,0 @@
-// 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.
-
-#include "chrome/browser/chromeos/contacts/contact_manager.h"
-
-#include "base/logging.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/contacts/contact.pb.h"
-#include "chrome/browser/chromeos/contacts/contact_manager_observer.h"
-#include "chrome/browser/chromeos/contacts/contact_store.h"
-#include "chrome/browser/chromeos/contacts/google_contact_store.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/notification_service.h"
-
-using content::BrowserThread;
-
-namespace contacts {
-
-namespace {
-
-// Singleton instance.
-ContactManager* g_instance = NULL;
-
-} // namespace
-
-// static
-ContactManager* ContactManager::GetInstance() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(g_instance);
- return g_instance;
-}
-
-ContactManager::ContactManager()
- : profile_observers_deleter_(&profile_observers_),
- contact_store_factory_(new GoogleContactStoreFactory),
- contact_stores_deleter_(&contact_stores_),
- weak_ptr_factory_(this) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(!g_instance);
- g_instance = this;
-}
-
-ContactManager::~ContactManager() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK_EQ(g_instance, this);
- weak_ptr_factory_.InvalidateWeakPtrs();
- g_instance = NULL;
- for (ContactStoreMap::const_iterator it = contact_stores_.begin();
- it != contact_stores_.end(); ++it) {
- it->second->RemoveObserver(this);
- }
-}
-
-void ContactManager::SetContactStoreForTesting(
- scoped_ptr<ContactStoreFactory> factory) {
- DCHECK(contact_stores_.empty());
- contact_store_factory_.swap(factory);
-}
-
-void ContactManager::Init() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- registrar_.Add(
- this,
- chrome::NOTIFICATION_PROFILE_CREATED,
- content::NotificationService::AllSources());
- registrar_.Add(
- this,
- chrome::NOTIFICATION_PROFILE_DESTROYED,
- content::NotificationService::AllSources());
-
- // Notify about any already-existing profiles.
- std::vector<Profile*> profiles(
- g_browser_process->profile_manager()->GetLoadedProfiles());
- for (size_t i = 0; i < profiles.size(); ++i)
- HandleProfileCreated(profiles[i]);
-}
-
-base::WeakPtr<ContactManagerInterface> ContactManager::GetWeakPtr() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- return weak_ptr_factory_.GetWeakPtr();
-}
-
-void ContactManager::AddObserver(ContactManagerObserver* observer,
- Profile* profile) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(observer);
- DCHECK(profile);
- Observers* observers = GetObserversForProfile(profile, true);
- observers->AddObserver(observer);
-}
-
-void ContactManager::RemoveObserver(ContactManagerObserver* observer,
- Profile* profile) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(observer);
- DCHECK(profile);
- Observers* observers = GetObserversForProfile(profile, false);
- if (observers)
- observers->RemoveObserver(observer);
-}
-
-scoped_ptr<ContactPointers> ContactManager::GetAllContacts(Profile* profile) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(profile);
- scoped_ptr<ContactPointers> contacts(new ContactPointers);
- ContactStoreMap::const_iterator it = contact_stores_.find(profile);
- if (it != contact_stores_.end())
- it->second->AppendContacts(contacts.get());
- return contacts.Pass();
-}
-
-const Contact* ContactManager::GetContactById(Profile* profile,
- const std::string& contact_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(profile);
- ContactStoreMap::const_iterator it = contact_stores_.find(profile);
- return it != contact_stores_.end() ?
- it->second->GetContactById(contact_id) :
- NULL;
-}
-
-void ContactManager::OnContactsUpdated(ContactStore* store) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- for (ContactStoreMap::const_iterator it = contact_stores_.begin();
- it != contact_stores_.end(); ++it) {
- if (it->second == store) {
- Profile* profile = it->first;
- Observers* observers = GetObserversForProfile(profile, false);
- if (observers) {
- FOR_EACH_OBSERVER(ContactManagerObserver,
- *observers,
- OnContactsUpdated(profile));
- }
- return;
- }
- }
- NOTREACHED() << "Got update from unknown contact store " << store;
-}
-
-void ContactManager::Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- switch (type) {
- case chrome::NOTIFICATION_PROFILE_CREATED:
- HandleProfileCreated(content::Source<Profile>(source).ptr());
- break;
- case chrome::NOTIFICATION_PROFILE_DESTROYED: {
- Profile* profile = content::Details<Profile>(details).ptr();
- if (profile)
- HandleProfileDestroyed(profile);
- break;
- }
- default:
- NOTREACHED() << "Unexpected notification " << type;
- }
-}
-
-ContactManager::Observers* ContactManager::GetObserversForProfile(
- Profile* profile,
- bool create) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- ProfileObserversMap::const_iterator it = profile_observers_.find(profile);
- if (it != profile_observers_.end())
- return it->second;
- if (!create)
- return NULL;
-
- Observers* observers = new Observers;
- profile_observers_[profile] = observers;
- return observers;
-}
-
-void ContactManager::HandleProfileCreated(Profile* profile) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(profile);
-
- ContactStoreMap::iterator it = contact_stores_.find(profile);
- if (it != contact_stores_.end())
- return;
-
- if (!contact_store_factory_->CanCreateContactStoreForProfile(profile))
- return;
-
- VLOG(1) << "Adding profile " << profile->GetProfileName();
- ContactStore* store = contact_store_factory_->CreateContactStore(profile);
- DCHECK(store);
- store->AddObserver(this);
- store->Init();
- DCHECK_EQ(contact_stores_.count(profile), static_cast<size_t>(0));
- contact_stores_[profile] = store;
-}
-
-void ContactManager::HandleProfileDestroyed(Profile* profile) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(profile);
-
- ContactStoreMap::iterator store_it = contact_stores_.find(profile);
- if (store_it != contact_stores_.end()) {
- store_it->second->RemoveObserver(this);
- delete store_it->second;
- contact_stores_.erase(store_it);
- }
-
- ProfileObserversMap::iterator observer_it = profile_observers_.find(profile);
- if (observer_it != profile_observers_.end()) {
- delete observer_it->second;
- profile_observers_.erase(observer_it);
- }
-}
-
-} // namespace contacts
diff --git a/chrome/browser/chromeos/contacts/contact_manager.h b/chrome/browser/chromeos/contacts/contact_manager.h
deleted file mode 100644
index 0e508ff..0000000
--- a/chrome/browser/chromeos/contacts/contact_manager.h
+++ /dev/null
@@ -1,135 +0,0 @@
-// 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_CONTACTS_CONTACT_MANAGER_H_
-#define CHROME_BROWSER_CHROMEOS_CONTACTS_CONTACT_MANAGER_H_
-
-#include <map>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
-#include "base/stl_util.h"
-#include "chrome/browser/chromeos/contacts/contact_store_observer.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-
-class Profile;
-
-namespace contacts {
-
-class Contact;
-typedef std::vector<const Contact*> ContactPointers;
-
-class ContactManagerObserver;
-class ContactStore;
-class ContactStoreFactory;
-
-// Class that exposes contacts to rest of the browser.
-class ContactManagerInterface {
- public:
- ContactManagerInterface() {}
- virtual ~ContactManagerInterface() {}
-
- // Returns a weak pointer tied to the lifetime of this object.
- virtual base::WeakPtr<ContactManagerInterface> GetWeakPtr() = 0;
-
- // Adds or removes an observer for changes to |profile|'s contacts.
- virtual void AddObserver(ContactManagerObserver* observer,
- Profile* profile) = 0;
- virtual void RemoveObserver(ContactManagerObserver* observer,
- Profile* profile) = 0;
-
- // Returns pointers to all currently-loaded contacts for |profile|. The
- // returned Contact objects may not persist indefinitely; the caller must not
- // refer to them again after unblocking the UI thread.
- virtual scoped_ptr<ContactPointers> GetAllContacts(Profile* profile) = 0;
-
- // Returns the contact identified by |contact_id|.
- // NULL is returned if the contact doesn't exist.
- virtual const Contact* GetContactById(Profile* profile,
- const std::string& contact_id) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ContactManagerInterface);
-};
-
-// Real, singleton implementation of ContactManagerInterface.
-class ContactManager : public ContactManagerInterface,
- public ContactStoreObserver,
- public content::NotificationObserver {
- public:
- static ContactManager* GetInstance();
-
- ContactManager();
- virtual ~ContactManager();
-
- // Swaps in a new factory to use for creating ContactStores.
- // Must be called before any stores have been created.
- void SetContactStoreForTesting(scoped_ptr<ContactStoreFactory> factory);
-
- void Init();
-
- // ContactManagerInterface overrides:
- virtual base::WeakPtr<ContactManagerInterface> GetWeakPtr() OVERRIDE;
- virtual void AddObserver(ContactManagerObserver* observer,
- Profile* profile) OVERRIDE;
- virtual void RemoveObserver(ContactManagerObserver* observer,
- Profile* profile) OVERRIDE;
- virtual scoped_ptr<ContactPointers> GetAllContacts(Profile* profile) OVERRIDE;
- virtual const Contact* GetContactById(Profile* profile,
- const std::string& contact_id) OVERRIDE;
-
- // ContactStoreObserver overrides:
- virtual void OnContactsUpdated(ContactStore* store) OVERRIDE;
-
- // content::NotificationObserver overrides:
- virtual void Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) OVERRIDE;
-
- private:
- typedef ObserverList<ContactManagerObserver> Observers;
- typedef std::map<Profile*, ContactStore*> ContactStoreMap;
- typedef std::map<Profile*, Observers*> ProfileObserversMap;
-
- // Returns the list of observers interested in |profile|. If not present,
- // creates a new list if |create| is true and returns NULL otherwise.
- Observers* GetObserversForProfile(Profile* profile, bool create);
-
- // Handles profile creation and destruction.
- void HandleProfileCreated(Profile* profile);
- void HandleProfileDestroyed(Profile* profile);
-
- content::NotificationRegistrar registrar_;
-
- // Maps from a profile to observers that are interested in changes to that
- // profile's contacts.
- ProfileObserversMap profile_observers_;
-
- // Deletes values in |profile_observers_|.
- STLValueDeleter<ProfileObserversMap> profile_observers_deleter_;
-
- // Creates objects for |contact_stores_|.
- scoped_ptr<ContactStoreFactory> contact_store_factory_;
-
- // Maps from a profile to a store for getting the profile's contacts.
- ContactStoreMap contact_stores_;
-
- // Deletes values in |contact_stores_|.
- STLValueDeleter<ContactStoreMap> contact_stores_deleter_;
-
- // Note: This should remain the last member so it'll be destroyed and
- // invalidate its weak pointers before any other members are destroyed.
- base::WeakPtrFactory<ContactManagerInterface> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ContactManager);
-};
-
-} // namespace contacts
-
-#endif // CHROME_BROWSER_CHROMEOS_CONTACTS_CONTACT_MANAGER_H_
diff --git a/chrome/browser/chromeos/contacts/contact_manager_observer.h b/chrome/browser/chromeos/contacts/contact_manager_observer.h
deleted file mode 100644
index 1913f38..0000000
--- a/chrome/browser/chromeos/contacts/contact_manager_observer.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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_CONTACTS_CONTACT_MANAGER_OBSERVER_H_
-#define CHROME_BROWSER_CHROMEOS_CONTACTS_CONTACT_MANAGER_OBSERVER_H_
-
-class Profile;
-
-namespace contacts {
-
-class ContactManager;
-
-// Interface for classes that need to observe changes to ContactManager.
-class ContactManagerObserver {
- public:
- ContactManagerObserver() {}
- virtual ~ContactManagerObserver() {}
-
- // Called when |profile|'s contacts have been updated.
- virtual void OnContactsUpdated(Profile* profile) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ContactManagerObserver);
-};
-
-} // namespace contacts
-
-#endif // CHROME_BROWSER_CHROMEOS_CONTACTS_CONTACT_MANAGER_OBSERVER_H_
diff --git a/chrome/browser/chromeos/contacts/contact_manager_stub.cc b/chrome/browser/chromeos/contacts/contact_manager_stub.cc
deleted file mode 100644
index 0ce8248..0000000
--- a/chrome/browser/chromeos/contacts/contact_manager_stub.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// 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.
-
-#include "chrome/browser/chromeos/contacts/contact_manager_stub.h"
-
-#include "base/logging.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/contacts/contact.pb.h"
-#include "chrome/browser/chromeos/contacts/contact_manager_observer.h"
-#include "chrome/browser/chromeos/contacts/contact_test_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
-
-namespace contacts {
-
-ContactManagerStub::ContactManagerStub(Profile* profile)
- : profile_(profile),
- weak_ptr_factory_(this) {
-}
-
-ContactManagerStub::~ContactManagerStub() {}
-
-void ContactManagerStub::NotifyObserversAboutUpdatedContacts() {
- FOR_EACH_OBSERVER(ContactManagerObserver,
- observers_,
- OnContactsUpdated(profile_));
-}
-
-void ContactManagerStub::SetContacts(const ContactPointers& contacts) {
- test::CopyContacts(contacts, &contacts_);
-}
-
-base::WeakPtr<ContactManagerInterface> ContactManagerStub::GetWeakPtr() {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- return weak_ptr_factory_.GetWeakPtr();
-}
-
-void ContactManagerStub::AddObserver(ContactManagerObserver* observer,
- Profile* profile) {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- CHECK(observer);
- CHECK_EQ(profile, profile_);
- CHECK(!observers_.HasObserver(observer));
- observers_.AddObserver(observer);
-}
-
-void ContactManagerStub::RemoveObserver(ContactManagerObserver* observer,
- Profile* profile) {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- CHECK(observer);
- CHECK_EQ(profile, profile_);
- CHECK(observers_.HasObserver(observer));
- observers_.RemoveObserver(observer);
-}
-
-scoped_ptr<ContactPointers> ContactManagerStub::GetAllContacts(
- Profile* profile) {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- CHECK_EQ(profile, profile_);
- scoped_ptr<ContactPointers> contacts(new ContactPointers);
- for (size_t i = 0; i < contacts_.size(); ++i)
- contacts->push_back(contacts_[i]);
- return contacts.Pass();
-}
-
-const Contact* ContactManagerStub::GetContactById(
- Profile* profile,
- const std::string& contact_id) {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- CHECK_EQ(profile, profile_);
- for (size_t i = 0; i < contacts_.size(); ++i) {
- if (contacts_[i]->contact_id() == contact_id)
- return contacts_[i];
- }
- return NULL;
-}
-
-} // namespace contacts
diff --git a/chrome/browser/chromeos/contacts/contact_manager_stub.h b/chrome/browser/chromeos/contacts/contact_manager_stub.h
deleted file mode 100644
index 3403740..0000000
--- a/chrome/browser/chromeos/contacts/contact_manager_stub.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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_CONTACTS_CONTACT_MANAGER_STUB_H_
-#define CHROME_BROWSER_CHROMEOS_CONTACTS_CONTACT_MANAGER_STUB_H_
-
-#include "chrome/browser/chromeos/contacts/contact_manager.h"
-
-#include "base/memory/scoped_vector.h"
-
-namespace contacts {
-
-// ContactManagerInterface implementation that returns a fixed set of contacts.
-// Used for testing.
-class ContactManagerStub : public ContactManagerInterface {
- public:
- explicit ContactManagerStub(Profile* profile);
- virtual ~ContactManagerStub();
-
- // Updates |contacts_|.
- void SetContacts(const ContactPointers& contacts);
-
- // Invokes OnContactsUpdated() on |observers_|.
- void NotifyObserversAboutUpdatedContacts();
-
- // ContactManagerInterface overrides:
- virtual base::WeakPtr<ContactManagerInterface> GetWeakPtr() OVERRIDE;
- virtual void AddObserver(ContactManagerObserver* observer, Profile* profile)
- OVERRIDE;
- virtual void RemoveObserver(ContactManagerObserver* observer,
- Profile* profile) OVERRIDE;
- virtual scoped_ptr<ContactPointers> GetAllContacts(Profile* profile) OVERRIDE;
- virtual const Contact* GetContactById(Profile* profile,
- const std::string& contact_id) OVERRIDE;
-
- private:
- // Profile expected to be passed to ContactManagerInterface methods.
- // Passing any other profile will result in a crash.
- Profile* profile_; // not owned
-
- // Observers registered for |profile_|.
- ObserverList<ContactManagerObserver> observers_;
-
- // Contacts that will be returned by GetAllContacts() and GetContactById().
- ScopedVector<Contact> contacts_;
-
- // Note: This should remain the last member so it'll be destroyed and
- // invalidate its weak pointers before any other members are destroyed.
- base::WeakPtrFactory<ContactManagerInterface> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ContactManagerStub);
-};
-
-} // namespace contacts
-
-#endif // CHROME_BROWSER_CHROMEOS_CONTACTS_CONTACT_MANAGER_STUB_H_
diff --git a/chrome/browser/chromeos/contacts/contact_manager_unittest.cc b/chrome/browser/chromeos/contacts/contact_manager_unittest.cc
deleted file mode 100644
index 211d3c2..0000000
--- a/chrome/browser/chromeos/contacts/contact_manager_unittest.cc
+++ /dev/null
@@ -1,171 +0,0 @@
-// 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.
-
-#include "chrome/browser/chromeos/contacts/contact_manager.h"
-
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/contacts/contact.pb.h"
-#include "chrome/browser/chromeos/contacts/contact_manager_observer.h"
-#include "chrome/browser/chromeos/contacts/contact_test_util.h"
-#include "chrome/browser/chromeos/contacts/fake_contact_store.h"
-#include "chrome/test/base/testing_browser_process.h"
-#include "chrome/test/base/testing_profile.h"
-#include "chrome/test/base/testing_profile_manager.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/test/test_browser_thread.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using content::BrowserThread;
-
-namespace contacts {
-namespace test {
-
-// ContactManagerObserver implementation that registers itself with a
-// ContactManager and counts the number of times that it's been told that
-// contacts have been updated.
-class TestContactManagerObserver : public ContactManagerObserver {
- public:
- TestContactManagerObserver(ContactManager* contact_manager,
- Profile* profile)
- : contact_manager_(contact_manager),
- profile_(profile),
- num_updates_(0) {
- contact_manager_->AddObserver(this, profile_);
- }
- virtual ~TestContactManagerObserver() {
- contact_manager_->RemoveObserver(this, profile_);
- }
-
- int num_updates() const { return num_updates_; }
- void reset_stats() { num_updates_ = 0; }
-
- // ContactManagerObserver overrides:
- virtual void OnContactsUpdated(Profile* profile) OVERRIDE {
- CHECK(profile == profile_);
- num_updates_++;
- }
-
- private:
- ContactManager* contact_manager_; // not owned
- Profile* profile_; // not owned
-
- // Number of times that OnContactsUpdated() has been called.
- int num_updates_;
-
- DISALLOW_COPY_AND_ASSIGN(TestContactManagerObserver);
-};
-
-class ContactManagerTest : public testing::Test {
- public:
- ContactManagerTest() : ui_thread_(BrowserThread::UI, &message_loop_) {}
- virtual ~ContactManagerTest() {}
-
- protected:
- // testing::Test implementation.
- virtual void SetUp() OVERRIDE {
- profile_manager_.reset(
- new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
- ASSERT_TRUE(profile_manager_->SetUp());
-
- contact_manager_.reset(new ContactManager);
- store_factory_ = new FakeContactStoreFactory;
- contact_manager_->SetContactStoreForTesting(
- scoped_ptr<ContactStoreFactory>(store_factory_).Pass());
- contact_manager_->Init();
- }
-
- base::MessageLoopForUI message_loop_;
- content::TestBrowserThread ui_thread_;
-
- scoped_ptr<TestingProfileManager> profile_manager_;
- scoped_ptr<ContactManager> contact_manager_;
- FakeContactStoreFactory* store_factory_; // not owned
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ContactManagerTest);
-};
-
-TEST_F(ContactManagerTest, NotifyOnUpdate) {
- const std::string kProfileName = "test_profile";
- TestingProfile* profile =
- profile_manager_->CreateTestingProfile(kProfileName);
- TestContactManagerObserver observer(contact_manager_.get(), profile);
- EXPECT_EQ(0, observer.num_updates());
-
- // ContactManager should notify its observers when it receives notification
- // that a ContactStore has been updated.
- FakeContactStore* store = store_factory_->GetContactStoreForProfile(profile);
- ASSERT_TRUE(store);
- store->NotifyObserversAboutContactsUpdate();
- EXPECT_EQ(1, observer.num_updates());
-
- store->NotifyObserversAboutContactsUpdate();
- EXPECT_EQ(2, observer.num_updates());
-
- profile_manager_->DeleteTestingProfile(kProfileName);
- EXPECT_EQ(2, observer.num_updates());
-}
-
-TEST_F(ContactManagerTest, GetContacts) {
- // Create two contacts and tell the store to return them.
- const std::string kContactId1 = "1";
- scoped_ptr<Contact> contact1(new Contact);
- InitContact(kContactId1, "1", false, contact1.get());
-
- const std::string kContactId2 = "2";
- scoped_ptr<Contact> contact2(new Contact);
- InitContact(kContactId2, "2", false, contact2.get());
-
- const std::string kProfileName = "test_profile";
- TestingProfile* profile =
- profile_manager_->CreateTestingProfile(kProfileName);
- FakeContactStore* store = store_factory_->GetContactStoreForProfile(profile);
- ASSERT_TRUE(store);
-
- ContactPointers store_contacts;
- store_contacts.push_back(contact1.get());
- store_contacts.push_back(contact2.get());
- store->SetContacts(store_contacts);
- store->NotifyObserversAboutContactsUpdate();
-
- // Check that GetAllContacts() returns both contacts.
- scoped_ptr<ContactPointers> loaded_contacts =
- contact_manager_->GetAllContacts(profile);
- EXPECT_EQ(ContactsToString(store_contacts),
- ContactsToString(*loaded_contacts));
-
- // Check that we can get individual contacts using GetContactById().
- const Contact* loaded_contact = contact_manager_->GetContactById(profile,
- kContactId1);
- ASSERT_TRUE(loaded_contact);
- EXPECT_EQ(ContactToString(*contact1), ContactToString(*loaded_contact));
-
- loaded_contact = contact_manager_->GetContactById(profile, kContactId2);
- ASSERT_TRUE(loaded_contact);
- EXPECT_EQ(ContactToString(*contact2), ContactToString(*loaded_contact));
-
- // We should get NULL if we pass a nonexistent contact ID.
- EXPECT_FALSE(contact_manager_->GetContactById(profile, "foo"));
-
- profile_manager_->DeleteTestingProfile(kProfileName);
-}
-
-TEST_F(ContactManagerTest, ProfileUnsupportedByContactStore) {
- // ContactManager shouldn't try to create a ContactStore for an unsuppported
- // Profile.
- store_factory_->set_permit_store_creation(false);
- const std::string kProfileName = "test_profile";
- TestingProfile* profile =
- profile_manager_->CreateTestingProfile(kProfileName);
- EXPECT_FALSE(store_factory_->GetContactStoreForProfile(profile));
- profile_manager_->DeleteTestingProfile(kProfileName);
-}
-
-} // namespace test
-} // namespace contacts
diff --git a/chrome/browser/chromeos/contacts/contact_map.cc b/chrome/browser/chromeos/contacts/contact_map.cc
deleted file mode 100644
index f02aef4..0000000
--- a/chrome/browser/chromeos/contacts/contact_map.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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.
-
-#include "chrome/browser/chromeos/contacts/contact_map.h"
-
-#include "chrome/browser/chromeos/contacts/contact.pb.h"
-
-namespace contacts {
-
-ContactMap::ContactMap() : contacts_deleter_(&contacts_) {}
-
-ContactMap::~ContactMap() {}
-
-const Contact* ContactMap::Find(const std::string& contact_id) const {
- Map::const_iterator it = contacts_.find(contact_id);
- return (it != contacts_.end()) ? it->second : NULL;
-}
-
-void ContactMap::Erase(const std::string& contact_id) {
- Map::iterator it = contacts_.find(contact_id);
- if (it == contacts_.end())
- return;
-
- delete it->second;
- contacts_.erase(it);
-}
-
-void ContactMap::Clear() {
- STLDeleteValues(&contacts_);
-}
-
-void ContactMap::Merge(scoped_ptr<ScopedVector<Contact> > updated_contacts,
- DeletedContactPolicy policy) {
- for (ScopedVector<Contact>::iterator it = updated_contacts->begin();
- it != updated_contacts->end(); ++it) {
- Contact* contact = *it;
- Map::iterator map_it = contacts_.find(contact->contact_id());
-
- if (contact->deleted() && policy == DROP_DELETED_CONTACTS) {
- // Also delete the previous version of the contact, if any.
- if (map_it != contacts_.end()) {
- delete map_it->second;
- contacts_.erase(map_it);
- }
- delete contact;
- } else {
- if (map_it != contacts_.end()) {
- delete map_it->second;
- map_it->second = contact;
- } else {
- contacts_[contact->contact_id()] = contact;
- }
- }
- }
-
- // Make sure that the Contact objects that we just saved to the map won't be
- // destroyed when |updated_contacts| is destroyed.
- updated_contacts->weak_clear();
-}
-
-} // namespace contacts
diff --git a/chrome/browser/chromeos/contacts/contact_map.h b/chrome/browser/chromeos/contacts/contact_map.h
deleted file mode 100644
index 66a8444..0000000
--- a/chrome/browser/chromeos/contacts/contact_map.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// 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_CONTACTS_CONTACT_MAP_H_
-#define CHROME_BROWSER_CHROMEOS_CONTACTS_CONTACT_MAP_H_
-
-#include <map>
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "base/stl_util.h"
-#include "base/time/time.h"
-
-namespace contacts {
-
-class Contact;
-
-// Stores Contact objects indexed by their IDs.
-class ContactMap {
- public:
- typedef std::map<std::string, Contact*> Map;
- typedef Map::const_iterator const_iterator;
-
- // What should Merge() do when passed a deleted contact?
- enum DeletedContactPolicy {
- // The deleted contact will be inserted into the map.
- KEEP_DELETED_CONTACTS,
-
- // The deleted contact will not be deleted from the map, and if there is a
- // previous version of the now-deleted contact already in the map, it will
- // also be removed.
- DROP_DELETED_CONTACTS,
- };
-
- ContactMap();
- ~ContactMap();
-
- bool empty() const { return contacts_.empty(); }
- size_t size() const { return contacts_.size(); }
- const_iterator begin() const { return contacts_.begin(); }
- const_iterator end() const { return contacts_.end(); }
-
- // Returns the contact with ID |contact_id|. NULL is returned if the contact
- // isn't present.
- const Contact* Find(const std::string& contact_id) const;
-
- // Deletes the contact with ID |contact_id|.
- void Erase(const std::string& contact_id);
-
- // Deletes all contacts.
- void Clear();
-
- // Merges |updated_contacts| into |contacts_|.
- void Merge(scoped_ptr<ScopedVector<Contact> > updated_contacts,
- DeletedContactPolicy policy);
-
- private:
- Map contacts_;
-
- // Deletes values in |contacts_|.
- STLValueDeleter<Map> contacts_deleter_;
-
- DISALLOW_COPY_AND_ASSIGN(ContactMap);
-};
-
-} // namespace contacts
-
-#endif // CHROME_BROWSER_CHROMEOS_CONTACTS_CONTACT_MAP_H_
diff --git a/chrome/browser/chromeos/contacts/contact_map_unittest.cc b/chrome/browser/chromeos/contacts/contact_map_unittest.cc
deleted file mode 100644
index ebd46e1..0000000
--- a/chrome/browser/chromeos/contacts/contact_map_unittest.cc
+++ /dev/null
@@ -1,105 +0,0 @@
-// 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.
-
-#include "chrome/browser/chromeos/contacts/contact_map.h"
-
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "base/time/time.h"
-#include "chrome/browser/chromeos/contacts/contact.pb.h"
-#include "chrome/browser/chromeos/contacts/contact_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace contacts {
-namespace test {
-
-TEST(ContactMapTest, Merge) {
- ContactMap map;
- EXPECT_TRUE(map.empty());
- EXPECT_EQ(0U, map.size());
-
- // Create a contact.
- const std::string kContactId1 = "contact_id_1";
- scoped_ptr<Contact> contact1(new Contact);
- InitContact(kContactId1, "1", false, contact1.get());
-
- // Merge it into the map and check that it's stored.
- scoped_ptr<ScopedVector<Contact> > contacts_to_merge(
- new ScopedVector<Contact>);
- contacts_to_merge->push_back(new Contact(*contact1));
- map.Merge(contacts_to_merge.Pass(), ContactMap::KEEP_DELETED_CONTACTS);
- EXPECT_FALSE(map.empty());
- EXPECT_EQ(1U, map.size());
- ASSERT_TRUE(map.Find(kContactId1));
- EXPECT_EQ(ContactMapToString(map), VarContactsToString(1, contact1.get()));
-
- // Create a second, deleted contact.
- const std::string kContactId2 = "contact_id_2";
- scoped_ptr<Contact> contact2(new Contact);
- InitContact(kContactId2, "2", true, contact2.get());
-
- // Merge it into the map. Since we request keeping deleted contacts, the
- // contact should be saved.
- contacts_to_merge.reset(new ScopedVector<Contact>);
- contacts_to_merge->push_back(new Contact(*contact2));
- map.Merge(contacts_to_merge.Pass(), ContactMap::KEEP_DELETED_CONTACTS);
- EXPECT_EQ(2U, map.size());
- ASSERT_TRUE(map.Find(kContactId2));
- EXPECT_EQ(ContactMapToString(map),
- VarContactsToString(2, contact1.get(), contact2.get()));
-
- // Update the first contact's update time and merge it into the map.
- contact1->set_update_time(contact1->update_time() + 20);
- contacts_to_merge.reset(new ScopedVector<Contact>);
- contacts_to_merge->push_back(new Contact(*contact1));
- map.Merge(contacts_to_merge.Pass(), ContactMap::KEEP_DELETED_CONTACTS);
- EXPECT_EQ(ContactMapToString(map),
- VarContactsToString(2, contact1.get(), contact2.get()));
-
- // Create another deleted contact.
- const std::string kContactId3 = "contact_id_3";
- scoped_ptr<Contact> contact3(new Contact);
- InitContact(kContactId3, "3", true, contact3.get());
-
- // Merge it into the map with DROP_DELETED_CONTACTS. The contact shouldn't be
- // saved.
- contacts_to_merge.reset(new ScopedVector<Contact>);
- contacts_to_merge->push_back(new Contact(*contact3));
- map.Merge(contacts_to_merge.Pass(), ContactMap::DROP_DELETED_CONTACTS);
- EXPECT_EQ(ContactMapToString(map),
- VarContactsToString(2, contact1.get(), contact2.get()));
-
- // Mark the first contact as being deleted and merge it with
- // DROP_DELETED_CONTACTS. The previous version of the contact should also be
- // removed.
- contact1->set_deleted(true);
- contacts_to_merge.reset(new ScopedVector<Contact>);
- contacts_to_merge->push_back(new Contact(*contact1));
- map.Merge(contacts_to_merge.Pass(), ContactMap::DROP_DELETED_CONTACTS);
- EXPECT_EQ(ContactMapToString(map), VarContactsToString(1, contact2.get()));
-
- map.Clear();
- EXPECT_TRUE(map.empty());
- EXPECT_EQ(0U, map.size());
-}
-
-TEST(ContactMapTest, Erase) {
- ContactMap map;
- const std::string kContactId = "contact_id";
- scoped_ptr<Contact> contact(new Contact);
- InitContact(kContactId, "1", false, contact.get());
-
- scoped_ptr<ScopedVector<Contact> > contacts_to_merge(
- new ScopedVector<Contact>);
- contacts_to_merge->push_back(new Contact(*contact));
- map.Merge(contacts_to_merge.Pass(), ContactMap::KEEP_DELETED_CONTACTS);
- EXPECT_TRUE(map.Find(kContactId));
-
- map.Erase(kContactId);
- EXPECT_FALSE(map.Find(kContactId));
- EXPECT_TRUE(map.empty());
-}
-
-} // namespace test
-} // namespace contacts
diff --git a/chrome/browser/chromeos/contacts/contact_store.h b/chrome/browser/chromeos/contacts/contact_store.h
deleted file mode 100644
index d9de027..0000000
--- a/chrome/browser/chromeos/contacts/contact_store.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// 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_CONTACTS_CONTACT_STORE_H_
-#define CHROME_BROWSER_CHROMEOS_CONTACTS_CONTACT_STORE_H_
-
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-
-class Profile;
-
-namespace contacts {
-
-class Contact;
-typedef std::vector<const Contact*> ContactPointers;
-class ContactStoreObserver;
-
-// Interface for classes that store contacts from a particular source.
-class ContactStore {
- public:
- ContactStore() {}
- virtual ~ContactStore() {}
-
- // Initializes the object.
- virtual void Init() = 0;
-
- // Appends all (non-deleted) contacts to |contacts_out|.
- virtual void AppendContacts(ContactPointers* contacts_out) = 0;
-
- // Returns the contact identified by |contact_id|.
- // NULL is returned if the contact doesn't exist.
- virtual const Contact* GetContactById(const std::string& contact_id) = 0;
-
- // Adds or removes an observer.
- virtual void AddObserver(ContactStoreObserver* observer) = 0;
- virtual void RemoveObserver(ContactStoreObserver* observer) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ContactStore);
-};
-
-// Interface for factories that return ContactStore objects of a given type.
-class ContactStoreFactory {
- public:
- ContactStoreFactory() {}
- virtual ~ContactStoreFactory() {}
-
- // Does |profile| support this type of ContactStore?
- virtual bool CanCreateContactStoreForProfile(Profile* profile) = 0;
-
- // Creates and returns a new, uninitialized ContactStore for |profile|.
- // CanCreateContactStoreForProfile() should be called first.
- // TODO(derat): Figure out how this should work if/when there are other
- // ContactStore implementations that need additional information beyond the
- // stuff contained in a Profile.
- virtual ContactStore* CreateContactStore(Profile* profile) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ContactStoreFactory);
-};
-
-} // namespace contacts
-
-#endif // CHROME_BROWSER_CHROMEOS_CONTACTS_CONTACT_STORE_H_
diff --git a/chrome/browser/chromeos/contacts/contact_store_observer.h b/chrome/browser/chromeos/contacts/contact_store_observer.h
deleted file mode 100644
index dc387ed..0000000
--- a/chrome/browser/chromeos/contacts/contact_store_observer.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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_CONTACTS_CONTACT_STORE_OBSERVER_H_
-#define CHROME_BROWSER_CHROMEOS_CONTACTS_CONTACT_STORE_OBSERVER_H_
-
-#include "base/basictypes.h"
-
-namespace contacts {
-
-class ContactStore;
-
-// Interface for observing changes to a ContactStore.
-class ContactStoreObserver {
- public:
- ContactStoreObserver() {}
- virtual ~ContactStoreObserver() {}
-
- // Called when the contacts stored within a ContactStore are updated.
- virtual void OnContactsUpdated(ContactStore* store) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ContactStoreObserver);
-};
-
-} // namespace contacts
-
-#endif // CHROME_BROWSER_CHROMEOS_CONTACTS_CONTACT_STORE_OBSERVER_H_
diff --git a/chrome/browser/chromeos/contacts/contact_test_util.cc b/chrome/browser/chromeos/contacts/contact_test_util.cc
deleted file mode 100644
index 071083a..0000000
--- a/chrome/browser/chromeos/contacts/contact_test_util.cc
+++ /dev/null
@@ -1,255 +0,0 @@
-// 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.
-
-#include "chrome/browser/chromeos/contacts/contact_test_util.h"
-
-#include <algorithm>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/time/time.h"
-#include "chrome/browser/chromeos/contacts/contact_map.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "ui/gfx/codec/png_codec.h"
-#include "ui/gfx/size.h"
-
-namespace contacts {
-namespace test {
-
-namespace {
-
-// Invokes |stringify_callback| on each item in |items| and prepends |prefix|,
-// and then sorts the resulting strings and joins them using |join_char|.
-template<class T>
-std::string StringifyField(
- const ::google::protobuf::RepeatedPtrField<T>& items,
- base::Callback<std::string(const T&)> stringify_callback,
- const std::string& prefix,
- char join_char) {
- std::vector<std::string> strings;
- for (int i = 0; i < items.size(); ++i)
- strings.push_back(prefix + stringify_callback.Run(items.Get(i)));
- std::sort(strings.begin(), strings.end());
- return JoinString(strings, join_char);
-}
-
-std::string EmailAddressToString(const Contact_EmailAddress& email) {
- return email.address() + "," +
- base::IntToString(email.type().relation()) + "," +
- email.type().label() + "," +
- base::IntToString(email.primary());
-}
-
-std::string PhoneNumberToString(const Contact_PhoneNumber& phone) {
- return phone.number() + "," +
- base::IntToString(phone.type().relation()) + "," +
- phone.type().label() + "," +
- base::IntToString(phone.primary());
-}
-
-std::string PostalAddressToString(const Contact_PostalAddress& postal) {
- return postal.address() + "," +
- base::IntToString(postal.type().relation()) + "," +
- postal.type().label() + "," +
- base::IntToString(postal.primary());
-}
-
-std::string InstantMessagingAddressToString(
- const Contact_InstantMessagingAddress& im) {
- return im.address() + "," +
- base::IntToString(im.protocol()) + "," +
- base::IntToString(im.type().relation()) + "," +
- im.type().label() + "," +
- base::IntToString(im.primary());
-}
-
-} // namespace
-
-std::string ContactToString(const Contact& contact) {
- std::string result =
- contact.contact_id() + "," +
- base::Int64ToString(contact.update_time()) + "," +
- base::IntToString(contact.deleted()) + "," +
- contact.full_name() + "," +
- contact.given_name() + "," +
- contact.additional_name() + "," +
- contact.family_name() + "," +
- contact.name_prefix() + "," +
- contact.name_suffix();
-
- SkBitmap bitmap;
- if (contact.has_raw_untrusted_photo()) {
- // Testing code just uses PNG for now. If that changes, use ImageDecoder
- // here instead.
- CHECK(gfx::PNGCodec::Decode(reinterpret_cast<const unsigned char*>(
- contact.raw_untrusted_photo().data()),
- contact.raw_untrusted_photo().size(),
- &bitmap));
- }
- result += "," + base::IntToString(bitmap.width()) + "x" +
- base::IntToString(bitmap.height());
-
- result += " " + StringifyField(contact.email_addresses(),
- base::Bind(EmailAddressToString),
- "email=", ' ');
- result += " " + StringifyField(contact.phone_numbers(),
- base::Bind(PhoneNumberToString),
- "phone=", ' ');
- result += " " + StringifyField(contact.postal_addresses(),
- base::Bind(PostalAddressToString),
- "postal=", ' ');
- result += " " + StringifyField(contact.instant_messaging_addresses(),
- base::Bind(InstantMessagingAddressToString),
- "im=", ' ');
-
- return result;
-}
-
-std::string ContactsToString(const ContactPointers& contacts) {
- std::vector<std::string> contact_strings;
- for (size_t i = 0; i < contacts.size(); ++i)
- contact_strings.push_back(ContactToString(*contacts[i]));
- std::sort(contact_strings.begin(), contact_strings.end());
- return JoinString(contact_strings, '\n');
-}
-
-std::string ContactsToString(const ScopedVector<Contact>& contacts) {
- ContactPointers pointers;
- for (size_t i = 0; i < contacts.size(); ++i)
- pointers.push_back(contacts[i]);
- return ContactsToString(pointers);
-}
-
-std::string VarContactsToString(int num_contacts, ...) {
- ContactPointers contacts;
- va_list list;
- va_start(list, num_contacts);
- for (int i = 0; i < num_contacts; ++i)
- contacts.push_back(va_arg(list, const Contact*));
- va_end(list);
- return ContactsToString(contacts);
-}
-
-std::string ContactMapToString(const ContactMap& contact_map) {
- ContactPointers contacts;
- for (ContactMap::const_iterator it = contact_map.begin();
- it != contact_map.end(); ++it) {
- contacts.push_back(it->second);
- }
- return ContactsToString(contacts);
-}
-
-void CopyContacts(const ContactPointers& source,
- ScopedVector<Contact>* dest) {
- DCHECK(dest);
- dest->clear();
- for (size_t i = 0; i < source.size(); ++i)
- dest->push_back(new Contact(*source[i]));
-}
-
-void CopyContacts(const ScopedVector<Contact>& source,
- ScopedVector<Contact>* dest) {
- ContactPointers pointers;
- for (size_t i = 0; i < source.size(); ++i)
- pointers.push_back(source[i]);
- CopyContacts(pointers, dest);
-}
-
-void InitContact(const std::string& contact_id,
- const std::string& name_suffix,
- bool deleted,
- Contact* contact) {
- DCHECK(contact);
- contact->Clear();
- contact->set_contact_id(contact_id);
- contact->set_update_time(base::Time::Now().ToInternalValue());
- contact->set_deleted(deleted);
- contact->set_full_name("full_name_" + name_suffix);
- contact->set_given_name("given_name_" + name_suffix);
- contact->set_additional_name("additional_name_" + name_suffix);
- contact->set_family_name("family_name_" + name_suffix);
- contact->set_name_prefix("name_prefix_" + name_suffix);
- contact->set_name_suffix("name_suffix_" + name_suffix);
-}
-
-void AddEmailAddress(const std::string& address,
- Contact_AddressType_Relation relation,
- const std::string& label,
- bool primary,
- Contact* contact) {
- DCHECK(contact);
- Contact::EmailAddress* email = contact->add_email_addresses();
- email->set_address(address);
- email->mutable_type()->set_relation(relation);
- email->mutable_type()->set_label(label);
- email->set_primary(primary);
-}
-
-void AddPhoneNumber(const std::string& number,
- Contact_AddressType_Relation relation,
- const std::string& label,
- bool primary,
- Contact* contact) {
- DCHECK(contact);
- Contact::PhoneNumber* phone = contact->add_phone_numbers();
- phone->set_number(number);
- phone->mutable_type()->set_relation(relation);
- phone->mutable_type()->set_label(label);
- phone->set_primary(primary);
-}
-
-void AddPostalAddress(const std::string& address,
- Contact_AddressType_Relation relation,
- const std::string& label,
- bool primary,
- Contact* contact) {
- DCHECK(contact);
- Contact::PostalAddress* postal = contact->add_postal_addresses();
- postal->set_address(address);
- postal->mutable_type()->set_relation(relation);
- postal->mutable_type()->set_label(label);
- postal->set_primary(primary);
-}
-
-void AddInstantMessagingAddress(
- const std::string& address,
- Contact_InstantMessagingAddress_Protocol protocol,
- Contact_AddressType_Relation relation,
- const std::string& label,
- bool primary,
- Contact* contact) {
- DCHECK(contact);
- Contact::InstantMessagingAddress* im =
- contact->add_instant_messaging_addresses();
- im->set_address(address);
- im->set_protocol(protocol);
- im->mutable_type()->set_relation(relation);
- im->mutable_type()->set_label(label);
- im->set_primary(primary);
-}
-
-void SetPhoto(const gfx::Size& size, Contact* contact) {
- DCHECK(contact);
- if (size.IsEmpty()) {
- contact->clear_raw_untrusted_photo();
- return;
- }
-
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
- bitmap.allocPixels();
- SkCanvas canvas(bitmap);
- canvas.clear(SK_ColorBLACK);
-
- std::vector<unsigned char> png_photo;
- CHECK(gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &png_photo));
- contact->set_raw_untrusted_photo(&png_photo[0], png_photo.size());
-}
-
-} // namespace test
-} // namespace contacts
diff --git a/chrome/browser/chromeos/contacts/contact_test_util.h b/chrome/browser/chromeos/contacts/contact_test_util.h
deleted file mode 100644
index a16d946..0000000
--- a/chrome/browser/chromeos/contacts/contact_test_util.h
+++ /dev/null
@@ -1,94 +0,0 @@
-// 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_CONTACTS_CONTACT_TEST_UTIL_H_
-#define CHROME_BROWSER_CHROMEOS_CONTACTS_CONTACT_TEST_UTIL_H_
-
-#include <string>
-
-#include "base/memory/scoped_vector.h"
-#include "chrome/browser/chromeos/contacts/contact.pb.h"
-#include "ui/gfx/size.h"
-
-namespace contacts {
-
-typedef std::vector<const Contact*> ContactPointers;
-class ContactMap;
-
-namespace test {
-
-// Returns a string containing the information stored in |contact|. The same
-// string will be returned for functionally-equivalent contacts (e.g. ones
-// containing the same email addresses but in a different order).
-std::string ContactToString(const Contact& contact);
-
-// Runs ContactToString() on each entry in |contacts| and returns the results
-// joined by newlines (in a consistent order).
-std::string ContactsToString(const ContactPointers& contacts);
-std::string ContactsToString(const ScopedVector<Contact>& contacts);
-
-// Convenience wrapper for ContactsToString(). Takes |num_contacts|
-// const Contact* arguments.
-std::string VarContactsToString(int num_contacts, ...);
-
-// Like ContactsToStrings(), but takes a ContactMap as input.
-std::string ContactMapToString(const ContactMap& contact_map);
-
-// Saves copies of all contacts in |source| to |dest|.
-void CopyContacts(const ContactPointers& source,
- ScopedVector<Contact>* dest);
-void CopyContacts(const ScopedVector<Contact>& source,
- ScopedVector<Contact>* dest);
-
-// Initializes |contact| with the passed-in data. The photo and all address
-// fields are cleared. |contact_id| corresponds to Contact::contact_id,
-// |deleted| to Contact::deleted, and a unique string should be passed to
-// |name_suffix| to make the name-related fields be distinct from those in other
-// contacts.
-void InitContact(const std::string& contact_id,
- const std::string& name_suffix,
- bool deleted,
- Contact* contact);
-
-// Adds an email address to |contact|.
-void AddEmailAddress(const std::string& address,
- Contact_AddressType_Relation relation,
- const std::string& label,
- bool primary,
- Contact* contact);
-
-// Adds a phone number to |contact|.
-void AddPhoneNumber(const std::string& number,
- Contact_AddressType_Relation relation,
- const std::string& label,
- bool primary,
- Contact* contact);
-
-// Adds a postal address to |contact|.
-void AddPostalAddress(const std::string& address,
- Contact_AddressType_Relation relation,
- const std::string& label,
- bool primary,
- Contact* contact);
-
-// Adds an IM address to |contact|.
-void AddInstantMessagingAddress(
- const std::string& address,
- Contact_InstantMessagingAddress_Protocol protocol,
- Contact_AddressType_Relation relation,
- const std::string& label,
- bool primary,
- Contact* contact);
-
-// Initializes |contact|'s photo to a bitmap of the given size.
-// ContactToString() includes the photo's dimensions in its output, so tests can
-// call this method to set the photo to a given size and then check that the
-// size matches later (e.g. after loading the contact from a server or from
-// disk) to confirm that the photo was loaded correctly.
-void SetPhoto(const gfx::Size& size, Contact* contact);
-
-} // namespace test
-} // namespace contacts
-
-#endif // CHROME_BROWSER_CHROMEOS_CONTACTS_CONTACT_TEST_UTIL_H_
diff --git a/chrome/browser/chromeos/contacts/fake_contact_database.cc b/chrome/browser/chromeos/contacts/fake_contact_database.cc
deleted file mode 100644
index 00b30b8..0000000
--- a/chrome/browser/chromeos/contacts/fake_contact_database.cc
+++ /dev/null
@@ -1,87 +0,0 @@
-// 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.
-
-#include "chrome/browser/chromeos/contacts/fake_contact_database.h"
-
-#include "chrome/browser/chromeos/contacts/contact.pb.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
-
-namespace contacts {
-
-FakeContactDatabase::FakeContactDatabase()
- : init_success_(true),
- save_success_(true),
- load_success_(true),
- num_saved_contacts_(0) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-}
-
-void FakeContactDatabase::Init(const base::FilePath& database_dir,
- InitCallback callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- callback.Run(init_success_);
-}
-
-void FakeContactDatabase::SetContacts(const ContactPointers& contacts,
- const UpdateMetadata& metadata) {
- contacts_.Clear();
- MergeContacts(contacts, ContactIds());
- metadata_ = metadata;
-}
-
-void FakeContactDatabase::DestroyOnUIThread() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- delete this;
-}
-
-void FakeContactDatabase::SaveContacts(
- scoped_ptr<ContactPointers> contacts_to_save,
- scoped_ptr<ContactIds> contact_ids_to_delete,
- scoped_ptr<UpdateMetadata> metadata,
- bool is_full_update,
- SaveCallback callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (save_success_) {
- num_saved_contacts_ += contacts_to_save->size();
- if (is_full_update)
- contacts_.Clear();
- MergeContacts(*contacts_to_save, *contact_ids_to_delete);
- metadata_ = *metadata;
- }
- callback.Run(save_success_);
-}
-
-void FakeContactDatabase::LoadContacts(LoadCallback callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- scoped_ptr<ScopedVector<Contact> > contacts(new ScopedVector<Contact>());
- scoped_ptr<UpdateMetadata> metadata(new UpdateMetadata);
- if (load_success_) {
- for (ContactMap::const_iterator it = contacts_.begin();
- it != contacts_.end(); ++it) {
- contacts->push_back(new Contact(*it->second));
- }
- *metadata = metadata_;
- }
- callback.Run(load_success_, contacts.Pass(), metadata.Pass());
-}
-
-FakeContactDatabase::~FakeContactDatabase() {
-}
-
-void FakeContactDatabase::MergeContacts(
- const ContactPointers& updated_contacts,
- const ContactIds& contact_ids_to_delete) {
- scoped_ptr<ScopedVector<Contact> > copied_contacts(new ScopedVector<Contact>);
- for (size_t i = 0; i < updated_contacts.size(); ++i)
- copied_contacts->push_back(new Contact(*updated_contacts[i]));
- contacts_.Merge(copied_contacts.Pass(), ContactMap::KEEP_DELETED_CONTACTS);
- for (ContactIds::const_iterator it = contact_ids_to_delete.begin();
- it != contact_ids_to_delete.end(); ++it) {
- contacts_.Erase(*it);
- }
-}
-
-} // namespace contacts
diff --git a/chrome/browser/chromeos/contacts/fake_contact_database.h b/chrome/browser/chromeos/contacts/fake_contact_database.h
deleted file mode 100644
index 9263ef6..0000000
--- a/chrome/browser/chromeos/contacts/fake_contact_database.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// 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_CONTACTS_FAKE_CONTACT_DATABASE_H_
-#define CHROME_BROWSER_CHROMEOS_CONTACTS_FAKE_CONTACT_DATABASE_H_
-
-#include "chrome/browser/chromeos/contacts/contact_database.h"
-
-#include "chrome/browser/chromeos/contacts/contact.pb.h"
-#include "chrome/browser/chromeos/contacts/contact_map.h"
-
-namespace contacts {
-
-// Fake implementation used for testing.
-class FakeContactDatabase : public ContactDatabaseInterface {
- public:
- FakeContactDatabase();
-
- const ContactMap& contacts() const { return contacts_; }
- const UpdateMetadata& metadata() const { return metadata_; }
-
- void set_init_success(bool success) { init_success_ = success; }
- void set_save_success(bool success) { save_success_ = success; }
- void set_load_success(bool success) { load_success_ = success; }
-
- int num_saved_contacts() const { return num_saved_contacts_; }
- void reset_stats() { num_saved_contacts_ = 0; }
-
- // Copies |contacts| into |contacts_| and |metadata| into |metadata_|. These
- // values will be returned by subsequent calls to LoadContacts().
- void SetContacts(const ContactPointers& contacts,
- const UpdateMetadata& metadata);
-
- // ContactDatabaseInterface implementation.
- virtual void DestroyOnUIThread() OVERRIDE;
- virtual void Init(const base::FilePath& database_dir,
- InitCallback callback) OVERRIDE;
- virtual void SaveContacts(scoped_ptr<ContactPointers> contacts_to_save,
- scoped_ptr<ContactIds> contact_ids_to_delete,
- scoped_ptr<UpdateMetadata> metadata,
- bool is_full_update,
- SaveCallback callback) OVERRIDE;
- virtual void LoadContacts(LoadCallback callback) OVERRIDE;
-
- protected:
- virtual ~FakeContactDatabase();
-
- private:
- // Merges |updated_contacts| into |contacts_| and deletes contacts with IDs in
- // |contact_ids_to_delete|.
- void MergeContacts(const ContactPointers& updated_contacts,
- const ContactIds& contact_ids_to_delete);
-
- // Should we report success in response to various requests?
- bool init_success_;
- bool save_success_;
- bool load_success_;
-
- // Total number of contacts that have been passed to SaveContacts() while
- // |save_success_| is true.
- int num_saved_contacts_;
-
- // Currently-stored contacts and metadata.
- ContactMap contacts_;
- UpdateMetadata metadata_;
-
- DISALLOW_COPY_AND_ASSIGN(FakeContactDatabase);
-};
-
-} // namespace contacts
-
-#endif // CHROME_BROWSER_CHROMEOS_CONTACTS_FAKE_CONTACT_DATABASE_H_
diff --git a/chrome/browser/chromeos/contacts/fake_contact_store.cc b/chrome/browser/chromeos/contacts/fake_contact_store.cc
deleted file mode 100644
index 4533917..0000000
--- a/chrome/browser/chromeos/contacts/fake_contact_store.cc
+++ /dev/null
@@ -1,112 +0,0 @@
-// 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.
-
-#include "chrome/browser/chromeos/contacts/fake_contact_store.h"
-
-#include <utility>
-
-#include "chrome/browser/chromeos/contacts/contact.pb.h"
-#include "chrome/browser/chromeos/contacts/contact_store_observer.h"
-#include "chrome/browser/profiles/profile.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
-
-namespace contacts {
-
-FakeContactStore::FakeContactStore(FakeContactStoreFactory* factory)
- : factory_(factory),
- contacts_deleter_(&contacts_) {
-}
-
-FakeContactStore::~FakeContactStore() {
- factory_->RemoveStore(this);
-}
-
-void FakeContactStore::SetContacts(const ContactPointers& contacts) {
- STLDeleteValues(&contacts_);
- contacts_.clear();
- for (ContactPointers::const_iterator it = contacts.begin();
- it != contacts.end(); ++it) {
- contacts_[(*it)->contact_id()] = new Contact(**it);
- }
-}
-
-void FakeContactStore::NotifyObserversAboutContactsUpdate() {
- FOR_EACH_OBSERVER(ContactStoreObserver,
- observers_,
- OnContactsUpdated(this));
-}
-
-void FakeContactStore::Init() {
-}
-
-void FakeContactStore::AppendContacts(ContactPointers* contacts_out) {
- CHECK(contacts_out);
- for (ContactMap::const_iterator it = contacts_.begin();
- it != contacts_.end(); ++it) {
- if (!it->second->deleted())
- contacts_out->push_back(it->second);
- }
-}
-
-const Contact* FakeContactStore::GetContactById(const std::string& contact_id) {
- ContactMap::const_iterator it = contacts_.find(contact_id);
- return (it != contacts_.end() && !it->second->deleted()) ? it->second : NULL;
-}
-
-void FakeContactStore::AddObserver(ContactStoreObserver* observer) {
- CHECK(observer);
- observers_.AddObserver(observer);
-}
-
-void FakeContactStore::RemoveObserver(ContactStoreObserver* observer) {
- CHECK(observer);
- observers_.RemoveObserver(observer);
-}
-
-FakeContactStoreFactory::FakeContactStoreFactory()
- : permit_store_creation_(true) {
-}
-
-FakeContactStoreFactory::~FakeContactStoreFactory() {
- CHECK(stores_.empty());
-}
-
-FakeContactStore* FakeContactStoreFactory::GetContactStoreForProfile(
- Profile* profile) {
- CHECK(profile);
- ProfileStoreMap::const_iterator it = stores_.find(profile);
- return it != stores_.end() ? it->second : NULL;
-}
-
-void FakeContactStoreFactory::RemoveStore(FakeContactStore* store) {
- CHECK(store);
- for (ProfileStoreMap::iterator it = stores_.begin();
- it != stores_.end(); ++it) {
- if (it->second == store) {
- stores_.erase(it);
- return;
- }
- }
- NOTREACHED() << "No record of destroyed FakeContactStore " << store;
-}
-
-bool FakeContactStoreFactory::CanCreateContactStoreForProfile(
- Profile* profile) {
- CHECK(profile);
- return permit_store_creation_;
-}
-
-ContactStore* FakeContactStoreFactory::CreateContactStore(Profile* profile) {
- CHECK(profile);
- CHECK(CanCreateContactStoreForProfile(profile));
- FakeContactStore* store = new FakeContactStore(this);
- CHECK(stores_.insert(std::make_pair(profile, store)).second)
- << "Got request to create second FakeContactStore for profile "
- << profile << " (" << profile->GetProfileName() << ")";
- return store;
-}
-
-} // namespace contacts
diff --git a/chrome/browser/chromeos/contacts/fake_contact_store.h b/chrome/browser/chromeos/contacts/fake_contact_store.h
deleted file mode 100644
index 4300468..0000000
--- a/chrome/browser/chromeos/contacts/fake_contact_store.h
+++ /dev/null
@@ -1,103 +0,0 @@
-// 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_CONTACTS_FAKE_CONTACT_STORE_H_
-#define CHROME_BROWSER_CHROMEOS_CONTACTS_FAKE_CONTACT_STORE_H_
-
-#include "chrome/browser/chromeos/contacts/contact_store.h"
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/observer_list.h"
-#include "base/stl_util.h"
-
-class Profile;
-
-namespace contacts {
-
-class Contact;
-class FakeContactStoreFactory;
-typedef std::vector<const Contact*> ContactPointers;
-
-// A "fake" in-memory implementation of ContactStore used for testing.
-class FakeContactStore : public ContactStore {
- public:
- explicit FakeContactStore(FakeContactStoreFactory* factory);
- virtual ~FakeContactStore();
-
- // Makes an internal copy of |contacts| so they can be returned by
- // AppendContacts() and GetContactById().
- void SetContacts(const ContactPointers& contacts);
-
- // Invokes observers' OnContactsUpdated() methods.
- void NotifyObserversAboutContactsUpdate();
-
- // ContactStore implementation:
- virtual void Init() OVERRIDE;
- virtual void AppendContacts(ContactPointers* contacts_out) OVERRIDE;
- virtual const Contact* GetContactById(const std::string& contact_id) OVERRIDE;
- virtual void AddObserver(ContactStoreObserver* observer) OVERRIDE;
- virtual void RemoveObserver(ContactStoreObserver* observer) OVERRIDE;
-
- private:
- // Map from a contact's ID to the contact itself.
- typedef std::map<std::string, Contact*> ContactMap;
-
- // Factory that created this store. Not owned.
- FakeContactStoreFactory* factory_;
-
- ObserverList<ContactStoreObserver> observers_;
-
- // Owns the pointed-to Contact values.
- ContactMap contacts_;
-
- // Deletes values in |contacts_|.
- STLValueDeleter<ContactMap> contacts_deleter_;
-
- DISALLOW_COPY_AND_ASSIGN(FakeContactStore);
-};
-
-// ContactStoreFactory implementation that returns FakeContactStores.
-class FakeContactStoreFactory : public ContactStoreFactory {
- public:
- FakeContactStoreFactory();
- virtual ~FakeContactStoreFactory();
-
- void set_permit_store_creation(bool permit) {
- permit_store_creation_ = permit;
- }
-
- // Returns the FakeContactStore previously created for |profile|, or NULL if
- // no store has been created for it.
- FakeContactStore* GetContactStoreForProfile(Profile* profile);
-
- // Removes |store| from |stores_| after being called by a FakeContactStore's
- // d'tor.
- void RemoveStore(FakeContactStore* store);
-
- // ContactStoreFactory implementation:
- virtual bool CanCreateContactStoreForProfile(Profile* profile) OVERRIDE;
- virtual ContactStore* CreateContactStore(Profile* profile) OVERRIDE;
-
- private:
- typedef std::map<Profile*, FakeContactStore*> ProfileStoreMap;
-
- // Live FakeContactStore objects that we've handed out. We don't retain
- // ownership of these, but we hang on to the pointers so that tests can
- // manipulate the stores while they're in use.
- ProfileStoreMap stores_;
-
- // Should CanCreateContactStoreForProfile() return true?
- bool permit_store_creation_;
-
- DISALLOW_COPY_AND_ASSIGN(FakeContactStoreFactory);
-};
-
-} // namespace contacts
-
-#endif // CHROME_BROWSER_CHROMEOS_CONTACTS_FAKE_CONTACT_STORE_H_
diff --git a/chrome/browser/chromeos/contacts/gdata_contacts_service.cc b/chrome/browser/chromeos/contacts/gdata_contacts_service.cc
deleted file mode 100644
index 16ce208..0000000
--- a/chrome/browser/chromeos/contacts/gdata_contacts_service.cc
+++ /dev/null
@@ -1,894 +0,0 @@
-// 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.
-
-#include "chrome/browser/chromeos/contacts/gdata_contacts_service.h"
-
-#include <cstring>
-#include <map>
-#include <string>
-#include <utility>
-
-#include "base/json/json_value_converter.h"
-#include "base/json/json_writer.h"
-#include "base/logging.h"
-#include "base/memory/weak_ptr.h"
-#include "base/metrics/histogram.h"
-#include "base/stl_util.h"
-#include "base/strings/string_util.h"
-#include "base/threading/sequenced_worker_pool.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-#include "base/values.h"
-#include "chrome/browser/chromeos/contacts/contact.pb.h"
-#include "content/public/browser/browser_thread.h"
-#include "google_apis/drive/gdata_contacts_requests.h"
-#include "google_apis/drive/gdata_errorcode.h"
-#include "google_apis/drive/request_sender.h"
-#include "google_apis/drive/time_util.h"
-
-using content::BrowserThread;
-
-namespace contacts {
-
-namespace {
-
-// Download outcomes reported via the "Contacts.FullUpdateResult" and
-// "Contacts.IncrementalUpdateResult" histograms.
-enum HistogramResult {
- HISTOGRAM_RESULT_SUCCESS = 0,
- HISTOGRAM_RESULT_GROUPS_DOWNLOAD_FAILURE = 1,
- HISTOGRAM_RESULT_GROUPS_PARSE_FAILURE = 2,
- HISTOGRAM_RESULT_MY_CONTACTS_GROUP_NOT_FOUND = 3,
- HISTOGRAM_RESULT_CONTACTS_DOWNLOAD_FAILURE = 4,
- HISTOGRAM_RESULT_CONTACTS_PARSE_FAILURE = 5,
- HISTOGRAM_RESULT_PHOTO_DOWNLOAD_FAILURE = 6,
- HISTOGRAM_RESULT_MAX_VALUE = 7,
-};
-
-// Maximum number of profile photos that we'll download per second.
-// At values above 10, Google starts returning 503 errors.
-const int kMaxPhotoDownloadsPerSecond = 10;
-
-// Give up after seeing more than this many transient errors while trying to
-// download a photo for a single contact.
-const int kMaxTransientPhotoDownloadErrorsPerContact = 2;
-
-// Hardcoded system group ID for the "My Contacts" group, per
-// https://developers.google.com/google-apps/contacts/v3/#contact_group_entry.
-const char kMyContactsSystemGroupId[] = "Contacts";
-
-// Top-level field in a contact groups feed containing the list of entries.
-const char kGroupEntryField[] = "feed.entry";
-
-// Field in group entries containing the system group ID (e.g. ID "Contacts"
-// for the "My Contacts" system group). See
-// https://developers.google.com/google-apps/contacts/v3/#contact_group_entry
-// for more details.
-const char kSystemGroupIdField[] = "gContact$systemGroup.id";
-
-// Field in the top-level object containing the contacts feed.
-const char kFeedField[] = "feed";
-
-// Field in the contacts feed containing a list of category information, along
-// with fields within the dictionaries contained in the list and expected
-// values.
-const char kCategoryField[] = "category";
-const char kCategorySchemeField[] = "scheme";
-const char kCategorySchemeValue[] = "http://schemas.google.com/g/2005#kind";
-const char kCategoryTermField[] = "term";
-const char kCategoryTermValue[] =
- "http://schemas.google.com/contact/2008#contact";
-
-// Field in the contacts feed containing a list of contact entries.
-const char kEntryField[] = "entry";
-
-// Field in group and contact entries containing the item's ID.
-const char kIdField[] = "id.$t";
-
-// Top-level fields in contact entries.
-const char kDeletedField[] = "gd$deleted";
-const char kFullNameField[] = "gd$name.gd$fullName.$t";
-const char kGivenNameField[] = "gd$name.gd$givenName.$t";
-const char kAdditionalNameField[] = "gd$name.gd$additionalName.$t";
-const char kFamilyNameField[] = "gd$name.gd$familyName.$t";
-const char kNamePrefixField[] = "gd$name.gd$namePrefix.$t";
-const char kNameSuffixField[] = "gd$name.gd$nameSuffix.$t";
-const char kEmailField[] = "gd$email";
-const char kPhoneField[] = "gd$phoneNumber";
-const char kPostalAddressField[] = "gd$structuredPostalAddress";
-const char kInstantMessagingField[] = "gd$im";
-const char kLinkField[] = "link";
-const char kUpdatedField[] = "updated.$t";
-
-// Fields in entries in the |kEmailField| list.
-const char kEmailAddressField[] = "address";
-
-// Fields in entries in the |kPhoneField| list.
-const char kPhoneNumberField[] = "$t";
-
-// Fields in entries in the |kPostalAddressField| list.
-const char kPostalAddressFormattedField[] = "gd$formattedAddress.$t";
-
-// Fields in entries in the |kInstantMessagingField| list.
-const char kInstantMessagingAddressField[] = "address";
-const char kInstantMessagingProtocolField[] = "protocol";
-const char kInstantMessagingProtocolAimValue[] =
- "http://schemas.google.com/g/2005#AIM";
-const char kInstantMessagingProtocolMsnValue[] =
- "http://schemas.google.com/g/2005#MSN";
-const char kInstantMessagingProtocolYahooValue[] =
- "http://schemas.google.com/g/2005#YAHOO";
-const char kInstantMessagingProtocolSkypeValue[] =
- "http://schemas.google.com/g/2005#SKYPE";
-const char kInstantMessagingProtocolQqValue[] =
- "http://schemas.google.com/g/2005#QQ";
-const char kInstantMessagingProtocolGoogleTalkValue[] =
- "http://schemas.google.com/g/2005#GOOGLE_TALK";
-const char kInstantMessagingProtocolIcqValue[] =
- "http://schemas.google.com/g/2005#ICQ";
-const char kInstantMessagingProtocolJabberValue[] =
- "http://schemas.google.com/g/2005#JABBER";
-
-// Generic fields shared between address-like items (email, postal, etc.).
-const char kAddressPrimaryField[] = "primary";
-const char kAddressPrimaryTrueValue[] = "true";
-const char kAddressRelField[] = "rel";
-const char kAddressRelHomeValue[] = "http://schemas.google.com/g/2005#home";
-const char kAddressRelWorkValue[] = "http://schemas.google.com/g/2005#work";
-const char kAddressRelMobileValue[] = "http://schemas.google.com/g/2005#mobile";
-const char kAddressLabelField[] = "label";
-
-// Fields in entries in the |kLinkField| list.
-const char kLinkHrefField[] = "href";
-const char kLinkRelField[] = "rel";
-const char kLinkETagField[] = "gd$etag";
-const char kLinkRelPhotoValue[] =
- "http://schemas.google.com/contacts/2008/rel#photo";
-
-// Returns a string containing a pretty-printed JSON representation of |value|.
-std::string PrettyPrintValue(const base::Value& value) {
- std::string out;
- base::JSONWriter::WriteWithOptions(
- &value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &out);
- return out;
-}
-
-// Assigns the value at |path| within |dict| to |out|, returning false if the
-// path wasn't present. Unicode byte order marks are removed from the string.
-bool GetCleanedString(const base::DictionaryValue& dict,
- const std::string& path,
- std::string* out) {
- if (!dict.GetString(path, out))
- return false;
-
- // The Unicode byte order mark, U+FEFF, is useless in UTF-8 strings (which are
- // interpreted one byte at a time).
- ReplaceSubstringsAfterOffset(out, 0, "\xEF\xBB\xBF", "");
- return true;
-}
-
-// Returns whether an address is primary, given a dictionary representing a
-// single address.
-bool IsAddressPrimary(const base::DictionaryValue& address_dict) {
- std::string primary;
- address_dict.GetString(kAddressPrimaryField, &primary);
- return primary == kAddressPrimaryTrueValue;
-}
-
-// Initializes an AddressType message given a dictionary representing a single
-// address.
-void InitAddressType(const base::DictionaryValue& address_dict,
- Contact_AddressType* type) {
- DCHECK(type);
- type->Clear();
-
- std::string rel;
- address_dict.GetString(kAddressRelField, &rel);
- if (rel == kAddressRelHomeValue)
- type->set_relation(Contact_AddressType_Relation_HOME);
- else if (rel == kAddressRelWorkValue)
- type->set_relation(Contact_AddressType_Relation_WORK);
- else if (rel == kAddressRelMobileValue)
- type->set_relation(Contact_AddressType_Relation_MOBILE);
- else
- type->set_relation(Contact_AddressType_Relation_OTHER);
-
- GetCleanedString(address_dict, kAddressLabelField, type->mutable_label());
-}
-
-// Maps the protocol from a dictionary representing a contact's IM address to a
-// contacts::Contact_InstantMessagingAddress_Protocol value.
-contacts::Contact_InstantMessagingAddress_Protocol
-GetInstantMessagingProtocol(const base::DictionaryValue& im_dict) {
- std::string protocol;
- im_dict.GetString(kInstantMessagingProtocolField, &protocol);
- if (protocol == kInstantMessagingProtocolAimValue)
- return contacts::Contact_InstantMessagingAddress_Protocol_AIM;
- else if (protocol == kInstantMessagingProtocolMsnValue)
- return contacts::Contact_InstantMessagingAddress_Protocol_MSN;
- else if (protocol == kInstantMessagingProtocolYahooValue)
- return contacts::Contact_InstantMessagingAddress_Protocol_YAHOO;
- else if (protocol == kInstantMessagingProtocolSkypeValue)
- return contacts::Contact_InstantMessagingAddress_Protocol_SKYPE;
- else if (protocol == kInstantMessagingProtocolQqValue)
- return contacts::Contact_InstantMessagingAddress_Protocol_QQ;
- else if (protocol == kInstantMessagingProtocolGoogleTalkValue)
- return contacts::Contact_InstantMessagingAddress_Protocol_GOOGLE_TALK;
- else if (protocol == kInstantMessagingProtocolIcqValue)
- return contacts::Contact_InstantMessagingAddress_Protocol_ICQ;
- else if (protocol == kInstantMessagingProtocolJabberValue)
- return contacts::Contact_InstantMessagingAddress_Protocol_JABBER;
- else
- return contacts::Contact_InstantMessagingAddress_Protocol_OTHER;
-}
-
-// Gets the photo URL from a contact's dictionary (within the "entry" list).
-// Returns an empty string if no photo was found.
-std::string GetPhotoUrl(const base::DictionaryValue& dict) {
- const base::ListValue* link_list = NULL;
- if (!dict.GetList(kLinkField, &link_list))
- return std::string();
-
- for (size_t i = 0; i < link_list->GetSize(); ++i) {
- const base::DictionaryValue* link_dict = NULL;
- if (!link_list->GetDictionary(i, &link_dict))
- continue;
-
- std::string rel;
- if (!link_dict->GetString(kLinkRelField, &rel))
- continue;
- if (rel != kLinkRelPhotoValue)
- continue;
-
- // From https://goo.gl/7T6Od: "If a contact does not have a photo, then the
- // photo link element has no gd:etag attribute."
- std::string etag;
- if (!link_dict->GetString(kLinkETagField, &etag))
- continue;
-
- std::string url;
- if (link_dict->GetString(kLinkHrefField, &url))
- return url;
- }
- return std::string();
-}
-
-// Fills a Contact's fields using an entry from a GData feed.
-bool FillContactFromDictionary(const base::DictionaryValue& dict,
- contacts::Contact* contact) {
- DCHECK(contact);
- contact->Clear();
-
- if (!dict.GetString(kIdField, contact->mutable_contact_id()))
- return false;
-
- std::string updated;
- if (dict.GetString(kUpdatedField, &updated)) {
- base::Time update_time;
- if (!google_apis::util::GetTimeFromString(updated, &update_time)) {
- LOG(WARNING) << "Unable to parse time \"" << updated << "\"";
- return false;
- }
- contact->set_update_time(update_time.ToInternalValue());
- }
-
- const base::Value* deleted_value = NULL;
- contact->set_deleted(dict.Get(kDeletedField, &deleted_value));
- if (contact->deleted())
- return true;
-
- GetCleanedString(dict, kFullNameField, contact->mutable_full_name());
- GetCleanedString(dict, kGivenNameField, contact->mutable_given_name());
- GetCleanedString(
- dict, kAdditionalNameField, contact->mutable_additional_name());
- GetCleanedString(dict, kFamilyNameField, contact->mutable_family_name());
- GetCleanedString(dict, kNamePrefixField, contact->mutable_name_prefix());
- GetCleanedString(dict, kNameSuffixField, contact->mutable_name_suffix());
-
- const base::ListValue* email_list = NULL;
- if (dict.GetList(kEmailField, &email_list)) {
- for (size_t i = 0; i < email_list->GetSize(); ++i) {
- const base::DictionaryValue* email_dict = NULL;
- if (!email_list->GetDictionary(i, &email_dict))
- return false;
-
- contacts::Contact_EmailAddress* email = contact->add_email_addresses();
- if (!GetCleanedString(*email_dict,
- kEmailAddressField,
- email->mutable_address())) {
- return false;
- }
- email->set_primary(IsAddressPrimary(*email_dict));
- InitAddressType(*email_dict, email->mutable_type());
- }
- }
-
- const base::ListValue* phone_list = NULL;
- if (dict.GetList(kPhoneField, &phone_list)) {
- for (size_t i = 0; i < phone_list->GetSize(); ++i) {
- const base::DictionaryValue* phone_dict = NULL;
- if (!phone_list->GetDictionary(i, &phone_dict))
- return false;
-
- contacts::Contact_PhoneNumber* phone = contact->add_phone_numbers();
- if (!GetCleanedString(*phone_dict,
- kPhoneNumberField,
- phone->mutable_number())) {
- return false;
- }
- phone->set_primary(IsAddressPrimary(*phone_dict));
- InitAddressType(*phone_dict, phone->mutable_type());
- }
- }
-
- const base::ListValue* address_list = NULL;
- if (dict.GetList(kPostalAddressField, &address_list)) {
- for (size_t i = 0; i < address_list->GetSize(); ++i) {
- const base::DictionaryValue* address_dict = NULL;
- if (!address_list->GetDictionary(i, &address_dict))
- return false;
-
- contacts::Contact_PostalAddress* address =
- contact->add_postal_addresses();
- if (!GetCleanedString(*address_dict,
- kPostalAddressFormattedField,
- address->mutable_address())) {
- return false;
- }
- address->set_primary(IsAddressPrimary(*address_dict));
- InitAddressType(*address_dict, address->mutable_type());
- }
- }
-
- const base::ListValue* im_list = NULL;
- if (dict.GetList(kInstantMessagingField, &im_list)) {
- for (size_t i = 0; i < im_list->GetSize(); ++i) {
- const base::DictionaryValue* im_dict = NULL;
- if (!im_list->GetDictionary(i, &im_dict))
- return false;
-
- contacts::Contact_InstantMessagingAddress* im =
- contact->add_instant_messaging_addresses();
- if (!GetCleanedString(*im_dict,
- kInstantMessagingAddressField,
- im->mutable_address())) {
- return false;
- }
- im->set_primary(IsAddressPrimary(*im_dict));
- InitAddressType(*im_dict, im->mutable_type());
- im->set_protocol(GetInstantMessagingProtocol(*im_dict));
- }
- }
-
- return true;
-}
-
-// Structure into which we parse the contact groups feed using
-// JSONValueConverter.
-struct ContactGroups {
- struct ContactGroup {
- // Group ID, e.g.
- // "http://www.google.com/m8/feeds/groups/user%40gmail.com/base/6".
- std::string group_id;
-
- // System group ID (e.g. "Contacts" for the "My Contacts" system group) if
- // this is a system group, and empty otherwise. See http://goo.gl/oWVnN
- // for more details.
- std::string system_group_id;
- };
-
- // Given a system group ID, returns the corresponding group ID or an empty
- // string if the requested system group wasn't present.
- std::string GetGroupIdForSystemGroup(const std::string& system_group_id) {
- for (size_t i = 0; i < groups.size(); ++i) {
- const ContactGroup& group = *groups[i];
- if (group.system_group_id == system_group_id)
- return group.group_id;
- }
- return std::string();
- }
-
- // Given |value| corresponding to a dictionary in a contact group feed's
- // "entry" list, fills |result| with information about the group.
- static bool GetContactGroup(const base::Value* value, ContactGroup* result) {
- DCHECK(value);
- DCHECK(result);
- const base::DictionaryValue* dict = NULL;
- if (!value->GetAsDictionary(&dict))
- return false;
-
- dict->GetString(kIdField, &result->group_id);
- dict->GetString(kSystemGroupIdField, &result->system_group_id);
- return true;
- }
-
- static void RegisterJSONConverter(
- base::JSONValueConverter<ContactGroups>* converter) {
- DCHECK(converter);
- converter->RegisterRepeatedCustomValue<ContactGroup>(
- kGroupEntryField, &ContactGroups::groups, &GetContactGroup);
- }
-
- ScopedVector<ContactGroup> groups;
-};
-
-} // namespace
-
-// This class handles a single request to download all of a user's contacts.
-//
-// First, the feed containing the user's contact groups is downloaded via
-// GetContactGroupsRequest and examined to find the ID for the "My Contacts"
-// group (by default, the contacts API also returns suggested contacts). The
-// group ID is cached in GDataContactsService so that this step can be skipped
-// by later DownloadContactRequests.
-//
-// Next, the contacts feed is downloaded via GetContactsRequest and parsed.
-// Individual contacts::Contact objects are created using the data from the
-// feed.
-//
-// Finally, GetContactPhotoRequests are created and used to start downloading
-// contacts' photos in parallel. When all photos have been downloaded, the
-// contacts are passed to the passed-in callback.
-class GDataContactsService::DownloadContactsRequest {
- public:
- DownloadContactsRequest(
- GDataContactsService* service,
- google_apis::RequestSender* sender,
- SuccessCallback success_callback,
- FailureCallback failure_callback,
- const base::Time& min_update_time)
- : service_(service),
- sender_(sender),
- success_callback_(success_callback),
- failure_callback_(failure_callback),
- min_update_time_(min_update_time),
- contacts_(new ScopedVector<contacts::Contact>),
- my_contacts_group_id_(service->cached_my_contacts_group_id_),
- num_in_progress_photo_downloads_(0),
- photo_download_failed_(false),
- num_photo_download_404_errors_(0),
- total_photo_bytes_(0),
- weak_ptr_factory_(this) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(service_);
- DCHECK(sender_);
- }
-
- ~DownloadContactsRequest() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- service_ = NULL;
- sender_ = NULL;
- }
-
- const std::string my_contacts_group_id() const {
- return my_contacts_group_id_;
- }
-
- // Begins the contacts-downloading process. If the ID for the "My Contacts"
- // group has previously been cached, then the contacts download is started.
- // Otherwise, the contact groups download is started.
- void Run() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- download_start_time_ = base::TimeTicks::Now();
- if (!my_contacts_group_id_.empty()) {
- StartContactsDownload();
- } else {
- google_apis::GetContactGroupsRequest* operation =
- new google_apis::GetContactGroupsRequest(
- sender_,
- base::Bind(&DownloadContactsRequest::HandleGroupsFeedData,
- weak_ptr_factory_.GetWeakPtr()));
- if (!service_->groups_feed_url_for_testing_.is_empty()) {
- operation->set_feed_url_for_testing(
- service_->groups_feed_url_for_testing_);
- }
- sender_->StartRequestWithRetry(operation);
- }
- }
-
- private:
- // Invokes the failure callback and notifies GDataContactsService that the
- // request is done.
- void ReportFailure(HistogramResult histogram_result) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- SendHistograms(histogram_result);
- failure_callback_.Run();
- service_->OnRequestComplete(this);
- }
-
- // Reports UMA stats after the request has completed.
- void SendHistograms(HistogramResult result) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK_GE(result, 0);
- DCHECK_LT(result, HISTOGRAM_RESULT_MAX_VALUE);
-
- bool success = (result == HISTOGRAM_RESULT_SUCCESS);
- base::TimeDelta elapsed_time =
- base::TimeTicks::Now() - download_start_time_;
- int photo_error_percent = static_cast<int>(
- 100.0 * transient_photo_download_errors_per_contact_.size() /
- contact_photo_urls_.size() + 0.5);
-
- if (min_update_time_.is_null()) {
- UMA_HISTOGRAM_ENUMERATION("Contacts.FullUpdateResult",
- result, HISTOGRAM_RESULT_MAX_VALUE);
- if (success) {
- UMA_HISTOGRAM_MEDIUM_TIMES("Contacts.FullUpdateDuration",
- elapsed_time);
- UMA_HISTOGRAM_COUNTS_10000("Contacts.FullUpdateContacts",
- contacts_->size());
- UMA_HISTOGRAM_COUNTS_10000("Contacts.FullUpdatePhotos",
- contact_photo_urls_.size());
- UMA_HISTOGRAM_MEMORY_KB("Contacts.FullUpdatePhotoBytes",
- total_photo_bytes_);
- UMA_HISTOGRAM_COUNTS_10000("Contacts.FullUpdatePhoto404Errors",
- num_photo_download_404_errors_);
- UMA_HISTOGRAM_PERCENTAGE("Contacts.FullUpdatePhotoErrorPercent",
- photo_error_percent);
- }
- } else {
- UMA_HISTOGRAM_ENUMERATION("Contacts.IncrementalUpdateResult",
- result, HISTOGRAM_RESULT_MAX_VALUE);
- if (success) {
- UMA_HISTOGRAM_MEDIUM_TIMES("Contacts.IncrementalUpdateDuration",
- elapsed_time);
- UMA_HISTOGRAM_COUNTS_10000("Contacts.IncrementalUpdateContacts",
- contacts_->size());
- UMA_HISTOGRAM_COUNTS_10000("Contacts.IncrementalUpdatePhotos",
- contact_photo_urls_.size());
- UMA_HISTOGRAM_MEMORY_KB("Contacts.IncrementalUpdatePhotoBytes",
- total_photo_bytes_);
- UMA_HISTOGRAM_COUNTS_10000("Contacts.IncrementalUpdatePhoto404Errors",
- num_photo_download_404_errors_);
- UMA_HISTOGRAM_PERCENTAGE("Contacts.IncrementalUpdatePhotoErrorPercent",
- photo_error_percent);
- }
- }
- }
-
- // Callback for GetContactGroupsRequest calls. Starts downloading the
- // actual contacts after finding the "My Contacts" group ID.
- void HandleGroupsFeedData(google_apis::GDataErrorCode error,
- scoped_ptr<base::Value> feed_data) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (error != google_apis::HTTP_SUCCESS) {
- LOG(WARNING) << "Got error " << error << " while downloading groups";
- ReportFailure(HISTOGRAM_RESULT_GROUPS_DOWNLOAD_FAILURE);
- return;
- }
-
- VLOG(2) << "Got groups feed data:\n"
- << PrettyPrintValue(*(feed_data.get()));
- ContactGroups groups;
- base::JSONValueConverter<ContactGroups> converter;
- if (!converter.Convert(*feed_data, &groups)) {
- LOG(WARNING) << "Unable to parse groups feed";
- ReportFailure(HISTOGRAM_RESULT_GROUPS_PARSE_FAILURE);
- return;
- }
-
- my_contacts_group_id_ =
- groups.GetGroupIdForSystemGroup(kMyContactsSystemGroupId);
- if (!my_contacts_group_id_.empty()) {
- StartContactsDownload();
- } else {
- LOG(WARNING) << "Unable to find ID for \"My Contacts\" group";
- ReportFailure(HISTOGRAM_RESULT_MY_CONTACTS_GROUP_NOT_FOUND);
- }
- }
-
- // Starts a download of the contacts from the "My Contacts" group.
- void StartContactsDownload() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- google_apis::GetContactsRequest* operation =
- new google_apis::GetContactsRequest(
- sender_,
- my_contacts_group_id_,
- min_update_time_,
- base::Bind(&DownloadContactsRequest::HandleContactsFeedData,
- weak_ptr_factory_.GetWeakPtr()));
- if (!service_->contacts_feed_url_for_testing_.is_empty()) {
- operation->set_feed_url_for_testing(
- service_->contacts_feed_url_for_testing_);
- }
- sender_->StartRequestWithRetry(operation);
- }
-
- // Callback for GetContactsRequest calls.
- void HandleContactsFeedData(google_apis::GDataErrorCode error,
- scoped_ptr<base::Value> feed_data) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (error != google_apis::HTTP_SUCCESS) {
- LOG(WARNING) << "Got error " << error << " while downloading contacts";
- ReportFailure(HISTOGRAM_RESULT_CONTACTS_DOWNLOAD_FAILURE);
- return;
- }
-
- VLOG(2) << "Got contacts feed data:\n"
- << PrettyPrintValue(*(feed_data.get()));
- if (!ProcessContactsFeedData(*feed_data.get())) {
- LOG(WARNING) << "Unable to process contacts feed data";
- ReportFailure(HISTOGRAM_RESULT_CONTACTS_PARSE_FAILURE);
- return;
- }
-
- StartPhotoDownloads();
- photo_download_timer_.Start(
- FROM_HERE, service_->photo_download_timer_interval_,
- this, &DownloadContactsRequest::StartPhotoDownloads);
- CheckCompletion();
- }
-
- // Processes the raw contacts feed from |feed_data| and fills |contacts_|.
- // Returns true on success.
- bool ProcessContactsFeedData(const base::Value& feed_data) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- const base::DictionaryValue* toplevel_dict = NULL;
- if (!feed_data.GetAsDictionary(&toplevel_dict)) {
- LOG(WARNING) << "Top-level object is not a dictionary";
- return false;
- }
-
- const base::DictionaryValue* feed_dict = NULL;
- if (!toplevel_dict->GetDictionary(kFeedField, &feed_dict)) {
- LOG(WARNING) << "Feed dictionary missing";
- return false;
- }
-
- // Check the category field to confirm that this is actually a contact feed.
- const base::ListValue* category_list = NULL;
- if (!feed_dict->GetList(kCategoryField, &category_list)) {
- LOG(WARNING) << "Category list missing";
- return false;
- }
- const base::DictionaryValue* category_dict = NULL;
- if (category_list->GetSize() != 1 ||
- !category_list->GetDictionary(0, &category_dict)) {
- LOG(WARNING) << "Unable to get dictionary from category list of size "
- << category_list->GetSize();
- return false;
- }
- std::string category_scheme, category_term;
- if (!category_dict->GetString(kCategorySchemeField, &category_scheme) ||
- !category_dict->GetString(kCategoryTermField, &category_term) ||
- category_scheme != kCategorySchemeValue ||
- category_term != kCategoryTermValue) {
- LOG(WARNING) << "Unexpected category (scheme was \"" << category_scheme
- << "\", term was \"" << category_term << "\")";
- return false;
- }
-
- // A missing entry list means no entries (maybe we're doing an incremental
- // update and nothing has changed).
- const base::ListValue* entry_list = NULL;
- if (!feed_dict->GetList(kEntryField, &entry_list))
- return true;
-
- contacts_needing_photo_downloads_.reserve(entry_list->GetSize());
-
- for (base::ListValue::const_iterator entry_it = entry_list->begin();
- entry_it != entry_list->end(); ++entry_it) {
- const size_t index = (entry_it - entry_list->begin());
- const base::DictionaryValue* contact_dict = NULL;
- if (!(*entry_it)->GetAsDictionary(&contact_dict)) {
- LOG(WARNING) << "Entry " << index << " isn't a dictionary";
- return false;
- }
-
- scoped_ptr<contacts::Contact> contact(new contacts::Contact);
- if (!FillContactFromDictionary(*contact_dict, contact.get())) {
- LOG(WARNING) << "Unable to fill entry " << index;
- return false;
- }
-
- VLOG(1) << "Got contact " << index << ":"
- << " id=" << contact->contact_id()
- << " full_name=\"" << contact->full_name() << "\""
- << " update_time=" << contact->update_time();
-
- std::string photo_url = GetPhotoUrl(*contact_dict);
- if (!photo_url.empty()) {
- if (!service_->rewrite_photo_url_callback_for_testing_.is_null()) {
- photo_url =
- service_->rewrite_photo_url_callback_for_testing_.Run(photo_url);
- }
- contact_photo_urls_[contact.get()] = photo_url;
- contacts_needing_photo_downloads_.push_back(contact.get());
- }
-
- contacts_->push_back(contact.release());
- }
-
- return true;
- }
-
- // If we're done downloading photos, invokes a callback and deletes |this|.
- // Otherwise, starts one or more downloads of URLs from
- // |contacts_needing_photo_downloads_|.
- void CheckCompletion() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (contacts_needing_photo_downloads_.empty() &&
- num_in_progress_photo_downloads_ == 0) {
- VLOG(1) << "Done downloading photos; invoking callback";
- photo_download_timer_.Stop();
- if (photo_download_failed_) {
- ReportFailure(HISTOGRAM_RESULT_PHOTO_DOWNLOAD_FAILURE );
- } else {
- SendHistograms(HISTOGRAM_RESULT_SUCCESS);
- success_callback_.Run(contacts_.Pass());
- service_->OnRequestComplete(this);
- }
- return;
- }
- }
-
- // Starts photo downloads for contacts in |contacts_needing_photo_downloads_|.
- // Should be invoked only once per second.
- void StartPhotoDownloads() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- while (!contacts_needing_photo_downloads_.empty() &&
- (num_in_progress_photo_downloads_ <
- service_->max_photo_downloads_per_second_)) {
- contacts::Contact* contact = contacts_needing_photo_downloads_.back();
- contacts_needing_photo_downloads_.pop_back();
- DCHECK(contact_photo_urls_.count(contact));
- std::string url = contact_photo_urls_[contact];
-
- VLOG(1) << "Starting download of photo " << url << " for "
- << contact->contact_id();
- sender_->StartRequestWithRetry(
- new google_apis::GetContactPhotoRequest(
- sender_,
- GURL(url),
- base::Bind(&DownloadContactsRequest::HandlePhotoData,
- weak_ptr_factory_.GetWeakPtr(),
- contact)));
- num_in_progress_photo_downloads_++;
- }
- }
-
- // Callback for GetContactPhotoRequest calls. Updates the associated
- // Contact and checks for completion.
- void HandlePhotoData(contacts::Contact* contact,
- google_apis::GDataErrorCode error,
- scoped_ptr<std::string> download_data) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- VLOG(1) << "Got photo data for " << contact->contact_id()
- << " (error=" << error << " size=" << download_data->size() << ")";
- num_in_progress_photo_downloads_--;
-
- if (error == google_apis::HTTP_INTERNAL_SERVER_ERROR ||
- error == google_apis::HTTP_SERVICE_UNAVAILABLE) {
- int num_errors = ++transient_photo_download_errors_per_contact_[contact];
- if (num_errors <= kMaxTransientPhotoDownloadErrorsPerContact) {
- LOG(WARNING) << "Got error " << error << " while downloading photo "
- << "for " << contact->contact_id() << "; retrying";
- contacts_needing_photo_downloads_.push_back(contact);
- return;
- }
- }
-
- if (error == google_apis::HTTP_NOT_FOUND) {
- LOG(WARNING) << "Got error " << error << " while downloading photo "
- << "for " << contact->contact_id() << "; skipping";
- num_photo_download_404_errors_++;
- CheckCompletion();
- return;
- }
-
- if (error != google_apis::HTTP_SUCCESS) {
- LOG(WARNING) << "Got error " << error << " while downloading photo "
- << "for " << contact->contact_id() << "; giving up";
- photo_download_failed_ = true;
- // Make sure we don't start any more downloads.
- contacts_needing_photo_downloads_.clear();
- CheckCompletion();
- return;
- }
-
- total_photo_bytes_ += download_data->size();
- contact->set_raw_untrusted_photo(*download_data);
- CheckCompletion();
- }
-
- typedef std::map<contacts::Contact*, std::string> ContactPhotoUrls;
-
- GDataContactsService* service_; // not owned
- google_apis::RequestSender* sender_; // not owned
-
- SuccessCallback success_callback_;
- FailureCallback failure_callback_;
-
- base::Time min_update_time_;
-
- scoped_ptr<ScopedVector<contacts::Contact> > contacts_;
-
- // ID of the "My Contacts" contacts group.
- std::string my_contacts_group_id_;
-
- // Map from a contact to the URL at which its photo is located.
- // Contacts without photos do not appear in this map.
- ContactPhotoUrls contact_photo_urls_;
-
- // Invokes StartPhotoDownloads() once per second.
- base::RepeatingTimer<DownloadContactsRequest> photo_download_timer_;
-
- // Contacts that have photos that we still need to start downloading.
- // When we start a download, the contact is removed from this list.
- std::vector<contacts::Contact*> contacts_needing_photo_downloads_;
-
- // Number of in-progress photo downloads.
- int num_in_progress_photo_downloads_;
-
- // Map from a contact to the number of transient errors that we've encountered
- // while trying to download its photo. Contacts for which no errors have been
- // encountered aren't represented in the map.
- std::map<contacts::Contact*, int>
- transient_photo_download_errors_per_contact_;
-
- // Did we encounter a fatal error while downloading a photo?
- bool photo_download_failed_;
-
- // How many photos did we skip due to 404 errors?
- int num_photo_download_404_errors_;
-
- // Total size of all photos that were downloaded.
- size_t total_photo_bytes_;
-
- // Time at which Run() was called.
- base::TimeTicks download_start_time_;
-
- // Note: This should remain the last member so it'll be destroyed and
- // invalidate its weak pointers before any other members are destroyed.
- base::WeakPtrFactory<DownloadContactsRequest> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(DownloadContactsRequest);
-};
-
-GDataContactsService::GDataContactsService(
- net::URLRequestContextGetter* url_request_context_getter,
- google_apis::AuthServiceInterface* auth_service)
- : max_photo_downloads_per_second_(kMaxPhotoDownloadsPerSecond),
- photo_download_timer_interval_(base::TimeDelta::FromSeconds(1)) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- sender_.reset(new google_apis::RequestSender(
- auth_service,
- url_request_context_getter,
- BrowserThread::GetBlockingPool()->GetSequencedTaskRunner(
- BrowserThread::GetBlockingPool()->GetSequenceToken()).get(),
- "" /* custom_user_agent */));
-}
-
-GDataContactsService::~GDataContactsService() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- STLDeleteContainerPointers(requests_.begin(), requests_.end());
- requests_.clear();
-}
-
-void GDataContactsService::DownloadContacts(SuccessCallback success_callback,
- FailureCallback failure_callback,
- const base::Time& min_update_time) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DownloadContactsRequest* request =
- new DownloadContactsRequest(this,
- sender_.get(),
- success_callback,
- failure_callback,
- min_update_time);
- VLOG(1) << "Starting contacts download with request " << request;
- requests_.insert(request);
- request->Run();
-}
-
-void GDataContactsService::OnRequestComplete(DownloadContactsRequest* request) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(request);
- VLOG(1) << "Download request " << request << " complete";
- if (!request->my_contacts_group_id().empty())
- cached_my_contacts_group_id_ = request->my_contacts_group_id();
- requests_.erase(request);
- delete request;
-}
-
-} // namespace contacts
diff --git a/chrome/browser/chromeos/contacts/gdata_contacts_service.h b/chrome/browser/chromeos/contacts/gdata_contacts_service.h
deleted file mode 100644
index d41fa25..0000000
--- a/chrome/browser/chromeos/contacts/gdata_contacts_service.h
+++ /dev/null
@@ -1,139 +0,0 @@
-// 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_CONTACTS_GDATA_CONTACTS_SERVICE_H_
-#define CHROME_BROWSER_CHROMEOS_CONTACTS_GDATA_CONTACTS_SERVICE_H_
-
-#include <set>
-#include <string>
-
-#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/time.h"
-#include "url/gurl.h"
-
-class Profile;
-
-namespace base {
-class Value;
-} // namespace base
-
-namespace google_apis {
-class AuthServiceInterface;
-class RequestSender;
-} // namespace google_apis
-
-namespace net {
-class URLRequestContextGetter;
-} // namespace net
-
-namespace contacts {
-
-class Contact;
-
-// 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() {}
-
- // 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;
-
- GDataContactsService(
- net::URLRequestContextGetter* url_request_context_getter,
- google_apis::AuthServiceInterface* auth_service);
- virtual ~GDataContactsService();
-
- const std::string& cached_my_contacts_group_id_for_testing() const {
- return cached_my_contacts_group_id_;
- }
- void clear_cached_my_contacts_group_id_for_testing() {
- cached_my_contacts_group_id_.clear();
- }
-
- void set_max_photo_downloads_per_second_for_testing(int max_downloads) {
- max_photo_downloads_per_second_ = max_downloads;
- }
- void set_photo_download_timer_interval_for_testing(base::TimeDelta interval) {
- photo_download_timer_interval_ = interval;
- }
- void set_groups_feed_url_for_testing(const GURL& url) {
- groups_feed_url_for_testing_ = url;
- }
- void set_contacts_feed_url_for_testing(const GURL& url) {
- contacts_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 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);
-
- scoped_ptr<google_apis::RequestSender> sender_;
-
- // Group ID for the "My Contacts" system contacts group.
- // Cached after a DownloadContactsRequest has completed.
- std::string cached_my_contacts_group_id_;
-
- // In-progress download requests. Pointers are owned by this class.
- std::set<DownloadContactsRequest*> requests_;
-
- // Maximum number of photos we'll try to download per second (per
- // DownloadContacts() request).
- int max_photo_downloads_per_second_;
-
- // Amount of time that we'll wait between waves of photo download requests.
- // This is usually one second (see |max_photo_downloads_per_second_|) but can
- // be set to a lower value for tests to make them complete more quickly.
- base::TimeDelta photo_download_timer_interval_;
-
- // If non-empty, URLs that will be used to fetch feeds.
- GURL groups_feed_url_for_testing_;
- GURL contacts_feed_url_for_testing_;
-
- // 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 contacts
-
-#endif // CHROME_BROWSER_CHROMEOS_CONTACTS_GDATA_CONTACTS_SERVICE_H_
diff --git a/chrome/browser/chromeos/contacts/gdata_contacts_service_stub.cc b/chrome/browser/chromeos/contacts/gdata_contacts_service_stub.cc
deleted file mode 100644
index a14e5c0..0000000
--- a/chrome/browser/chromeos/contacts/gdata_contacts_service_stub.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// 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.
-
-#include "chrome/browser/chromeos/contacts/gdata_contacts_service_stub.h"
-
-#include <vector>
-
-#include "chrome/browser/chromeos/contacts/contact.pb.h"
-#include "chrome/browser/chromeos/contacts/contact_test_util.h"
-#include "content/public/browser/browser_thread.h"
-#include "google_apis/drive/time_util.h"
-
-using content::BrowserThread;
-
-namespace contacts {
-
-GDataContactsServiceStub::GDataContactsServiceStub()
- : num_download_requests_(0),
- num_download_requests_with_wrong_timestamps_(0),
- download_should_succeed_(true) {
-}
-
-GDataContactsServiceStub::~GDataContactsServiceStub() {
-}
-
-void GDataContactsServiceStub::SetContacts(
- const contacts::ContactPointers& contacts,
- const base::Time& expected_min_update_time) {
- contacts::test::CopyContacts(contacts, &contacts_);
- expected_min_update_time_ = expected_min_update_time;
-}
-
-void GDataContactsServiceStub::DownloadContacts(
- SuccessCallback success_callback,
- FailureCallback failure_callback,
- const base::Time& min_update_time) {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- num_download_requests_++;
-
- if (!download_should_succeed_) {
- failure_callback.Run();
- return;
- }
-
- if (min_update_time != expected_min_update_time_) {
- LOG(ERROR) << "Actual minimum update time ("
- << google_apis::util::FormatTimeAsString(min_update_time) << ") "
- << "differed from expected ("
- << google_apis::util::FormatTimeAsString(
- expected_min_update_time_)
- << "); not returning any contacts";
- num_download_requests_with_wrong_timestamps_++;
- failure_callback.Run();
- return;
- }
-
- scoped_ptr<ScopedVector<contacts::Contact> > contacts(
- new ScopedVector<contacts::Contact>());
- contacts::test::CopyContacts(contacts_, contacts.get());
- success_callback.Run(contacts.Pass());
-}
-
-} // namespace contacts
diff --git a/chrome/browser/chromeos/contacts/gdata_contacts_service_stub.h b/chrome/browser/chromeos/contacts/gdata_contacts_service_stub.h
deleted file mode 100644
index 7db2381..0000000
--- a/chrome/browser/chromeos/contacts/gdata_contacts_service_stub.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// 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_CONTACTS_GDATA_CONTACTS_SERVICE_STUB_H_
-#define CHROME_BROWSER_CHROMEOS_CONTACTS_GDATA_CONTACTS_SERVICE_STUB_H_
-
-#include "chrome/browser/chromeos/contacts/gdata_contacts_service.h"
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/time/time.h"
-
-namespace contacts {
-typedef std::vector<const contacts::Contact*> ContactPointers;
-
-// "Stub" implementation of GDataContactsServiceInterface used for testing.
-// Returns a pre-set list of contacts in response to DownloadContacts() calls.
-class GDataContactsServiceStub : public GDataContactsServiceInterface {
- public:
- GDataContactsServiceStub();
- virtual ~GDataContactsServiceStub();
-
- int num_download_requests() const { return num_download_requests_; }
- int num_download_requests_with_wrong_timestamps() const {
- return num_download_requests_with_wrong_timestamps_;
- }
- void reset_stats() {
- num_download_requests_ = 0;
- num_download_requests_with_wrong_timestamps_ = 0;
- }
- void set_download_should_succeed(bool succeed) {
- download_should_succeed_ = succeed;
- }
-
- // Sets the contacts that will be returned by DownloadContacts(), assuming
- // that the request's |min_update_time| matches |expected_min_update_time|.
- void SetContacts(const contacts::ContactPointers& contacts,
- const base::Time& expected_min_update_time);
-
- // Overridden from GDataContactsServiceInterface:
- virtual void DownloadContacts(SuccessCallback success_callback,
- FailureCallback failure_callback,
- const base::Time& min_update_time) OVERRIDE;
-
- private:
- // How many times has DownloadContacts() been called?
- int num_download_requests_;
-
- // How many times has DownloadContacts() been called with a |min_update_time|
- // parameter that doesn't match |expected_min_update_time_|?
- int num_download_requests_with_wrong_timestamps_;
-
- // Should calls to DownloadContacts() succeed?
- bool download_should_succeed_;
-
- // Contacts to be returned by calls to DownloadContacts().
- ScopedVector<contacts::Contact> contacts_;
-
- // |min_update_time| value that we expect to be passed to DownloadContacts().
- // If a different value is passed, we'll log an error and report failure.
- base::Time expected_min_update_time_;
-
- DISALLOW_COPY_AND_ASSIGN(GDataContactsServiceStub);
-};
-
-} // namespace contacts
-
-#endif // CHROME_BROWSER_CHROMEOS_CONTACTS_GDATA_CONTACTS_SERVICE_STUB_H_
diff --git a/chrome/browser/chromeos/contacts/gdata_contacts_service_unittest.cc b/chrome/browser/chromeos/contacts/gdata_contacts_service_unittest.cc
deleted file mode 100644
index c16704e..0000000
--- a/chrome/browser/chromeos/contacts/gdata_contacts_service_unittest.cc
+++ /dev/null
@@ -1,331 +0,0 @@
-// 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.
-
-#include "chrome/browser/chromeos/contacts/gdata_contacts_service.h"
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/stringprintf.h"
-#include "base/time/time.h"
-#include "chrome/browser/chromeos/contacts/contact.pb.h"
-#include "chrome/browser/chromeos/contacts/contact_test_util.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/test/test_browser_thread.h"
-#include "content/public/test/test_utils.h"
-#include "google_apis/drive/dummy_auth_service.h"
-#include "google_apis/drive/test_util.h"
-#include "google_apis/drive/time_util.h"
-#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "net/test/embedded_test_server/http_request.h"
-#include "net/test/embedded_test_server/http_response.h"
-#include "net/url_request/url_request_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/size.h"
-
-using content::BrowserThread;
-
-namespace contacts {
-namespace {
-
-// Filename of JSON feed containing contact groups.
-const char kGroupsFeedFilename[] = "/groups.json";
-
-// Width and height of /photo.png on the test server.
-const int kPhotoSize = 48;
-
-// Initializes |contact| using the passed-in values.
-void InitContact(const std::string& contact_id,
- const std::string& rfc_3339_update_time,
- bool deleted,
- const std::string& full_name,
- const std::string& given_name,
- const std::string& additional_name,
- const std::string& family_name,
- const std::string& name_prefix,
- const std::string& name_suffix,
- contacts::Contact* contact) {
- DCHECK(contact);
- contact->set_contact_id(contact_id);
- base::Time update_time;
- CHECK(google_apis::util::GetTimeFromString(
- rfc_3339_update_time, &update_time))
- << "Unable to parse time \"" << rfc_3339_update_time << "\"";
- contact->set_update_time(update_time.ToInternalValue());
- contact->set_deleted(deleted);
- contact->set_full_name(full_name);
- contact->set_given_name(given_name);
- contact->set_additional_name(additional_name);
- contact->set_family_name(family_name);
- contact->set_name_prefix(name_prefix);
- contact->set_name_suffix(name_suffix);
-}
-
-class GDataContactsServiceTest : public testing::Test {
- public:
- GDataContactsServiceTest()
- : ui_thread_(content::BrowserThread::UI, &message_loop_),
- io_thread_(content::BrowserThread::IO),
- download_was_successful_(false) {
- }
-
- virtual void SetUp() OVERRIDE {
- io_thread_.StartIOThread();
- request_context_getter_ = new net::TestURLRequestContextGetter(
- content::BrowserThread::GetMessageLoopProxyForThread(
- content::BrowserThread::IO));
-
- test_server_.reset(new net::test_server::EmbeddedTestServer);
- ASSERT_TRUE(test_server_->InitializeAndWaitUntilReady());
- test_server_->RegisterRequestHandler(
- base::Bind(&GDataContactsServiceTest::HandleDownloadRequest,
- base::Unretained(this)));
- service_.reset(new GDataContactsService(request_context_getter_.get(),
- new google_apis::DummyAuthService));
- service_->set_rewrite_photo_url_callback_for_testing(
- base::Bind(&GDataContactsServiceTest::RewritePhotoUrl,
- base::Unretained(this)));
- service_->set_groups_feed_url_for_testing(
- test_server_->GetURL(kGroupsFeedFilename));
- service_->set_photo_download_timer_interval_for_testing(
- base::TimeDelta::FromMilliseconds(10));
- }
-
- virtual void TearDown() OVERRIDE {
- EXPECT_TRUE(test_server_->ShutdownAndWaitUntilComplete());
- test_server_.reset();
- request_context_getter_ = NULL;
- service_.reset();
- }
-
- protected:
- // Downloads contacts from |feed_filename| (within the chromeos/gdata/contacts
- // test data directory). |min_update_time| is appended to the URL and the
- // resulting contacts are swapped into |contacts|. Returns false if the
- // download failed.
- bool Download(const std::string& feed_filename,
- const base::Time& min_update_time,
- scoped_ptr<ScopedVector<contacts::Contact> >* contacts) {
- DCHECK(contacts);
- service_->set_contacts_feed_url_for_testing(
- test_server_->GetURL(feed_filename));
- service_->DownloadContacts(
- base::Bind(&GDataContactsServiceTest::OnSuccess,
- base::Unretained(this)),
- base::Bind(&GDataContactsServiceTest::OnFailure,
- base::Unretained(this)),
- min_update_time);
- content::RunMessageLoop();
- contacts->swap(downloaded_contacts_);
- return download_was_successful_;
- }
-
- scoped_ptr<GDataContactsService> service_;
- scoped_ptr<net::test_server::EmbeddedTestServer> test_server_;
-
- private:
- // Rewrites |original_url|, a photo URL from a contacts feed, to instead point
- // at a file on |test_server_|.
- std::string RewritePhotoUrl(const std::string& original_url) {
- return test_server_->GetURL(GURL(original_url).path()).spec();
- }
-
- // Handles success for Download().
- void OnSuccess(scoped_ptr<ScopedVector<contacts::Contact> > contacts) {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- download_was_successful_ = true;
- downloaded_contacts_.swap(contacts);
- base::MessageLoop::current()->Quit();
- }
-
- // Handles failure for Download().
- void OnFailure() {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- download_was_successful_ = false;
- downloaded_contacts_.reset(new ScopedVector<contacts::Contact>());
- base::MessageLoop::current()->Quit();
- }
-
- // Handles a request for downloading a file. Reads a requested file and
- // returns the content.
- scoped_ptr<net::test_server::HttpResponse> HandleDownloadRequest(
- const net::test_server::HttpRequest& request) {
- // Requested url must not contain a query string.
- scoped_ptr<net::test_server::BasicHttpResponse> result =
- google_apis::test_util::CreateHttpResponseFromFile(
- google_apis::test_util::GetTestFilePath(
- std::string("chromeos/gdata/contacts") + request.relative_url));
- return result.PassAs<net::test_server::HttpResponse>();
- }
-
- base::MessageLoopForUI message_loop_;
- content::TestBrowserThread ui_thread_;
- content::TestBrowserThread io_thread_;
- scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
-
- // Was the last download successful? Used to pass the result back from
- // OnSuccess() and OnFailure() to Download().
- bool download_was_successful_;
-
- // Used to pass downloaded contacts back to Download().
- scoped_ptr<ScopedVector<contacts::Contact> > downloaded_contacts_;
-};
-
-} // namespace
-
-// Test that we report failure for feeds that are broken in various ways.
-TEST_F(GDataContactsServiceTest, BrokenFeeds) {
- scoped_ptr<ScopedVector<contacts::Contact> > contacts;
- EXPECT_FALSE(Download("/some_bogus_file", base::Time(), &contacts));
- EXPECT_FALSE(Download("/empty.txt", base::Time(), &contacts));
- EXPECT_FALSE(Download("/not_json.txt", base::Time(), &contacts));
- EXPECT_FALSE(Download("/not_dictionary.json", base::Time(), &contacts));
- EXPECT_FALSE(Download("/no_feed.json", base::Time(), &contacts));
- EXPECT_FALSE(Download("/no_category.json", base::Time(), &contacts));
- EXPECT_FALSE(Download("/wrong_category.json", base::Time(), &contacts));
-
- // Missing photos should be allowed, though (as this can occur in production).
- EXPECT_TRUE(Download("/feed_photo_404.json", base::Time(), &contacts));
- ASSERT_EQ(static_cast<size_t>(1), contacts->size());
- EXPECT_FALSE((*contacts)[0]->has_raw_untrusted_photo());
-
- // We should report failure when we're unable to download the contact group
- // feed.
- service_->clear_cached_my_contacts_group_id_for_testing();
- service_->set_groups_feed_url_for_testing(
- test_server_->GetURL("/404"));
- EXPECT_FALSE(Download("/feed.json", base::Time(), &contacts));
- EXPECT_TRUE(service_->cached_my_contacts_group_id_for_testing().empty());
-
- // We should also fail when the "My Contacts" group isn't listed in the group
- // feed.
- service_->clear_cached_my_contacts_group_id_for_testing();
- service_->set_groups_feed_url_for_testing(
- test_server_->GetURL("/groups_no_my_contacts.json"));
- EXPECT_FALSE(Download("/feed.json", base::Time(), &contacts));
- EXPECT_TRUE(service_->cached_my_contacts_group_id_for_testing().empty());
-}
-
-// Check that we're able to download an empty feed and a normal-looking feed
-// with two regular contacts and one deleted one.
-TEST_F(GDataContactsServiceTest, Download) {
- scoped_ptr<ScopedVector<contacts::Contact> > contacts;
- EXPECT_TRUE(Download("/no_entries.json", base::Time(), &contacts));
- EXPECT_TRUE(contacts->empty());
-
- EXPECT_TRUE(Download("/feed.json", base::Time(), &contacts));
-
- // Check that we got the group ID for the "My Contacts" group that's hardcoded
- // in the groups feed.
- EXPECT_EQ(
- "http://www.google.com/m8/feeds/groups/test.user%40gmail.com/base/6",
- service_->cached_my_contacts_group_id_for_testing());
-
- // All of these expected values are hardcoded in the feed.
- scoped_ptr<contacts::Contact> contact1(new contacts::Contact);
- InitContact("http://example.com/1",
- "2012-06-04T15:53:36.023Z",
- false, "Joe Contact", "Joe", "", "Contact", "", "",
- contact1.get());
- contacts::test::SetPhoto(gfx::Size(kPhotoSize, kPhotoSize), contact1.get());
- contacts::test::AddEmailAddress(
- "joe.contact@gmail.com",
- contacts::Contact_AddressType_Relation_OTHER, "", true, contact1.get());
- contacts::test::AddPostalAddress(
- "345 Spear St\nSan Francisco CA 94105",
- contacts::Contact_AddressType_Relation_HOME, "", false, contact1.get());
-
- scoped_ptr<contacts::Contact> contact2(new contacts::Contact);
- InitContact("http://example.com/2",
- "2012-06-21T16:20:13.208Z",
- false, "Dr. Jane Liz Doe Sr.", "Jane", "Liz", "Doe", "Dr.", "Sr.",
- contact2.get());
- contacts::test::AddEmailAddress(
- "jane.doe@gmail.com",
- contacts::Contact_AddressType_Relation_HOME, "", true, contact2.get());
- contacts::test::AddEmailAddress(
- "me@privacy.net",
- contacts::Contact_AddressType_Relation_WORK, "", false, contact2.get());
- contacts::test::AddEmailAddress(
- "foo@example.org",
- contacts::Contact_AddressType_Relation_OTHER, "Fake", false,
- contact2.get());
- contacts::test::AddPhoneNumber(
- "123-456-7890",
- contacts::Contact_AddressType_Relation_MOBILE, "", false,
- contact2.get());
- contacts::test::AddPhoneNumber(
- "234-567-8901",
- contacts::Contact_AddressType_Relation_OTHER, "grandcentral", false,
- contact2.get());
- contacts::test::AddPostalAddress(
- "100 Elm St\nSan Francisco, CA 94110",
- contacts::Contact_AddressType_Relation_HOME, "", false, contact2.get());
- contacts::test::AddInstantMessagingAddress(
- "foo@example.org",
- contacts::Contact_InstantMessagingAddress_Protocol_GOOGLE_TALK,
- contacts::Contact_AddressType_Relation_OTHER, "", false,
- contact2.get());
- contacts::test::AddInstantMessagingAddress(
- "12345678",
- contacts::Contact_InstantMessagingAddress_Protocol_ICQ,
- contacts::Contact_AddressType_Relation_OTHER, "", false,
- contact2.get());
-
- scoped_ptr<contacts::Contact> contact3(new contacts::Contact);
- InitContact("http://example.com/3",
- "2012-07-23T23:07:06.133Z",
- true, "", "", "", "", "", "",
- contact3.get());
-
- EXPECT_EQ(contacts::test::VarContactsToString(
- 3, contact1.get(), contact2.get(), contact3.get()),
- contacts::test::ContactsToString(*contacts));
-}
-
-// Download a feed containing more photos than we're able to download in
-// parallel to check that we still end up with all the photos.
-TEST_F(GDataContactsServiceTest, ParallelPhotoDownload) {
- // The feed used for this test contains 8 contacts.
- const int kNumContacts = 8;
- service_->set_max_photo_downloads_per_second_for_testing(6);
- scoped_ptr<ScopedVector<contacts::Contact> > contacts;
- EXPECT_TRUE(Download("/feed_multiple_photos.json", base::Time(), &contacts));
- ASSERT_EQ(static_cast<size_t>(kNumContacts), contacts->size());
-
- ScopedVector<contacts::Contact> expected_contacts;
- for (int i = 0; i < kNumContacts; ++i) {
- contacts::Contact* contact = new contacts::Contact;
- InitContact(base::StringPrintf("http://example.com/%d", i + 1),
- "2012-06-04T15:53:36.023Z",
- false, "", "", "", "", "", "", contact);
- contacts::test::SetPhoto(gfx::Size(kPhotoSize, kPhotoSize), contact);
- expected_contacts.push_back(contact);
- }
- EXPECT_EQ(contacts::test::ContactsToString(expected_contacts),
- contacts::test::ContactsToString(*contacts));
-}
-
-TEST_F(GDataContactsServiceTest, UnicodeStrings) {
- scoped_ptr<ScopedVector<contacts::Contact> > contacts;
- EXPECT_TRUE(Download("/feed_unicode.json", base::Time(), &contacts));
-
- // All of these expected values are hardcoded in the feed.
- scoped_ptr<contacts::Contact> contact1(new contacts::Contact);
- InitContact("http://example.com/1", "2012-06-04T15:53:36.023Z",
- false, "\xE5\xAE\x89\xE8\x97\xA4\x20\xE5\xBF\xA0\xE9\x9B\x84",
- "\xE5\xBF\xA0\xE9\x9B\x84", "", "\xE5\xAE\x89\xE8\x97\xA4",
- "", "", contact1.get());
- scoped_ptr<contacts::Contact> contact2(new contacts::Contact);
- InitContact("http://example.com/2", "2012-06-21T16:20:13.208Z",
- false, "Bob Smith", "Bob", "", "Smith", "", "",
- contact2.get());
- EXPECT_EQ(contacts::test::VarContactsToString(
- 2, contact1.get(), contact2.get()),
- contacts::test::ContactsToString(*contacts));
-}
-
-} // namespace contacts
diff --git a/chrome/browser/chromeos/contacts/google_contact_store.cc b/chrome/browser/chromeos/contacts/google_contact_store.cc
deleted file mode 100644
index 52b8ba5..0000000
--- a/chrome/browser/chromeos/contacts/google_contact_store.cc
+++ /dev/null
@@ -1,434 +0,0 @@
-// 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.
-
-#include "chrome/browser/chromeos/contacts/google_contact_store.h"
-
-#include <algorithm>
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/contacts/contact.pb.h"
-#include "chrome/browser/chromeos/contacts/contact_database.h"
-#include "chrome/browser/chromeos/contacts/contact_store_observer.h"
-#include "chrome/browser/chromeos/contacts/gdata_contacts_service.h"
-#include "chrome/browser/chromeos/profiles/profile_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/profile_oauth2_token_service.h"
-#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
-#include "chrome/browser/signin/signin_manager.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
-#include "content/public/browser/browser_thread.h"
-#include "google_apis/drive/auth_service.h"
-#include "google_apis/drive/time_util.h"
-
-using content::BrowserThread;
-
-namespace contacts {
-
-namespace {
-
-// Name of the directory within the profile directory where the contact database
-// is stored.
-const base::FilePath::CharType kDatabaseDirectoryName[] =
- FILE_PATH_LITERAL("Google Contacts");
-
-// We wait this long after the last update has completed successfully before
-// updating again.
-// TODO(derat): Decide what this should be.
-const int kUpdateIntervalSec = 600;
-
-// https://developers.google.com/google-apps/contacts/v3/index says that deleted
-// contact (groups?) will only be returned for 30 days after deletion when the
-// "showdeleted" parameter is set. If it's been longer than that since the last
-// successful update, we do a full refresh to make sure that we haven't missed
-// any deletions. Use 29 instead to make sure that we don't run afoul of
-// daylight saving time shenanigans or minor skew in the system clock.
-const int kForceFullUpdateDays = 29;
-
-// When an update fails, we initially wait this many seconds before retrying.
-// The delay increases exponentially in response to repeated failures.
-const int kUpdateFailureInitialRetrySec = 5;
-
-// Amount by which |update_delay_on_next_failure_| is multiplied on failure.
-const int kUpdateFailureBackoffFactor = 2;
-
-// OAuth2 scope for the Contacts API.
-const char kContactsScope[] = "https://www.google.com/m8/feeds/";
-
-} // namespace
-
-GoogleContactStore::TestAPI::TestAPI(GoogleContactStore* store)
- : store_(store) {
- DCHECK(store);
-}
-
-GoogleContactStore::TestAPI::~TestAPI() {
- store_ = NULL;
-}
-
-void GoogleContactStore::TestAPI::SetDatabase(ContactDatabaseInterface* db) {
- store_->DestroyDatabase();
- store_->db_ = db;
-}
-
-void GoogleContactStore::TestAPI::SetGDataService(
- GDataContactsServiceInterface* service) {
- store_->gdata_service_.reset(service);
-}
-
-void GoogleContactStore::TestAPI::DoUpdate() {
- store_->UpdateContacts();
-}
-
-void GoogleContactStore::TestAPI::NotifyAboutNetworkStateChange(bool online) {
- net::NetworkChangeNotifier::ConnectionType type =
- online ?
- net::NetworkChangeNotifier::CONNECTION_UNKNOWN :
- net::NetworkChangeNotifier::CONNECTION_NONE;
- store_->OnConnectionTypeChanged(type);
-}
-
-scoped_ptr<ContactPointers> GoogleContactStore::TestAPI::GetLoadedContacts() {
- scoped_ptr<ContactPointers> contacts(new ContactPointers);
- for (ContactMap::const_iterator it = store_->contacts_.begin();
- it != store_->contacts_.end(); ++it) {
- contacts->push_back(it->second);
- }
- return contacts.Pass();
-}
-
-GoogleContactStore::GoogleContactStore(
- net::URLRequestContextGetter* url_request_context_getter,
- Profile* profile)
- : url_request_context_getter_(url_request_context_getter),
- profile_(profile),
- db_(new ContactDatabase),
- update_delay_on_next_failure_(
- base::TimeDelta::FromSeconds(kUpdateFailureInitialRetrySec)),
- is_online_(true),
- should_update_when_online_(false),
- weak_ptr_factory_(this) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
- is_online_ = !net::NetworkChangeNotifier::IsOffline();
-}
-
-GoogleContactStore::~GoogleContactStore() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- weak_ptr_factory_.InvalidateWeakPtrs();
- net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
- DestroyDatabase();
-}
-
-void GoogleContactStore::Init() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // Create a GData service if one hasn't already been assigned for testing.
- if (!gdata_service_.get()) {
- std::vector<std::string> scopes;
- scopes.push_back(kContactsScope);
-
- ProfileOAuth2TokenService* oauth2_service =
- ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
- SigninManagerBase* signin_manager =
- SigninManagerFactory::GetForProfile(profile_);
- gdata_service_.reset(new GDataContactsService(
- url_request_context_getter_,
- new google_apis::AuthService(
- oauth2_service,
- signin_manager->GetAuthenticatedAccountId(),
- url_request_context_getter_, scopes)));
- }
-
- base::FilePath db_path = profile_->GetPath().Append(kDatabaseDirectoryName);
- VLOG(1) << "Initializing contact database \"" << db_path.value() << "\" for "
- << profile_->GetProfileName();
- db_->Init(db_path,
- base::Bind(&GoogleContactStore::OnDatabaseInitialized,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
-void GoogleContactStore::AppendContacts(ContactPointers* contacts_out) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(contacts_out);
- for (ContactMap::const_iterator it = contacts_.begin();
- it != contacts_.end(); ++it) {
- if (!it->second->deleted())
- contacts_out->push_back(it->second);
- }
-}
-
-const Contact* GoogleContactStore::GetContactById(
- const std::string& contact_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- return contacts_.Find(contact_id);
-}
-
-void GoogleContactStore::AddObserver(ContactStoreObserver* observer) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(observer);
- observers_.AddObserver(observer);
-}
-
-void GoogleContactStore::RemoveObserver(ContactStoreObserver* observer) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(observer);
- observers_.RemoveObserver(observer);
-}
-
-void GoogleContactStore::OnConnectionTypeChanged(
- net::NetworkChangeNotifier::ConnectionType type) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- bool was_online = is_online_;
- is_online_ = (type != net::NetworkChangeNotifier::CONNECTION_NONE);
- if (!was_online && is_online_ && should_update_when_online_) {
- should_update_when_online_ = false;
- UpdateContacts();
- }
-}
-
-base::Time GoogleContactStore::GetCurrentTime() const {
- return !current_time_for_testing_.is_null() ?
- current_time_for_testing_ :
- base::Time::Now();
-}
-
-void GoogleContactStore::DestroyDatabase() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (db_) {
- db_->DestroyOnUIThread();
- db_ = NULL;
- }
-}
-
-void GoogleContactStore::UpdateContacts() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // If we're offline, defer the update.
- if (!is_online_) {
- VLOG(1) << "Deferring contact update due to offline state";
- should_update_when_online_ = true;
- return;
- }
-
- base::Time min_update_time;
- base::TimeDelta time_since_last_update =
- last_successful_update_start_time_.is_null() ?
- base::TimeDelta() :
- GetCurrentTime() - last_successful_update_start_time_;
-
- if (!last_contact_update_time_.is_null() &&
- time_since_last_update <
- base::TimeDelta::FromDays(kForceFullUpdateDays)) {
- // TODO(derat): I'm adding one millisecond to the last update time here as I
- // don't want to re-download the same most-recently-updated contact each
- // time, but what happens if within the same millisecond, contact A is
- // updated, we do a sync, and then contact B is updated? I'm probably being
- // overly paranoid about this.
- min_update_time =
- last_contact_update_time_ + base::TimeDelta::FromMilliseconds(1);
- }
- if (min_update_time.is_null()) {
- VLOG(1) << "Downloading all contacts for " << profile_->GetProfileName();
- } else {
- VLOG(1) << "Downloading contacts updated since "
- << google_apis::util::FormatTimeAsString(min_update_time) << " for "
- << profile_->GetProfileName();
- }
-
- gdata_service_->DownloadContacts(
- base::Bind(&GoogleContactStore::OnDownloadSuccess,
- weak_ptr_factory_.GetWeakPtr(),
- min_update_time.is_null(),
- GetCurrentTime()),
- base::Bind(&GoogleContactStore::OnDownloadFailure,
- weak_ptr_factory_.GetWeakPtr()),
- min_update_time);
-}
-
-void GoogleContactStore::ScheduleUpdate(bool last_update_was_successful) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- base::TimeDelta delay;
- if (last_update_was_successful) {
- delay = base::TimeDelta::FromSeconds(kUpdateIntervalSec);
- update_delay_on_next_failure_ =
- base::TimeDelta::FromSeconds(kUpdateFailureInitialRetrySec);
- } else {
- delay = update_delay_on_next_failure_;
- update_delay_on_next_failure_ = std::min(
- update_delay_on_next_failure_ * kUpdateFailureBackoffFactor,
- base::TimeDelta::FromSeconds(kUpdateIntervalSec));
- }
- VLOG(1) << "Scheduling update of " << profile_->GetProfileName()
- << " in " << delay.InSeconds() << " second(s)";
- update_timer_.Start(
- FROM_HERE, delay, this, &GoogleContactStore::UpdateContacts);
-}
-
-void GoogleContactStore::MergeContacts(
- bool is_full_update,
- scoped_ptr<ScopedVector<Contact> > updated_contacts) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- if (is_full_update) {
- contacts_.Clear();
- last_contact_update_time_ = base::Time();
- }
-
- // Find the maximum update time from |updated_contacts| since contacts whose
- // |deleted| flags are set won't be saved to |contacts_|.
- for (ScopedVector<Contact>::iterator it = updated_contacts->begin();
- it != updated_contacts->end(); ++it) {
- last_contact_update_time_ =
- std::max(last_contact_update_time_,
- base::Time::FromInternalValue((*it)->update_time()));
- }
- VLOG(1) << "Last contact update time is "
- << google_apis::util::FormatTimeAsString(last_contact_update_time_);
-
- contacts_.Merge(updated_contacts.Pass(), ContactMap::DROP_DELETED_CONTACTS);
-}
-
-void GoogleContactStore::OnDownloadSuccess(
- bool is_full_update,
- const base::Time& update_start_time,
- scoped_ptr<ScopedVector<Contact> > updated_contacts) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- VLOG(1) << "Got " << updated_contacts->size() << " contact(s) for "
- << profile_->GetProfileName();
-
- // Copy the pointers so we can update just these contacts in the database.
- scoped_ptr<ContactPointers> contacts_to_save_to_db(new ContactPointers);
- scoped_ptr<ContactDatabaseInterface::ContactIds>
- contact_ids_to_delete_from_db(new ContactDatabaseInterface::ContactIds);
- if (db_) {
- for (size_t i = 0; i < updated_contacts->size(); ++i) {
- Contact* contact = (*updated_contacts)[i];
- if (contact->deleted())
- contact_ids_to_delete_from_db->push_back(contact->contact_id());
- else
- contacts_to_save_to_db->push_back(contact);
- }
- }
- bool got_updates = !updated_contacts->empty();
-
- MergeContacts(is_full_update, updated_contacts.Pass());
- last_successful_update_start_time_ = update_start_time;
-
- if (is_full_update || got_updates) {
- FOR_EACH_OBSERVER(ContactStoreObserver,
- observers_,
- OnContactsUpdated(this));
- }
-
- if (db_) {
- // Even if this was an incremental update and we didn't get any updated
- // contacts, we still want to write updated metadata containing
- // |update_start_time|.
- VLOG(1) << "Saving " << contacts_to_save_to_db->size() << " contact(s) to "
- << "database and deleting " << contact_ids_to_delete_from_db->size()
- << " as " << (is_full_update ? "full" : "incremental") << " update";
-
- scoped_ptr<UpdateMetadata> metadata(new UpdateMetadata);
- metadata->set_last_update_start_time(update_start_time.ToInternalValue());
- metadata->set_last_contact_update_time(
- last_contact_update_time_.ToInternalValue());
-
- db_->SaveContacts(
- contacts_to_save_to_db.Pass(),
- contact_ids_to_delete_from_db.Pass(),
- metadata.Pass(),
- is_full_update,
- base::Bind(&GoogleContactStore::OnDatabaseContactsSaved,
- weak_ptr_factory_.GetWeakPtr()));
-
- // We'll schedule an update from OnDatabaseContactsSaved() after we're done
- // writing to the database -- we don't want to modify the contacts while
- // they're being used by the database.
- } else {
- ScheduleUpdate(true);
- }
-}
-
-void GoogleContactStore::OnDownloadFailure() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- LOG(WARNING) << "Contacts download failed for " << profile_->GetProfileName();
- ScheduleUpdate(false);
-}
-
-void GoogleContactStore::OnDatabaseInitialized(bool success) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (success) {
- VLOG(1) << "Contact database initialized for "
- << profile_->GetProfileName();
- db_->LoadContacts(base::Bind(&GoogleContactStore::OnDatabaseContactsLoaded,
- weak_ptr_factory_.GetWeakPtr()));
- } else {
- LOG(WARNING) << "Failed to initialize contact database for "
- << profile_->GetProfileName();
- // Limp along as best as we can: throw away the database and do an update,
- // which will schedule further updates.
- DestroyDatabase();
- UpdateContacts();
- }
-}
-
-void GoogleContactStore::OnDatabaseContactsLoaded(
- bool success,
- scoped_ptr<ScopedVector<Contact> > contacts,
- scoped_ptr<UpdateMetadata> metadata) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (success) {
- VLOG(1) << "Loaded " << contacts->size() << " contact(s) from database";
- MergeContacts(true, contacts.Pass());
- last_successful_update_start_time_ =
- base::Time::FromInternalValue(metadata->last_update_start_time());
- last_contact_update_time_ = std::max(
- last_contact_update_time_,
- base::Time::FromInternalValue(metadata->last_contact_update_time()));
-
- if (!contacts_.empty()) {
- FOR_EACH_OBSERVER(ContactStoreObserver,
- observers_,
- OnContactsUpdated(this));
- }
- } else {
- LOG(WARNING) << "Failed to load contacts from database";
- }
- UpdateContacts();
-}
-
-void GoogleContactStore::OnDatabaseContactsSaved(bool success) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (!success)
- LOG(WARNING) << "Failed to save contacts to database";
-
- // We only update the database when we've successfully downloaded contacts, so
- // report success to ScheduleUpdate() even if the database update failed.
- ScheduleUpdate(true);
-}
-
-GoogleContactStoreFactory::GoogleContactStoreFactory() {
-}
-
-GoogleContactStoreFactory::~GoogleContactStoreFactory() {
-}
-
-bool GoogleContactStoreFactory::CanCreateContactStoreForProfile(
- Profile* profile) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(profile);
- return chromeos::IsProfileAssociatedWithGaiaAccount(profile);
-}
-
-ContactStore* GoogleContactStoreFactory::CreateContactStore(Profile* profile) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(CanCreateContactStoreForProfile(profile));
- return new GoogleContactStore(
- g_browser_process->system_request_context(), profile);
-}
-
-} // namespace contacts
diff --git a/chrome/browser/chromeos/contacts/google_contact_store.h b/chrome/browser/chromeos/contacts/google_contact_store.h
deleted file mode 100644
index 8773722..0000000
--- a/chrome/browser/chromeos/contacts/google_contact_store.h
+++ /dev/null
@@ -1,203 +0,0 @@
-// 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_CONTACTS_GOOGLE_CONTACT_STORE_H_
-#define CHROME_BROWSER_CHROMEOS_CONTACTS_GOOGLE_CONTACT_STORE_H_
-
-#include "chrome/browser/chromeos/contacts/contact_store.h"
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-#include "chrome/browser/chromeos/contacts/contact_map.h"
-#include "net/base/network_change_notifier.h"
-
-class Profile;
-
-namespace net {
-class URLRequestContextGetter;
-} // namespace net
-
-namespace contacts {
-
-class Contact;
-class ContactDatabaseInterface;
-class GDataContactsServiceInterface;
-class UpdateMetadata;
-
-// A collection of contacts from a Google account.
-class GoogleContactStore
- : public ContactStore,
- public net::NetworkChangeNotifier::ConnectionTypeObserver {
- public:
- class TestAPI {
- public:
- explicit TestAPI(GoogleContactStore* store);
- ~TestAPI();
-
- bool update_scheduled() { return store_->update_timer_.IsRunning(); }
- base::Time last_contact_update_time() const {
- return store_->last_contact_update_time_;
- }
- void set_current_time(const base::Time& time) {
- store_->current_time_for_testing_ = time;
- }
-
- // Takes ownership of |db|. Must be called before Init().
- void SetDatabase(ContactDatabaseInterface* db);
-
- // Takes ownership of |service|. Must be called before Init(). The caller is
- // responsible for calling |service|'s Initialize() method.
- void SetGDataService(GDataContactsServiceInterface* service);
-
- // Triggers an update, similar to what happens when the update timer fires.
- void DoUpdate();
-
- // Notifies the store that the system has gone online or offline.
- void NotifyAboutNetworkStateChange(bool online);
-
- // Returns pointers to all of the contacts in the store's |contacts_|
- // member.
- scoped_ptr<ContactPointers> GetLoadedContacts();
-
- private:
- GoogleContactStore* store_; // not owned
-
- DISALLOW_COPY_AND_ASSIGN(TestAPI);
- };
-
- GoogleContactStore(
- net::URLRequestContextGetter* url_request_context_getter,
- Profile* profile);
- virtual ~GoogleContactStore();
-
- // ContactStore implementation:
- virtual void Init() OVERRIDE;
- virtual void AppendContacts(ContactPointers* contacts_out) OVERRIDE;
- virtual const Contact* GetContactById(const std::string& contact_id) OVERRIDE;
- virtual void AddObserver(ContactStoreObserver* observer) OVERRIDE;
- virtual void RemoveObserver(ContactStoreObserver* observer) OVERRIDE;
-
- // net::NetworkChangeNotifier::ConnectionTypeObserver implementation:
- virtual void OnConnectionTypeChanged(
- net::NetworkChangeNotifier::ConnectionType type) OVERRIDE;
-
- private:
- // Returns the current time. Uses |current_time_for_testing_| instead if it's
- // set.
- base::Time GetCurrentTime() const;
-
- // Destroys |db_| if non-NULL and resets the pointer.
- // The underlying data is preserved on-disk.
- void DestroyDatabase();
-
- // Asynchronously downloads updated contacts and merges them into |contacts_|.
- void UpdateContacts();
-
- // Starts |update_timer_| so UpdateContacts() will be run.
- void ScheduleUpdate(bool last_update_was_successful);
-
- // Moves |updated_contacts| into |contacts_| and updates
- // |last_contact_update_time_|.
- void MergeContacts(bool is_full_update,
- scoped_ptr<ScopedVector<Contact> > updated_contacts);
-
- // Handles a successful download, merging |updated_contacts| and saving the
- // updated contacts to |db_|.
- void OnDownloadSuccess(bool is_full_update,
- const base::Time& update_start_time,
- scoped_ptr<ScopedVector<Contact> > updated_contacts);
-
- // Handles a failed update. A new update is scheduled.
- void OnDownloadFailure();
-
- // Handles |db_|'s initialization. On success, we start loading the contacts
- // from the database; otherwise, we throw out the database and schedule an
- // update.
- void OnDatabaseInitialized(bool success);
-
- // Handles contacts being loaded from |db_|. On success, we merge the loaded
- // contacts. No matter what, we call UpdateContacts().
- void OnDatabaseContactsLoaded(bool success,
- scoped_ptr<ScopedVector<Contact> > contacts,
- scoped_ptr<UpdateMetadata> metadata);
-
- // Handles contacts being saved to |db_|. Now that the contacts are no longer
- // being accessed by the database, we schedule an update.
- void OnDatabaseContactsSaved(bool success);
-
- net::URLRequestContextGetter* url_request_context_getter_; // not owned
-
- Profile* profile_; // not owned
-
- ObserverList<ContactStoreObserver> observers_;
-
- // Owns the pointed-to Contact values.
- ContactMap contacts_;
-
- // Most-recent time that an entry in |contacts_| has been updated (as reported
- // by Google).
- base::Time last_contact_update_time_;
-
- // Used to download contacts.
- scoped_ptr<GDataContactsServiceInterface> gdata_service_;
-
- // Used to save contacts to disk and load them at startup. Owns the object.
- ContactDatabaseInterface* db_;
-
- // Used to schedule calls to UpdateContacts().
- base::OneShotTimer<GoogleContactStore> update_timer_;
-
- // Time at which the last successful update was started.
- base::Time last_successful_update_start_time_;
-
- // Amount of time that we'll wait before retrying the next time that an update
- // fails.
- base::TimeDelta update_delay_on_next_failure_;
-
- // Do we believe that it's likely that we'll be able to make network
- // connections?
- bool is_online_;
-
- // Should we call UpdateContacts() when |is_online_| becomes true? Set when
- // UpdateContacts() is called while we're offline.
- bool should_update_when_online_;
-
- // If non-null, used in place of base::Time::Now() when the current time is
- // needed.
- base::Time current_time_for_testing_;
-
- // Note: This should remain the last member so it'll be destroyed and
- // invalidate its weak pointers before any other members are destroyed.
- base::WeakPtrFactory<GoogleContactStore> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(GoogleContactStore);
-};
-
-// ContactStoreFactory implementation that returns GoogleContactStores.
-class GoogleContactStoreFactory : public ContactStoreFactory {
- public:
- GoogleContactStoreFactory();
- virtual ~GoogleContactStoreFactory();
-
- // ContactStoreFactory implementation:
- virtual bool CanCreateContactStoreForProfile(Profile* profile) OVERRIDE;
- virtual ContactStore* CreateContactStore(Profile* profile) OVERRIDE;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(GoogleContactStoreFactory);
-};
-
-} // namespace contacts
-
-#endif // CHROME_BROWSER_CHROMEOS_CONTACTS_GOOGLE_CONTACT_STORE_H_
diff --git a/chrome/browser/chromeos/contacts/google_contact_store_unittest.cc b/chrome/browser/chromeos/contacts/google_contact_store_unittest.cc
deleted file mode 100644
index e376fda..0000000
--- a/chrome/browser/chromeos/contacts/google_contact_store_unittest.cc
+++ /dev/null
@@ -1,540 +0,0 @@
-// 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.
-
-#include "chrome/browser/chromeos/contacts/google_contact_store.h"
-
-#include "base/bind.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/time/time.h"
-#include "chrome/browser/chromeos/contacts/contact.pb.h"
-#include "chrome/browser/chromeos/contacts/contact_store_observer.h"
-#include "chrome/browser/chromeos/contacts/contact_test_util.h"
-#include "chrome/browser/chromeos/contacts/fake_contact_database.h"
-#include "chrome/browser/chromeos/contacts/gdata_contacts_service_stub.h"
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/test/test_browser_thread.h"
-#include "google_apis/drive/time_util.h"
-#include "net/base/network_change_notifier.h"
-#include "net/url_request/url_request_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using content::BrowserThread;
-
-namespace contacts {
-namespace test {
-
-// ContactStoreObserver implementation that just counts the number of times
-// that it's been told that a store has been updated.
-class TestContactStoreObserver : public ContactStoreObserver {
- public:
- TestContactStoreObserver() : num_updates_(0) {}
- virtual ~TestContactStoreObserver() {}
-
- int num_updates() const { return num_updates_; }
- void reset_stats() { num_updates_ = 0; }
-
- // ContactStoreObserver overrides:
- virtual void OnContactsUpdated(ContactStore* store) OVERRIDE {
- DCHECK(store);
- num_updates_++;
- }
-
- private:
- // Number of times that OnContactsUpdated() has been called.
- int num_updates_;
-
- DISALLOW_COPY_AND_ASSIGN(TestContactStoreObserver);
-};
-
-class GoogleContactStoreTest : public testing::Test {
- public:
- GoogleContactStoreTest() : ui_thread_(BrowserThread::UI, &message_loop_) {}
- virtual ~GoogleContactStoreTest() {}
-
- protected:
- // testing::Test implementation.
- virtual void SetUp() OVERRIDE {
- // Create a mock NetworkChangeNotifier so the store won't be notified about
- // changes to the system's actual network state.
- network_change_notifier_.reset(net::NetworkChangeNotifier::CreateMock());
-
- profile_.reset(new TestingProfile);
-
- store_.reset(new GoogleContactStore(NULL, // request_context_getter
- profile_.get()));
- store_->AddObserver(&observer_);
-
- test_api_.reset(new GoogleContactStore::TestAPI(store_.get()));
-
- db_ = new FakeContactDatabase;
- test_api_->SetDatabase(db_);
-
- gdata_service_ = new GDataContactsServiceStub;
- test_api_->SetGDataService(gdata_service_);
- }
-
- base::MessageLoopForUI message_loop_;
- content::TestBrowserThread ui_thread_;
-
- TestContactStoreObserver observer_;
- scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_;
- scoped_ptr<TestingProfile> profile_;
- scoped_ptr<GoogleContactStore> store_;
- scoped_ptr<GoogleContactStore::TestAPI> test_api_;
-
- FakeContactDatabase* db_; // not owned
- GDataContactsServiceStub* gdata_service_; // not owned
-
- private:
- DISALLOW_COPY_AND_ASSIGN(GoogleContactStoreTest);
-};
-
-TEST_F(GoogleContactStoreTest, LoadFromDatabase) {
- // Store two contacts in the database.
- const std::string kContactId1 = "contact1";
- const std::string kContactId2 = "contact2";
- scoped_ptr<Contact> contact1(new Contact);
- InitContact(kContactId1, "1", false, contact1.get());
- scoped_ptr<Contact> contact2(new Contact);
- InitContact(kContactId2, "2", false, contact2.get());
- ContactPointers db_contacts;
- db_contacts.push_back(contact1.get());
- db_contacts.push_back(contact2.get());
- UpdateMetadata db_metadata;
- db_->SetContacts(db_contacts, db_metadata);
-
- // Tell the GData service to report failure, initialize the store, and check
- // that the contacts from the database are loaded.
- gdata_service_->set_download_should_succeed(false);
- store_->Init();
- ContactPointers loaded_contacts;
- store_->AppendContacts(&loaded_contacts);
- EXPECT_EQ(VarContactsToString(2, contact1.get(), contact2.get()),
- ContactsToString(loaded_contacts));
- EXPECT_TRUE(test_api_->update_scheduled());
- EXPECT_EQ(1, observer_.num_updates());
-
- // Check that we can also grab the contact via its ID.
- const Contact* loaded_contact1 = store_->GetContactById(kContactId1);
- ASSERT_TRUE(loaded_contact1);
- EXPECT_EQ(ContactToString(*contact1), ContactToString(*loaded_contact1));
-
- // We should get NULL if we request a nonexistent contact.
- EXPECT_FALSE(store_->GetContactById("bogus_id"));
-}
-
-TEST_F(GoogleContactStoreTest, LoadFromGData) {
- // Store two contacts in the GData service.
- scoped_ptr<Contact> contact1(new Contact);
- InitContact("contact1", "1", false, contact1.get());
- scoped_ptr<Contact> contact2(new Contact);
- InitContact("contact2", "2", false, contact2.get());
- ContactPointers gdata_contacts;
- gdata_contacts.push_back(contact1.get());
- gdata_contacts.push_back(contact2.get());
- gdata_service_->SetContacts(gdata_contacts, base::Time());
-
- // Initialize the store and check that the contacts are loaded from GData.
- store_->Init();
- ContactPointers loaded_contacts;
- store_->AppendContacts(&loaded_contacts);
- EXPECT_EQ(VarContactsToString(2, contact1.get(), contact2.get()),
- ContactsToString(loaded_contacts));
- EXPECT_TRUE(test_api_->update_scheduled());
- EXPECT_EQ(1, observer_.num_updates());
-
- // The contacts should've been saved to the database, too.
- EXPECT_EQ(VarContactsToString(2, contact1.get(), contact2.get()),
- ContactMapToString(db_->contacts()));
-}
-
-TEST_F(GoogleContactStoreTest, UpdateFromGData) {
- scoped_ptr<Contact> contact1(new Contact);
- InitContact("contact1", "1", false, contact1.get());
- scoped_ptr<Contact> contact2(new Contact);
- InitContact("contact2", "2", false, contact2.get());
- scoped_ptr<Contact> contact3(new Contact);
- InitContact("contact3", "3", false, contact3.get());
-
- // Store the first two contacts in the database.
- ContactPointers db_contacts;
- db_contacts.push_back(contact1.get());
- db_contacts.push_back(contact2.get());
- UpdateMetadata db_metadata;
- db_->SetContacts(db_contacts, db_metadata);
-
- // Store all three in the GData service. We expect the update request to ask
- // for all contacts updated one millisecond after the newest contact in the
- // database.
- ContactPointers gdata_contacts;
- gdata_contacts.push_back(contact1.get());
- gdata_contacts.push_back(contact2.get());
- gdata_contacts.push_back(contact3.get());
- gdata_service_->SetContacts(
- gdata_contacts,
- base::Time::FromInternalValue(contact2->update_time()) +
- base::TimeDelta::FromMilliseconds(1));
-
- // Check that the store ends up with all three contacts.
- store_->Init();
- ContactPointers loaded_contacts;
- store_->AppendContacts(&loaded_contacts);
- EXPECT_EQ(VarContactsToString(
- 3, contact1.get(), contact2.get(), contact3.get()),
- ContactsToString(loaded_contacts));
- EXPECT_EQ(2, observer_.num_updates());
-
- // All three contacts should've been saved to the database.
- EXPECT_EQ(VarContactsToString(
- 3, contact1.get(), contact2.get(), contact3.get()),
- ContactMapToString(db_->contacts()));
- EXPECT_EQ(3, db_->num_saved_contacts());
- EXPECT_TRUE(test_api_->update_scheduled());
-}
-
-TEST_F(GoogleContactStoreTest, FetchUpdatedContacts) {
- scoped_ptr<Contact> contact1(new Contact);
- InitContact("contact1", "1", false, contact1.get());
- scoped_ptr<Contact> contact2(new Contact);
- InitContact("contact2", "2", false, contact2.get());
- scoped_ptr<Contact> contact3(new Contact);
- InitContact("contact3", "3", false, contact3.get());
-
- ContactPointers kAllContacts;
- kAllContacts.push_back(contact1.get());
- kAllContacts.push_back(contact2.get());
- kAllContacts.push_back(contact3.get());
-
- // Tell the GData service to return all three contacts in response to a full
- // update.
- ContactPointers gdata_contacts(kAllContacts);
- gdata_service_->SetContacts(gdata_contacts, base::Time());
-
- // All the contacts should be loaded and saved to the database.
- store_->Init();
- ContactPointers loaded_contacts;
- store_->AppendContacts(&loaded_contacts);
- EXPECT_EQ(ContactsToString(kAllContacts), ContactsToString(loaded_contacts));
- EXPECT_EQ(ContactsToString(kAllContacts),
- ContactMapToString(db_->contacts()));
- EXPECT_EQ(static_cast<int>(kAllContacts.size()), db_->num_saved_contacts());
- EXPECT_TRUE(test_api_->update_scheduled());
- EXPECT_EQ(1, observer_.num_updates());
- observer_.reset_stats();
-
- // Update the third contact.
- contact3->set_full_name("new full name");
- base::Time old_contact3_update_time =
- base::Time::FromInternalValue(contact3->update_time());
- contact3->set_update_time(
- (old_contact3_update_time +
- base::TimeDelta::FromSeconds(10)).ToInternalValue());
- gdata_contacts.clear();
- gdata_contacts.push_back(contact3.get());
- gdata_service_->SetContacts(
- gdata_contacts,
- old_contact3_update_time + base::TimeDelta::FromMilliseconds(1));
-
- // Check that the updated contact is loaded (i.e. the store passed the
- // correct minimum update time to the service) and saved back to the database.
- db_->reset_stats();
- test_api_->DoUpdate();
- loaded_contacts.clear();
- store_->AppendContacts(&loaded_contacts);
- EXPECT_EQ(ContactsToString(kAllContacts), ContactsToString(loaded_contacts));
- EXPECT_EQ(ContactsToString(kAllContacts),
- ContactMapToString(db_->contacts()));
- EXPECT_EQ(1, db_->num_saved_contacts());
- EXPECT_TRUE(test_api_->update_scheduled());
- EXPECT_EQ(1, observer_.num_updates());
- observer_.reset_stats();
-
- // The next update should be based on the third contact's new update time.
- contact3->set_full_name("yet another full name");
- gdata_service_->SetContacts(
- gdata_contacts,
- base::Time::FromInternalValue(contact3->update_time()) +
- base::TimeDelta::FromMilliseconds(1));
-
- db_->reset_stats();
- test_api_->DoUpdate();
- loaded_contacts.clear();
- store_->AppendContacts(&loaded_contacts);
- EXPECT_EQ(ContactsToString(kAllContacts), ContactsToString(loaded_contacts));
- EXPECT_EQ(ContactsToString(kAllContacts),
- ContactMapToString(db_->contacts()));
- EXPECT_EQ(1, db_->num_saved_contacts());
- EXPECT_TRUE(test_api_->update_scheduled());
- EXPECT_EQ(1, observer_.num_updates());
-}
-
-TEST_F(GoogleContactStoreTest, DontReturnDeletedContacts) {
- // Tell GData to return a single deleted contact.
- const std::string kContactId = "contact";
- scoped_ptr<Contact> contact(new Contact);
- InitContact(kContactId, "1", true, contact.get());
- ContactPointers gdata_contacts;
- gdata_contacts.push_back(contact.get());
- gdata_service_->SetContacts(gdata_contacts, base::Time());
-
- // The contact shouldn't be returned by AppendContacts() or
- // GetContactById().
- store_->Init();
- ContactPointers loaded_contacts;
- store_->AppendContacts(&loaded_contacts);
- EXPECT_TRUE(loaded_contacts.empty());
- EXPECT_FALSE(store_->GetContactById(kContactId));
-}
-
-// Test that we do a full refresh from GData if enough time has passed since the
-// last refresh that we might've missed some contact deletions (see
-// |kForceFullUpdateDays| in google_contact_store.cc).
-TEST_F(GoogleContactStoreTest, FullRefreshAfterThirtyDays) {
- base::Time::Exploded kInitTimeExploded = { 2012, 3, 0, 1, 16, 34, 56, 123 };
- base::Time kInitTime = base::Time::FromUTCExploded(kInitTimeExploded);
-
- base::Time kOldUpdateTime = kInitTime - base::TimeDelta::FromDays(31);
- scoped_ptr<Contact> contact1(new Contact);
- InitContact("contact1", "1", false, contact1.get());
- contact1->set_update_time(kOldUpdateTime.ToInternalValue());
- scoped_ptr<Contact> contact2(new Contact);
- InitContact("contact2", "2", false, contact2.get());
- contact2->set_update_time(kOldUpdateTime.ToInternalValue());
-
- // Put both contacts in the database, along with metadata saying that the last
- // successful update was 31 days in the past.
- ContactPointers db_contacts;
- db_contacts.push_back(contact1.get());
- db_contacts.push_back(contact2.get());
- UpdateMetadata db_metadata;
- db_metadata.set_last_update_start_time(kOldUpdateTime.ToInternalValue());
- db_->SetContacts(db_contacts, db_metadata);
-
- // Tell the GData service to return only the first contact and to expect a
- // full refresh (since it's been a long time since the last update).
- ContactPointers gdata_contacts;
- gdata_contacts.push_back(contact1.get());
- gdata_service_->SetContacts(gdata_contacts, base::Time());
-
- test_api_->set_current_time(kInitTime);
- store_->Init();
- ContactPointers loaded_contacts;
- store_->AppendContacts(&loaded_contacts);
- EXPECT_EQ(ContactsToString(gdata_contacts),
- ContactsToString(loaded_contacts));
- EXPECT_TRUE(test_api_->update_scheduled());
-
- // Make GData return both contacts now in response to an incremental update.
- gdata_contacts.clear();
- contact2->set_update_time(kInitTime.ToInternalValue());
- gdata_contacts.push_back(contact1.get());
- gdata_contacts.push_back(contact2.get());
- gdata_service_->SetContacts(
- gdata_contacts, kOldUpdateTime + base::TimeDelta::FromMilliseconds(1));
-
- // Advance the time by twenty days and check that the update is successful.
- base::Time kFirstUpdateTime = kInitTime + base::TimeDelta::FromDays(20);
- test_api_->set_current_time(kFirstUpdateTime);
- test_api_->DoUpdate();
- loaded_contacts.clear();
- store_->AppendContacts(&loaded_contacts);
- EXPECT_EQ(ContactsToString(gdata_contacts),
- ContactsToString(loaded_contacts));
-
- // After we advance the time by 31 days, we should do a full refresh again.
- gdata_contacts.clear();
- gdata_contacts.push_back(contact1.get());
- gdata_service_->SetContacts(gdata_contacts, base::Time());
- base::Time kSecondUpdateTime =
- kFirstUpdateTime + base::TimeDelta::FromDays(31);
- test_api_->set_current_time(kSecondUpdateTime);
- test_api_->DoUpdate();
- loaded_contacts.clear();
- store_->AppendContacts(&loaded_contacts);
- EXPECT_EQ(ContactsToString(gdata_contacts),
- ContactsToString(loaded_contacts));
-}
-
-TEST_F(GoogleContactStoreTest, HandleDatabaseInitFailure) {
- scoped_ptr<Contact> contact1(new Contact);
- InitContact("contact1", "1", false, contact1.get());
-
- // Store a contact in the database but make initialization fail.
- ContactPointers db_contacts;
- db_contacts.push_back(contact1.get());
- UpdateMetadata db_metadata;
- db_->SetContacts(db_contacts, db_metadata);
- db_->set_init_success(false);
-
- // Create a second contact and tell the GData service to return it.
- scoped_ptr<Contact> contact2(new Contact);
- InitContact("contact2", "2", false, contact2.get());
- ContactPointers gdata_contacts;
- gdata_contacts.push_back(contact2.get());
- gdata_service_->SetContacts(gdata_contacts, base::Time());
-
- // Initialize the store. We shouldn't get the first contact (since DB
- // initialization failed) but we should still fetch the second one from GData
- // and schedule an update.
- store_->Init();
- ContactPointers loaded_contacts;
- store_->AppendContacts(&loaded_contacts);
- EXPECT_EQ(ContactsToString(gdata_contacts),
- ContactsToString(loaded_contacts));
- EXPECT_TRUE(test_api_->update_scheduled());
-}
-
-TEST_F(GoogleContactStoreTest, AvoidUpdatesWhenOffline) {
- EXPECT_EQ(0, gdata_service_->num_download_requests());
-
- // Notify the store that we're offline. Init() shouldn't attempt an update
- // and the update timer shouldn't be running.
- test_api_->NotifyAboutNetworkStateChange(false);
- store_->Init();
- EXPECT_EQ(0, gdata_service_->num_download_requests());
- EXPECT_FALSE(test_api_->update_scheduled());
-
- // We should do an update and schedule further updates as soon as we go
- // online.
- gdata_service_->reset_stats();
- test_api_->NotifyAboutNetworkStateChange(true);
- EXPECT_EQ(1, gdata_service_->num_download_requests());
- EXPECT_TRUE(test_api_->update_scheduled());
-
- // If we call DoUpdate() to mimic the code path that's used for a timer-driven
- // update while we're offline, we should again defer the update.
- gdata_service_->reset_stats();
- test_api_->NotifyAboutNetworkStateChange(false);
- test_api_->DoUpdate();
- EXPECT_EQ(0, gdata_service_->num_download_requests());
-
- // When we're back online, the update should happen.
- gdata_service_->reset_stats();
- test_api_->NotifyAboutNetworkStateChange(true);
- EXPECT_EQ(1, gdata_service_->num_download_requests());
-}
-
-TEST_F(GoogleContactStoreTest, DropDeletedContacts) {
- // Tell the GData service to return a single contact.
- scoped_ptr<Contact> contact1(new Contact);
- InitContact("contact1", "1", false, contact1.get());
- ContactPointers gdata_contacts;
- gdata_contacts.push_back(contact1.get());
- gdata_service_->SetContacts(gdata_contacts, base::Time());
-
- // Check that the contact store loads it into memory and saves it to the
- // database.
- store_->Init();
- EXPECT_EQ(0, gdata_service_->num_download_requests_with_wrong_timestamps());
- EXPECT_EQ(base::Time::FromInternalValue(contact1->update_time()),
- test_api_->last_contact_update_time());
- EXPECT_EQ(VarContactsToString(1, contact1.get()),
- ContactsToString(*test_api_->GetLoadedContacts()));
- EXPECT_EQ(VarContactsToString(1, contact1.get()),
- ContactMapToString(db_->contacts()));
- EXPECT_EQ(contact1->update_time(),
- db_->metadata().last_contact_update_time());
- EXPECT_TRUE(test_api_->update_scheduled());
-
- // Now tell the GData service to return a more-newly-updated, already deleted
- // contact.
- scoped_ptr<Contact> contact2(new Contact);
- InitContact("contact2", "2", true, contact2.get());
- contact2->set_update_time(
- (base::Time::FromInternalValue(contact1->update_time()) +
- base::TimeDelta::FromSeconds(5)).ToInternalValue());
- gdata_contacts.clear();
- gdata_contacts.push_back(contact2.get());
- gdata_service_->SetContacts(
- gdata_contacts,
- base::Time::FromInternalValue(contact1->update_time()) +
- base::TimeDelta::FromMilliseconds(1));
-
- // The contact store should save the last update time from the deleted
- // contact, but the contact itself shouldn't be loaded into memory or written
- // to the database.
- test_api_->DoUpdate();
- EXPECT_EQ(0, gdata_service_->num_download_requests_with_wrong_timestamps());
- EXPECT_EQ(base::Time::FromInternalValue(contact2->update_time()),
- test_api_->last_contact_update_time());
- EXPECT_EQ(VarContactsToString(1, contact1.get()),
- ContactsToString(*test_api_->GetLoadedContacts()));
- EXPECT_EQ(VarContactsToString(1, contact1.get()),
- ContactMapToString(db_->contacts()));
- EXPECT_EQ(contact2->update_time(),
- db_->metadata().last_contact_update_time());
-
- // Tell the GData service to report the first contact as having been deleted.
- contact1->set_update_time(
- (base::Time::FromInternalValue(contact2->update_time()) +
- base::TimeDelta::FromSeconds(10)).ToInternalValue());
- contact1->set_deleted(true);
- gdata_contacts.clear();
- gdata_contacts.push_back(contact1.get());
- gdata_service_->SetContacts(
- gdata_contacts,
- base::Time::FromInternalValue(contact2->update_time()) +
- base::TimeDelta::FromMilliseconds(1));
-
- // The contact store should drop the first contact after another update.
- test_api_->DoUpdate();
- EXPECT_EQ(0, gdata_service_->num_download_requests_with_wrong_timestamps());
- EXPECT_EQ(base::Time::FromInternalValue(contact1->update_time()),
- test_api_->last_contact_update_time());
- EXPECT_TRUE(test_api_->GetLoadedContacts()->empty());
- EXPECT_TRUE(db_->contacts().empty());
- EXPECT_EQ(contact1->update_time(),
- db_->metadata().last_contact_update_time());
-}
-
-TEST_F(GoogleContactStoreTest, UseLastContactUpdateTimeFromMetadata) {
- base::Time::Exploded kInitTimeExploded = { 2012, 3, 0, 1, 16, 34, 56, 123 };
- base::Time kInitTime = base::Time::FromUTCExploded(kInitTimeExploded);
-
- // Configure the metadata to say that a contact was updated one day before the
- // current time. We won't create a contact that actually contains this time,
- // though; this mimics the situation where the most-recently-updated contact
- // has been deleted and wasn't saved to the database.
- base::Time kDeletedContactUpdateTime =
- kInitTime - base::TimeDelta::FromDays(1);
- UpdateMetadata db_metadata;
- db_metadata.set_last_contact_update_time(
- kDeletedContactUpdateTime.ToInternalValue());
-
- // Create a non-deleted contact with an update time one day prior to the
- // update time in the metadata.
- base::Time kNonDeletedContactUpdateTime =
- kDeletedContactUpdateTime - base::TimeDelta::FromDays(1);
- scoped_ptr<Contact> non_deleted_contact(new Contact);
- InitContact("contact", "1", false, non_deleted_contact.get());
- non_deleted_contact->set_update_time(
- kNonDeletedContactUpdateTime.ToInternalValue());
-
- // Save the contact to the database.
- ContactPointers db_contacts;
- db_contacts.push_back(non_deleted_contact.get());
- db_->SetContacts(db_contacts, db_metadata);
-
- // Tell the GData service to expect the deleted contact's update time.
- ContactPointers gdata_contacts;
- gdata_contacts.push_back(non_deleted_contact.get());
- gdata_service_->SetContacts(
- gdata_contacts,
- kDeletedContactUpdateTime + base::TimeDelta::FromMilliseconds(1));
-
- test_api_->set_current_time(kInitTime);
- store_->Init();
- EXPECT_EQ(0, gdata_service_->num_download_requests_with_wrong_timestamps());
- ContactPointers loaded_contacts;
- store_->AppendContacts(&loaded_contacts);
- EXPECT_EQ(ContactsToString(gdata_contacts),
- ContactsToString(loaded_contacts));
- EXPECT_TRUE(test_api_->update_scheduled());
-
-}
-
-} // namespace test
-} // namespace contacts