Commit 5676bf28 authored by derat@chromium.org's avatar derat@chromium.org

chromeos: Use protocol buffers for Contact class.

This was formerly a hand-rolled C++ class, but Satoru
pointed out that using protocol buffers would make
serialization to disk much simpler.

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

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@148868 0039d316-1c4b-4281-b951-d872f2087c98
parent 11faec11
// 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.h"
namespace contacts {
Contact::AddressType::AddressType() : relation(RELATION_OTHER) {}
Contact::EmailAddress::EmailAddress() : primary(false) {}
Contact::PhoneNumber::PhoneNumber() : primary(false) {}
Contact::PostalAddress::PostalAddress() : primary(false) {}
Contact::InstantMessagingAddress::InstantMessagingAddress()
: protocol(PROTOCOL_OTHER),
primary(false) {}
Contact::Contact() : deleted(false) {}
Contact::~Contact() {}
} // namespace contacts
// 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_H_
#define CHROME_BROWSER_CHROMEOS_CONTACTS_CONTACT_H_
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/time.h"
#include "third_party/skia/include/core/SkBitmap.h"
namespace contacts {
// Struct representing a contact, roughly based on the GData Contact kind:
// https://developers.google.com/gdata/docs/2.0/elements#gdContactKind
// All strings are UTF-8.
struct Contact {
// Describes an address-like field's type.
struct AddressType {
enum Relation {
RELATION_HOME = 0,
RELATION_WORK = 1,
RELATION_MOBILE = 2,
RELATION_OTHER = 3,
};
AddressType();
Relation relation;
std::string label;
};
struct EmailAddress {
EmailAddress();
std::string address;
AddressType type;
bool primary;
};
struct PhoneNumber {
PhoneNumber();
std::string number;
AddressType type;
bool primary;
};
struct PostalAddress {
PostalAddress();
std::string address;
AddressType type;
bool primary;
};
struct InstantMessagingAddress {
// Taken from https://developers.google.com/gdata/docs/2.0/elements#gdIm.
enum Protocol {
PROTOCOL_AIM = 0,
PROTOCOL_MSN = 1,
PROTOCOL_YAHOO = 2,
PROTOCOL_SKYPE = 3,
PROTOCOL_QQ = 4,
PROTOCOL_GOOGLE_TALK = 5,
PROTOCOL_ICQ = 6,
PROTOCOL_JABBER = 7,
PROTOCOL_OTHER = 8,
};
InstantMessagingAddress();
std::string address;
Protocol protocol;
AddressType type;
bool primary;
};
Contact();
~Contact();
int64 serialized_update_time() const {
return update_time.ToInternalValue();
}
void set_serialized_update_time(int64 serialized) {
update_time = base::Time::FromInternalValue(serialized);
}
// NOTE: Any changes to the below fields must be reflected in
// contact_test_util.cc's CopyContact() function.
// Provider-assigned unique identifier.
std::string provider_id;
// Last time at which this contact was updated.
base::Time update_time;
// Has the contact been deleted?
bool deleted;
// Taken from https://developers.google.com/gdata/docs/2.0/elements#gdName.
std::string full_name;
std::string given_name;
std::string additional_name;
std::string family_name;
std::string name_prefix;
std::string name_suffix;
SkBitmap photo;
std::vector<EmailAddress> email_addresses;
std::vector<PhoneNumber> phone_numbers;
std::vector<PostalAddress> postal_addresses;
std::vector<InstantMessagingAddress> instant_messaging_addresses;
DISALLOW_COPY_AND_ASSIGN(Contact);
};
typedef std::vector<const Contact*> ContactPointers;
} // namespace contacts
#endif // CHROME_BROWSER_CHROMEOS_CONTACTS_CONTACT_H_
// 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.
message Contact {
// Next ID to use: 15
// Provider-assigned unique identifier.
optional string provider_id = 1;
// Last time at which this contact was updated within the upstream provider.
optional int64 update_time = 2;
// Has the contact been deleted recently within the upstream provider?
optional bool deleted = 3 [default = false];
// 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;
}
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/string_util.h" #include "base/string_util.h"
#include "base/time.h" #include "base/time.h"
#include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/size.h" #include "ui/gfx/size.h"
namespace contacts { namespace contacts {
...@@ -24,73 +25,83 @@ namespace { ...@@ -24,73 +25,83 @@ namespace {
// and then sorts the resulting strings and joins them using |join_char|. // and then sorts the resulting strings and joins them using |join_char|.
template<class T> template<class T>
std::string StringifyField( std::string StringifyField(
const std::vector<T>& items, const ::google::protobuf::RepeatedPtrField<T>& items,
base::Callback<std::string(const T&)> stringify_callback, base::Callback<std::string(const T&)> stringify_callback,
const std::string& prefix, const std::string& prefix,
char join_char) { char join_char) {
std::vector<std::string> strings; std::vector<std::string> strings;
for (size_t i = 0; i < items.size(); ++i) for (int i = 0; i < items.size(); ++i)
strings.push_back(prefix + stringify_callback.Run(items[i])); strings.push_back(prefix + stringify_callback.Run(items.Get(i)));
std::sort(strings.begin(), strings.end()); std::sort(strings.begin(), strings.end());
return JoinString(strings, join_char); return JoinString(strings, join_char);
} }
std::string EmailAddressToString(const Contact::EmailAddress& email) { std::string EmailAddressToString(const Contact_EmailAddress& email) {
return email.address + "," + return email.address() + "," +
base::IntToString(email.type.relation) + "," + base::IntToString(email.type().relation()) + "," +
email.type.label + "," + email.type().label() + "," +
base::IntToString(email.primary); base::IntToString(email.primary());
} }
std::string PhoneNumberToString(const Contact::PhoneNumber& phone) { std::string PhoneNumberToString(const Contact_PhoneNumber& phone) {
return phone.number + "," + return phone.number() + "," +
base::IntToString(phone.type.relation) + "," + base::IntToString(phone.type().relation()) + "," +
phone.type.label + "," + phone.type().label() + "," +
base::IntToString(phone.primary); base::IntToString(phone.primary());
} }
std::string PostalAddressToString(const Contact::PostalAddress& postal) { std::string PostalAddressToString(const Contact_PostalAddress& postal) {
return postal.address + "," + return postal.address() + "," +
base::IntToString(postal.type.relation) + "," + base::IntToString(postal.type().relation()) + "," +
postal.type.label + "," + postal.type().label() + "," +
base::IntToString(postal.primary); base::IntToString(postal.primary());
} }
std::string InstantMessagingAddressToString( std::string InstantMessagingAddressToString(
const Contact::InstantMessagingAddress& im) { const Contact_InstantMessagingAddress& im) {
return im.address + "," + return im.address() + "," +
base::IntToString(im.protocol) + "," + base::IntToString(im.protocol()) + "," +
base::IntToString(im.type.relation) + "," + base::IntToString(im.type().relation()) + "," +
im.type.label + "," + im.type().label() + "," +
base::IntToString(im.primary); base::IntToString(im.primary());
} }
} // namespace } // namespace
std::string ContactToString(const Contact& contact) { std::string ContactToString(const Contact& contact) {
std::string result = std::string result =
contact.provider_id + "," + contact.provider_id() + "," +
base::Int64ToString(contact.update_time.ToInternalValue()) + "," + base::Int64ToString(contact.update_time()) + "," +
base::IntToString(contact.deleted) + "," + base::IntToString(contact.deleted()) + "," +
contact.full_name + "," + contact.full_name() + "," +
contact.given_name + "," + contact.given_name() + "," +
contact.additional_name + "," + contact.additional_name() + "," +
contact.family_name + "," + contact.family_name() + "," +
contact.name_prefix + "," + contact.name_prefix() + "," +
contact.name_suffix + "," + contact.name_suffix();
base::IntToString(contact.photo.width()) + "x" +
base::IntToString(contact.photo.height()); SkBitmap bitmap;
if (contact.has_raw_untrusted_photo()) {
result += " " + StringifyField(contact.email_addresses, // 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), base::Bind(EmailAddressToString),
"email=", ' '); "email=", ' ');
result += " " + StringifyField(contact.phone_numbers, result += " " + StringifyField(contact.phone_numbers(),
base::Bind(PhoneNumberToString), base::Bind(PhoneNumberToString),
"phone=", ' '); "phone=", ' ');
result += " " + StringifyField(contact.postal_addresses, result += " " + StringifyField(contact.postal_addresses(),
base::Bind(PostalAddressToString), base::Bind(PostalAddressToString),
"postal=", ' '); "postal=", ' ');
result += " " + StringifyField(contact.instant_messaging_addresses, result += " " + StringifyField(contact.instant_messaging_addresses(),
base::Bind(InstantMessagingAddressToString), base::Bind(InstantMessagingAddressToString),
"im=", ' '); "im=", ' ');
...@@ -122,30 +133,13 @@ std::string VarContactsToString(int num_contacts, ...) { ...@@ -122,30 +133,13 @@ std::string VarContactsToString(int num_contacts, ...) {
return ContactsToString(contacts); return ContactsToString(contacts);
} }
void CopyContact(const Contact& source, Contact* dest) {
dest->provider_id = source.provider_id;
dest->update_time = source.update_time;
dest->deleted = source.deleted;
dest->full_name = source.full_name;
dest->given_name = source.given_name;
dest->additional_name = source.additional_name;
dest->family_name = source.family_name;
dest->name_prefix = source.name_prefix;
dest->name_suffix = source.name_suffix;
dest->photo = source.photo;
dest->email_addresses = source.email_addresses;
dest->phone_numbers = source.phone_numbers;
dest->postal_addresses = source.postal_addresses;
dest->instant_messaging_addresses = source.instant_messaging_addresses;
}
void CopyContacts(const ContactPointers& source, void CopyContacts(const ContactPointers& source,
ScopedVector<Contact>* dest) { ScopedVector<Contact>* dest) {
DCHECK(dest); DCHECK(dest);
dest->clear(); dest->clear();
for (size_t i = 0; i < source.size(); ++i) { for (size_t i = 0; i < source.size(); ++i) {
Contact* contact = new Contact; Contact* contact = new Contact;
CopyContact(*source[i], contact); *contact = *source[i];
dest->push_back(contact); dest->push_back(contact);
} }
} }
...@@ -163,86 +157,86 @@ void InitContact(const std::string& provider_id, ...@@ -163,86 +157,86 @@ void InitContact(const std::string& provider_id,
bool deleted, bool deleted,
Contact* contact) { Contact* contact) {
DCHECK(contact); DCHECK(contact);
contact->provider_id = provider_id; contact->Clear();
contact->update_time = base::Time::Now(); contact->set_provider_id(provider_id);
contact->deleted = deleted; contact->set_update_time(base::Time::Now().ToInternalValue());
contact->full_name = "full_name_" + name_suffix; contact->set_deleted(deleted);
contact->given_name = "given_name_" + name_suffix; contact->set_full_name("full_name_" + name_suffix);
contact->additional_name = "additional_name_" + name_suffix; contact->set_given_name("given_name_" + name_suffix);
contact->family_name = "family_name_" + name_suffix; contact->set_additional_name("additional_name_" + name_suffix);
contact->name_prefix = "name_prefix_" + name_suffix; contact->set_family_name("family_name_" + name_suffix);
contact->name_suffix = "name_suffix_" + name_suffix; contact->set_name_prefix("name_prefix_" + name_suffix);
contact->photo = SkBitmap(); contact->set_name_suffix("name_suffix_" + name_suffix);
contact->email_addresses.clear();
contact->phone_numbers.clear();
contact->postal_addresses.clear();
contact->instant_messaging_addresses.clear();
} }
void AddEmailAddress(const std::string& address, void AddEmailAddress(const std::string& address,
Contact::AddressType::Relation relation, Contact_AddressType_Relation relation,
const std::string& label, const std::string& label,
bool primary, bool primary,
Contact* contact) { Contact* contact) {
DCHECK(contact); DCHECK(contact);
Contact::EmailAddress email; Contact::EmailAddress* email = contact->add_email_addresses();
email.address = address; email->set_address(address);
email.type.relation = relation; email->mutable_type()->set_relation(relation);
email.type.label = label; email->mutable_type()->set_label(label);
email.primary = primary; email->set_primary(primary);
contact->email_addresses.push_back(email);
} }
void AddPhoneNumber(const std::string& number, void AddPhoneNumber(const std::string& number,
Contact::AddressType::Relation relation, Contact_AddressType_Relation relation,
const std::string& label, const std::string& label,
bool primary, bool primary,
Contact* contact) { Contact* contact) {
DCHECK(contact); DCHECK(contact);
Contact::PhoneNumber phone; Contact::PhoneNumber* phone = contact->add_phone_numbers();
phone.number = number; phone->set_number(number);
phone.type.relation = relation; phone->mutable_type()->set_relation(relation);
phone.type.label = label; phone->mutable_type()->set_label(label);
phone.primary = primary; phone->set_primary(primary);
contact->phone_numbers.push_back(phone);
} }
void AddPostalAddress(const std::string& address, void AddPostalAddress(const std::string& address,
Contact::AddressType::Relation relation, Contact_AddressType_Relation relation,
const std::string& label, const std::string& label,
bool primary, bool primary,
Contact* contact) { Contact* contact) {
DCHECK(contact); DCHECK(contact);
Contact::PostalAddress postal; Contact::PostalAddress* postal = contact->add_postal_addresses();
postal.address = address; postal->set_address(address);
postal.type.relation = relation; postal->mutable_type()->set_relation(relation);
postal.type.label = label; postal->mutable_type()->set_label(label);
postal.primary = primary; postal->set_primary(primary);
contact->postal_addresses.push_back(postal);
} }
void AddInstantMessagingAddress( void AddInstantMessagingAddress(
const std::string& address, const std::string& address,
Contact::InstantMessagingAddress::Protocol protocol, Contact_InstantMessagingAddress_Protocol protocol,
Contact::AddressType::Relation relation, Contact_AddressType_Relation relation,
const std::string& label, const std::string& label,
bool primary, bool primary,
Contact* contact) { Contact* contact) {
DCHECK(contact); DCHECK(contact);
Contact::InstantMessagingAddress im; Contact::InstantMessagingAddress* im =
im.address = address; contact->add_instant_messaging_addresses();
im.protocol = protocol; im->set_address(address);
im.type.relation = relation; im->set_protocol(protocol);
im.type.label = label; im->mutable_type()->set_relation(relation);
im.primary = primary; im->mutable_type()->set_label(label);
contact->instant_messaging_addresses.push_back(im); im->set_primary(primary);
} }
void SetPhoto(const gfx::Size& size, Contact* contact) { void SetPhoto(const gfx::Size& size, Contact* contact) {
DCHECK(contact); DCHECK(contact);
contact->photo.setConfig( if (size.IsEmpty()) {
SkBitmap::kARGB_8888_Config, size.width(), size.height()); contact->clear_raw_untrusted_photo();
contact->photo.allocPixels(); return;
}
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
bitmap.allocPixels();
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 test
......
...@@ -8,12 +8,14 @@ ...@@ -8,12 +8,14 @@
#include <string> #include <string>
#include "base/memory/scoped_vector.h" #include "base/memory/scoped_vector.h"
#include "chrome/browser/chromeos/contacts/contact.h" #include "chrome/browser/chromeos/contacts/contact.pb.h"
#include "ui/gfx/size.h" #include "ui/gfx/size.h"
namespace contacts { namespace contacts {
namespace test { namespace test {
typedef std::vector<const Contact*> ContactPointers;
// Returns a string containing the information stored in |contact|. The same // Returns a string containing the information stored in |contact|. The same
// string will be returned for functionally-equivalent contacts (e.g. ones // string will be returned for functionally-equivalent contacts (e.g. ones
// containing the same email addresses but in a different order). // containing the same email addresses but in a different order).
...@@ -28,9 +30,6 @@ std::string ContactsToString(const ScopedVector<Contact>& contacts); ...@@ -28,9 +30,6 @@ std::string ContactsToString(const ScopedVector<Contact>& contacts);
// const Contact* arguments. // const Contact* arguments.
std::string VarContactsToString(int num_contacts, ...); std::string VarContactsToString(int num_contacts, ...);
// Copies |source|'s data to |dest|.
void CopyContact(const Contact& source, Contact* dest);
// Saves copies of all contacts in |source| to |dest|. // Saves copies of all contacts in |source| to |dest|.
void CopyContacts(const ContactPointers& source, void CopyContacts(const ContactPointers& source,
ScopedVector<Contact>* dest); ScopedVector<Contact>* dest);
...@@ -49,21 +48,21 @@ void InitContact(const std::string& provider_id, ...@@ -49,21 +48,21 @@ void InitContact(const std::string& provider_id,
// Adds an email address to |contact|. // Adds an email address to |contact|.
void AddEmailAddress(const std::string& address, void AddEmailAddress(const std::string& address,
Contact::AddressType::Relation relation, Contact_AddressType_Relation relation,
const std::string& label, const std::string& label,
bool primary, bool primary,
Contact* contact); Contact* contact);
// Adds a phone number to |contact|. // Adds a phone number to |contact|.
void AddPhoneNumber(const std::string& number, void AddPhoneNumber(const std::string& number,
Contact::AddressType::Relation relation, Contact_AddressType_Relation relation,
const std::string& label, const std::string& label,
bool primary, bool primary,
Contact* contact); Contact* contact);
// Adds a postal address to |contact|. // Adds a postal address to |contact|.
void AddPostalAddress(const std::string& address, void AddPostalAddress(const std::string& address,
Contact::AddressType::Relation relation, Contact_AddressType_Relation relation,
const std::string& label, const std::string& label,
bool primary, bool primary,
Contact* contact); Contact* contact);
...@@ -71,8 +70,8 @@ void AddPostalAddress(const std::string& address, ...@@ -71,8 +70,8 @@ void AddPostalAddress(const std::string& address,
// Adds an IM address to |contact|. // Adds an IM address to |contact|.
void AddInstantMessagingAddress( void AddInstantMessagingAddress(
const std::string& address, const std::string& address,
Contact::InstantMessagingAddress::Protocol protocol, Contact_InstantMessagingAddress_Protocol protocol,
Contact::AddressType::Relation relation, Contact_AddressType_Relation relation,
const std::string& label, const std::string& label,
bool primary, bool primary,
Contact* contact); Contact* contact);
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
'safe_browsing_report_proto', 'safe_browsing_report_proto',
'feedback_proto', 'feedback_proto',
'gdata_proto', 'gdata_proto',
'contacts_proto',
'variations_seed_proto', 'variations_seed_proto',
'../build/temp_gyp/googleurl.gyp:googleurl', '../build/temp_gyp/googleurl.gyp:googleurl',
'../content/content.gyp:content_browser', '../content/content.gyp:content_browser',
...@@ -451,8 +452,6 @@ ...@@ -451,8 +452,6 @@
'browser/chromeos/choose_mobile_network_dialog.h', 'browser/chromeos/choose_mobile_network_dialog.h',
'browser/chromeos/chrome_browser_main_chromeos.cc', 'browser/chromeos/chrome_browser_main_chromeos.cc',
'browser/chromeos/chrome_browser_main_chromeos.h', 'browser/chromeos/chrome_browser_main_chromeos.h',
'browser/chromeos/contacts/contact.cc',
'browser/chromeos/contacts/contact.h',
'browser/chromeos/cros/burn_library.cc', 'browser/chromeos/cros/burn_library.cc',
'browser/chromeos/cros/burn_library.h', 'browser/chromeos/cros/burn_library.h',
'browser/chromeos/cros/cellular_data_plan.cc', 'browser/chromeos/cros/cellular_data_plan.cc',
...@@ -5446,6 +5445,17 @@ ...@@ -5446,6 +5445,17 @@
}, },
'includes': [ '../build/protoc.gypi' ] 'includes': [ '../build/protoc.gypi' ]
}, },
{
# Protobuf compiler / generator for contacts-related protocol buffers.
'target_name': 'contacts_proto',
'type': 'static_library',
'sources': [ 'browser/chromeos/contacts/contact.proto' ],
'variables': {
'proto_in_dir': 'browser/chromeos/contacts',
'proto_out_dir': 'chrome/browser/chromeos/contacts',
},
'includes': [ '../build/protoc.gypi' ]
},
{ {
# Protobuf compiler / generator for Chrome Variations seed. # Protobuf compiler / generator for Chrome Variations seed.
'target_name': 'variations_seed_proto', 'target_name': 'variations_seed_proto',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment