| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/browser/contacts/contacts_provider_android.h" |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/android/jni_bytebuffer.h" |
| #include "base/android/jni_string.h" |
| #include "base/functional/callback.h" |
| #include "base/metrics/histogram_functions.h" |
| #include "components/url_formatter/elide_url.h" |
| #include "content/browser/renderer_host/render_frame_host_impl.h" |
| #include "content/public/browser/contacts_picker_properties.h" |
| #include "content/public/browser/web_contents.h" |
| #include "url/origin.h" |
| |
| // Must come after all headers that specialize FromJniType() / ToJniType(). |
| #include "content/public/android/content_jni_headers/ContactsDialogHost_jni.h" |
| |
| namespace content { |
| |
| ContactsProviderAndroid::ContactsProviderAndroid( |
| RenderFrameHostImpl* render_frame_host) { |
| JNIEnv* env = base::android::AttachCurrentThread(); |
| |
| WebContents* web_contents = |
| WebContents::FromRenderFrameHost(render_frame_host); |
| if (!web_contents || !web_contents->GetTopLevelNativeWindow()) |
| return; |
| |
| formatted_origin_ = url_formatter::FormatUrlForSecurityDisplay( |
| render_frame_host->GetLastCommittedOrigin().GetURL(), |
| url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC); |
| |
| dialog_.Reset( |
| Java_ContactsDialogHost_create(env, web_contents->GetJavaWebContents(), |
| reinterpret_cast<intptr_t>(this))); |
| DCHECK(!dialog_.is_null()); |
| } |
| |
| ContactsProviderAndroid::~ContactsProviderAndroid() { |
| JNIEnv* env = base::android::AttachCurrentThread(); |
| Java_ContactsDialogHost_destroy(env, dialog_); |
| } |
| |
| void ContactsProviderAndroid::Select(bool multiple, |
| bool include_names, |
| bool include_emails, |
| bool include_tel, |
| bool include_addresses, |
| bool include_icons, |
| ContactsSelectedCallback callback) { |
| if (!dialog_) { |
| std::move(callback).Run(std::nullopt, /*percentage_shared=*/-1, |
| PROPERTIES_NONE); |
| return; |
| } |
| |
| callback_ = std::move(callback); |
| |
| JNIEnv* env = base::android::AttachCurrentThread(); |
| Java_ContactsDialogHost_showDialog( |
| env, dialog_, multiple, include_names, include_emails, include_tel, |
| include_addresses, include_icons, |
| base::android::ConvertUTF16ToJavaString(env, formatted_origin_)); |
| } |
| |
| void ContactsProviderAndroid::AddContact( |
| JNIEnv* env, |
| const base::android::JavaParamRef<jobjectArray>& names_java, |
| const base::android::JavaParamRef<jobjectArray>& emails_java, |
| const base::android::JavaParamRef<jobjectArray>& tel_java, |
| const base::android::JavaParamRef<jobjectArray>& addresses_java, |
| const base::android::JavaParamRef<jobjectArray>& icons_java) { |
| DCHECK(callback_); |
| |
| std::optional<std::vector<std::string>> names; |
| if (names_java) { |
| std::vector<std::string> names_vector; |
| base::android::AppendJavaStringArrayToStringVector(env, names_java, |
| &names_vector); |
| names = std::move(names_vector); |
| } |
| |
| std::optional<std::vector<std::string>> emails; |
| if (emails_java) { |
| std::vector<std::string> emails_vector; |
| base::android::AppendJavaStringArrayToStringVector(env, emails_java, |
| &emails_vector); |
| emails = std::move(emails_vector); |
| } |
| |
| std::optional<std::vector<std::string>> tel; |
| if (tel_java) { |
| std::vector<std::string> tel_vector; |
| base::android::AppendJavaStringArrayToStringVector(env, tel_java, |
| &tel_vector); |
| tel = std::move(tel_vector); |
| } |
| |
| std::optional<std::vector<payments::mojom::PaymentAddressPtr>> addresses; |
| if (addresses_java) { |
| std::vector<payments::mojom::PaymentAddressPtr> addresses_vector; |
| |
| for (const base::android::JavaRef<jbyteArray>& j_address : |
| addresses_java.ReadElements<jbyteArray>()) { |
| payments::mojom::PaymentAddressPtr address; |
| base::span<const uint8_t> address_bytes = |
| base::android::JavaByteBufferToSpan(env, j_address.obj()); |
| if (!payments::mojom::PaymentAddress::Deserialize( |
| address_bytes.data(), address_bytes.size(), &address)) { |
| continue; |
| } |
| addresses_vector.push_back(std::move(address)); |
| } |
| |
| addresses = std::move(addresses_vector); |
| } |
| |
| std::optional<std::vector<blink::mojom::ContactIconBlobPtr>> icons; |
| if (icons_java) { |
| std::vector<blink::mojom::ContactIconBlobPtr> icons_vector; |
| |
| for (const base::android::JavaRef<jbyteArray>& j_icon : |
| icons_java.ReadElements<jbyteArray>()) { |
| blink::mojom::ContactIconBlobPtr icon; |
| base::span<const uint8_t> icon_bytes = |
| base::android::JavaByteBufferToSpan(env, j_icon.obj()); |
| if (!blink::mojom::ContactIconBlob::Deserialize( |
| icon_bytes.data(), icon_bytes.size(), &icon)) { |
| continue; |
| } |
| icons_vector.push_back(std::move(icon)); |
| } |
| |
| icons = std::move(icons_vector); |
| } |
| |
| blink::mojom::ContactInfoPtr contact = blink::mojom::ContactInfo::New( |
| std::move(names), std::move(emails), std::move(tel), std::move(addresses), |
| std::move(icons)); |
| |
| contacts_.push_back(std::move(contact)); |
| } |
| |
| void ContactsProviderAndroid::EndContactsList(JNIEnv* env, |
| jint percentage_shared, |
| jint properties_requested) { |
| DCHECK(callback_); |
| ContactsPickerProperties properties = |
| static_cast<ContactsPickerProperties>(properties_requested); |
| std::move(callback_).Run(std::move(contacts_), percentage_shared, properties); |
| } |
| |
| void ContactsProviderAndroid::EndWithPermissionDenied(JNIEnv* env) { |
| DCHECK(callback_); |
| std::move(callback_).Run(std::nullopt, /*percentage_shared=*/-1, |
| PROPERTIES_NONE); |
| } |
| |
| } // namespace content |