diff options
Diffstat (limited to 'chrome/browser/chromeos')
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 |