Commit 29af52f5 authored by Rayan Kanso's avatar Rayan Kanso Committed by Commit Bot

[Contacts] Handle addresses in blink <-> mojo and back.

Pipes whether addresses are required to mojo, and handles the expected
address return values.

TBR=mkwst@chromium.org

Bug: 1016870
Change-Id: I4d77de31736195c01754369e71f78d6825a1f811
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1874206
Commit-Queue: Rayan Kanso <rayankans@chromium.org>
Reviewed-by: default avatarFinnur Thorarinsson <finnur@chromium.org>
Reviewed-by: default avatarKen Buchanan <kenrb@chromium.org>
Reviewed-by: default avatarRouslan Solomakhin <rouslan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#708710}
parent 8b8a35cd
......@@ -79,10 +79,11 @@ void ContactsManagerImpl::Select(bool multiple,
bool include_names,
bool include_emails,
bool include_tel,
bool include_addresses,
SelectCallback mojom_callback) {
if (contacts_provider_) {
contacts_provider_->Select(
multiple, include_names, include_emails, include_tel,
multiple, include_names, include_emails, include_tel, include_addresses,
base::BindOnce(&OnContactsSelected, std::move(mojom_callback),
source_id_));
} else {
......
......@@ -28,6 +28,7 @@ class CONTENT_EXPORT ContactsManagerImpl
bool include_names,
bool include_emails,
bool include_tel,
bool include_addresses,
SelectCallback mojom_callback) override;
private:
......
......@@ -27,6 +27,7 @@ class ContactsProvider {
bool include_names,
bool include_emails,
bool include_tel,
bool include_addresses,
ContactsSelectedCallback callback) = 0;
};
......
......@@ -50,6 +50,7 @@ void ContactsProviderAndroid::Select(bool multiple,
bool include_names,
bool include_emails,
bool include_tel,
bool include_addresses,
ContactsSelectedCallback callback) {
if (!dialog_) {
std::move(callback).Run(base::nullopt, /*percentage_shared=*/-1,
......@@ -96,8 +97,11 @@ void ContactsProviderAndroid::AddContact(
tel = tel_vector;
}
base::Optional<std::vector<payments::mojom::PaymentAddressPtr>> addresses;
blink::mojom::ContactInfoPtr contact =
blink::mojom::ContactInfo::New(names, emails, tel);
blink::mojom::ContactInfo::New(std::move(names), std::move(emails),
std::move(tel), std::move(addresses));
contacts_.push_back(std::move(contact));
}
......
......@@ -26,6 +26,7 @@ class ContactsProviderAndroid : public ContactsProvider {
bool include_names,
bool include_emails,
bool include_tel,
bool include_addresses,
ContactsSelectedCallback callback) override;
// Adds one contact to the list of contacts selected. Note, EndContactsList
......
......@@ -4,11 +4,14 @@
module blink.mojom;
import "components/payments/mojom/payment_request_data.mojom";
// As per https://wicg.github.io/contact-api/spec/.
struct ContactInfo {
array<string>? name;
array<string>? email;
array<string>? tel;
array<payments.mojom.PaymentAddress>? address;
};
// The Contacts Manager lives in the browser process and can be initiated by the
......@@ -18,6 +21,6 @@ interface ContactsManager {
// website. The array of contacts returned can be null, in case of an error,
// for example if the dialog cannot be shown. The array is empty if the user
// does not select any contacts (e.g. cancels selection).
Select(bool multiple, bool include_names, bool include_emails, bool include_tel)
Select(bool multiple, bool include_names, bool include_emails, bool include_tel, bool include_addresses)
=> (array<ContactInfo>? contacts);
};
......@@ -6,6 +6,8 @@ import("//third_party/blink/renderer/modules/modules.gni")
blink_modules_sources("contacts_picker") {
sources = [
"contact_address.cc",
"contact_address.h",
"contacts_manager.cc",
"contacts_manager.h",
"navigator_contacts.cc",
......
include_rules = [
"-third_party/blink/renderer/modules",
"+third_party/blink/renderer/modules/contacts_picker",
"+third_party/blink/renderer/modules/payments",
]
// Copyright 2019 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 "third_party/blink/renderer/modules/contacts_picker/contact_address.h"
namespace blink {
ContactAddress::ContactAddress(
payments::mojom::blink::PaymentAddressPtr payment_address)
: PaymentAddress(std::move(payment_address)) {}
ContactAddress::~ContactAddress() = default;
} // namespace blink
// Copyright 2019 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 THIRD_PARTY_BLINK_RENDERER_MODULES_CONTACTS_PICKER_CONTACT_ADDRESS_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_CONTACTS_PICKER_CONTACT_ADDRESS_H_
#include "third_party/blink/public/mojom/payments/payment_request.mojom-blink.h"
#include "third_party/blink/renderer/modules/payments/payment_address.h"
namespace blink {
class ContactAddress : public PaymentAddress {
DEFINE_WRAPPERTYPEINFO();
public:
explicit ContactAddress(
payments::mojom::blink::PaymentAddressPtr payment_address);
~ContactAddress() override;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CONTACTS_PICKER_CONTACT_ADDRESS_H_
// Copyright 2019 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.
// https://wicg.github.io/contact-api/spec/#contactaddress
[
SecureContext,
Exposed=Window,
RuntimeEnabled=ContactsManagerAddresses
] interface ContactAddress : PaymentAddress {};
......@@ -8,4 +8,5 @@ dictionary ContactInfo {
sequence<USVString> name;
sequence<USVString> email;
sequence<USVString> tel;
sequence<ContactAddress> address;
};
......@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/modules/contacts_picker/contact_address.h"
#include "third_party/blink/renderer/modules/contacts_picker/contact_info.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
......@@ -29,7 +30,7 @@ TypeConverter<blink::ContactInfo*, blink::mojom::blink::ContactInfoPtr>::
Convert(const blink::mojom::blink::ContactInfoPtr& contact) {
blink::ContactInfo* contact_info = blink::ContactInfo::Create();
if (contact->name.has_value()) {
if (contact->name) {
Vector<String> names;
names.ReserveInitialCapacity(contact->name->size());
......@@ -39,7 +40,7 @@ TypeConverter<blink::ContactInfo*, blink::mojom::blink::ContactInfoPtr>::
contact_info->setName(names);
}
if (contact->email.has_value()) {
if (contact->email) {
Vector<String> emails;
emails.ReserveInitialCapacity(contact->email->size());
......@@ -49,7 +50,7 @@ TypeConverter<blink::ContactInfo*, blink::mojom::blink::ContactInfoPtr>::
contact_info->setEmail(emails);
}
if (contact->tel.has_value()) {
if (contact->tel) {
Vector<String> numbers;
numbers.ReserveInitialCapacity(contact->tel->size());
......@@ -59,6 +60,17 @@ TypeConverter<blink::ContactInfo*, blink::mojom::blink::ContactInfoPtr>::
contact_info->setTel(numbers);
}
if (contact->address) {
blink::HeapVector<blink::Member<blink::ContactAddress>> addresses;
for (auto& address : *contact->address) {
auto* blink_address = blink::MakeGarbageCollected<blink::ContactAddress>(
std::move(address));
addresses.push_back(blink_address);
}
contact_info->setAddress(addresses);
}
return contact_info;
}
......@@ -132,6 +144,7 @@ ScriptPromise ContactsManager::select(ScriptState* script_state,
bool include_names = false;
bool include_emails = false;
bool include_tel = false;
bool include_addresses = false;
for (const String& property : properties) {
if (!base::Contains(properties_, property)) {
......@@ -149,6 +162,8 @@ ScriptPromise ContactsManager::select(ScriptState* script_state,
include_emails = true;
else if (property == kTel)
include_tel = true;
else if (property == kAddress)
include_addresses = true;
}
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
......@@ -157,6 +172,7 @@ ScriptPromise ContactsManager::select(ScriptState* script_state,
contact_picker_in_use_ = true;
GetContactsManager(script_state)
->Select(options->multiple(), include_names, include_emails, include_tel,
include_addresses,
WTF::Bind(&ContactsManager::OnContactsSelected,
WrapPersistent(this), WrapPersistent(resolver)));
......
......@@ -100,6 +100,7 @@ modules_idl_files =
"clipboard/clipboard_item.idl",
"compression/compression_stream.idl",
"compression/decompression_stream.idl",
"contacts_picker/contact_address.idl",
"contacts_picker/contacts_manager.idl",
"content_index/content_index.idl",
"content_index/content_index_event.idl",
......
......@@ -16,7 +16,7 @@
namespace blink {
class MODULES_EXPORT PaymentAddress final : public ScriptWrappable {
class MODULES_EXPORT PaymentAddress : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
......
......@@ -59,38 +59,53 @@ contactsTestWithUserActivation(async (test, setSelectedContacts) => {
}, 'Supported contact properties are exposed.');
contactsTestWithUserActivation(async (test, setSelectedContacts) => {
const dwightAddress = {
country: 'US',
city: 'Scranton',
addressLine: ['Schrute Farms'],
};
// Returns two contacts with all information available.
setSelectedContacts([
{ name: ['Dwight Schrute'], email: ['dwight@schrutefarmsbnb.com'], tel: ['000-0000'] },
{ name: ['Michael Scott', 'Prison Mike'], email: ['michael@dundermifflin.com'], tel: [] },
{ name: ['Dwight Schrute'], email: ['dwight@schrutefarmsbnb.com'], tel: ['000-0000'], address: [dwightAddress] },
{ name: ['Michael Scott', 'Prison Mike'], email: ['michael@dundermifflin.com'] },
]);
let results = await navigator.contacts.select(['name', 'email', 'tel'], { multiple: true });
let results = await navigator.contacts.select(['name', 'email', 'tel', 'address'], { multiple: true });
assert_equals(results.length, 2);
results = results.sort((c1, c2) => JSON.stringify(c1) < JSON.stringify(c2) ? -1 : 1);
{
const dwight = results[0];
const michael = results[0];
assert_own_property(michael, 'name');
assert_own_property(michael, 'email');
assert_own_property(michael, 'tel');
assert_own_property(michael, 'address');
assert_array_equals(michael.name, ['Michael Scott', 'Prison Mike']);
assert_array_equals(michael.email, ['michael@dundermifflin.com']);
assert_array_equals(michael.tel, []);
assert_array_equals(michael.address, []);
}
{
const dwight = results[1];
assert_own_property(dwight, 'name');
assert_own_property(dwight, 'email');
assert_own_property(dwight, 'tel');
assert_own_property(dwight, 'address');
assert_array_equals(dwight.name, ['Dwight Schrute']);
assert_array_equals(dwight.email, ['dwight@schrutefarmsbnb.com']);
assert_array_equals(dwight.tel, ['000-0000']);
}
{
const michael = results[1];
assert_own_property(michael, 'name');
assert_own_property(michael, 'email');
assert_own_property(michael, 'tel');
assert_array_equals(michael.name, ['Michael Scott', 'Prison Mike']);
assert_array_equals(michael.email, ['michael@dundermifflin.com']);
assert_array_equals(michael.tel, []);
assert_equals(dwight.address.length, 1);
const selectedAddress = dwight.address[0];
assert_object_equals({
country: selectedAddress.country,
city: selectedAddress.city,
addressLine: selectedAddress.addressLine,
}, dwightAddress);
}
}, 'The Contact API correctly returns ContactInfo entries');
......@@ -98,7 +113,7 @@ contactsTestWithUserActivation(async (test, setSelectedContacts) => {
// Returns two contacts with all information available.
setSelectedContacts([
{ name: ['Dwight Schrute'], email: ['dwight@schrutefarmsbnb.com'], tel: ['000-0000'] },
{ name: ['Michael Scott', 'Prison Mike'], email: ['michael@dundermifflin.com'], tel: [] },
{ name: ['Michael Scott', 'Prison Mike'], email: ['michael@dundermifflin.com'] },
]);
const results = await navigator.contacts.select(['name', 'email', 'tel']);
......@@ -108,7 +123,7 @@ contactsTestWithUserActivation(async (test, setSelectedContacts) => {
contactsTestWithUserActivation(async (test, setSelectedContacts) => {
// Returns partial information since no e-mail addresses are requested.
setSelectedContacts([{ name: ['Creed'], email: ['creedthoughts@www.creedthoughts.gov.www'], tel: [] }]);
setSelectedContacts([{ name: ['Creed'], email: ['creedthoughts@www.creedthoughts.gov.www'] }]);
const results = await navigator.contacts.select(['name']);
......@@ -125,7 +140,7 @@ contactsTestWithUserActivation(async (test, setSelectedContacts) => {
contactsTestWithUserActivation(async (test, setSelectedContacts) => {
// Returns partial information since no e-mail addresses are requested.
setSelectedContacts([{ name: ['Kelly'], email: [], tel: [] }]);
setSelectedContacts([{ name: ['Kelly'] }]);
// First request should work.
const promise1 = new Promise((resolve, reject) => {
......
......@@ -18,18 +18,38 @@ const WebContactsTest = (() => {
this.selectedContacts_ = [];
}
async select(multiple, includeNames, includeEmails, includeTel) {
formatAddress_(address) {
// These are all required fields in the mojo definition.
return {
country: address.country || '',
addressLine: address.addressLine || [],
region: address.region || '',
city: address.city || '',
dependentLocality: address.dependentLocality || '',
postalCode: address.postCode || '',
sortingCode: address.sortingCode || '',
organization: address.organization || '',
recipient: address.recipient || '',
phone: address.phone || '',
};
}
async select(multiple, includeNames, includeEmails, includeTel, includeAddresses) {
if (this.selectedContacts_ === null)
return {contacts: null};
const contactInfos = this.selectedContacts_.map(contact => {
const contactInfo = new blink.mojom.ContactInfo();
if (includeNames)
contactInfo.name = contact.name;
contactInfo.name = contact.name || [];
if (includeEmails)
contactInfo.email = contact.email;
contactInfo.email = contact.email || [];
if (includeTel)
contactInfo.tel = contact.tel;
contactInfo.tel = contact.tel || [];
if (includeAddresses) {
contactInfo.address = contact.address || [];
contactInfo.address = contactInfo.address.map(address => this.formatAddress_(address));
}
return contactInfo;
});
......
......@@ -1157,6 +1157,9 @@ interface ConstantSourceNode : AudioScheduledSourceNode
attribute @@toStringTag
getter offset
method constructor
interface ContactAddress : PaymentAddress
attribute @@toStringTag
method constructor
interface ContactsManager
attribute @@toStringTag
method constructor
......
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