summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/autofill.gypi1
-rw-r--r--components/autofill/content/browser/content_autofill_driver.cc10
-rw-r--r--components/autofill/content/browser/content_autofill_driver.h1
-rw-r--r--components/autofill/content/common/autofill_messages.h8
-rw-r--r--components/autofill/content/renderer/autofill_agent.cc5
-rw-r--r--components/autofill/content/renderer/autofill_agent.h1
-rw-r--r--components/autofill/core/browser/autofill_driver.h4
-rw-r--r--components/autofill/core/browser/autofill_external_delegate.cc65
-rw-r--r--components/autofill/core/browser/autofill_external_delegate.h8
-rw-r--r--components/autofill/core/browser/autofill_manager.cc22
-rw-r--r--components/autofill/core/browser/autofill_manager.h13
-rw-r--r--components/autofill/core/browser/personal_data_manager.h12
-rw-r--r--components/autofill/core/browser/personal_data_manager_mac.mm89
-rw-r--r--components/autofill/core/browser/popup_item_ids.h3
-rw-r--r--components/autofill/core/browser/test_autofill_driver.cc2
-rw-r--r--components/autofill/core/browser/test_autofill_driver.h1
-rw-r--r--components/autofill_strings.grdp7
17 files changed, 233 insertions, 19 deletions
diff --git a/components/autofill.gypi b/components/autofill.gypi
index 5972f5d1..d691ae3 100644
--- a/components/autofill.gypi
+++ b/components/autofill.gypi
@@ -183,6 +183,7 @@
'autofill/core/browser/phone_number.h',
'autofill/core/browser/phone_number_i18n.cc',
'autofill/core/browser/phone_number_i18n.h',
+ 'autofill/core/browser/popup_item_ids.h',
'autofill/core/browser/state_names.cc',
'autofill/core/browser/state_names.h',
'autofill/core/browser/validation.cc',
diff --git a/components/autofill/content/browser/content_autofill_driver.cc b/components/autofill/content/browser/content_autofill_driver.cc
index 62c64b2..54b095e 100644
--- a/components/autofill/content/browser/content_autofill_driver.cc
+++ b/components/autofill/content/browser/content_autofill_driver.cc
@@ -108,6 +108,13 @@ void ContentAutofillDriver::SendFormDataToRenderer(
}
}
+void ContentAutofillDriver::PingRenderer() {
+ if (!RendererIsAvailable())
+ return;
+ content::RenderViewHost* host = web_contents()->GetRenderViewHost();
+ host->Send(new AutofillMsg_Ping(host->GetRoutingID()));
+}
+
void ContentAutofillDriver::SendAutofillTypePredictionsToRenderer(
const std::vector<FormStructure*>& forms) {
if (!CommandLine::ForCurrentProcess()->HasSwitch(
@@ -181,6 +188,9 @@ bool ContentAutofillDriver::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_FORWARD(AutofillHostMsg_DidPreviewAutofillFormData,
autofill_manager_.get(),
AutofillManager::OnDidPreviewAutofillFormData)
+ IPC_MESSAGE_FORWARD(AutofillHostMsg_PingAck,
+ &autofill_external_delegate_,
+ AutofillExternalDelegate::OnPingAck)
IPC_MESSAGE_FORWARD(AutofillHostMsg_DidFillAutofillFormData,
autofill_manager_.get(),
AutofillManager::OnDidFillAutofillFormData)
diff --git a/components/autofill/content/browser/content_autofill_driver.h b/components/autofill/content/browser/content_autofill_driver.h
index ea21879..5fde045 100644
--- a/components/autofill/content/browser/content_autofill_driver.h
+++ b/components/autofill/content/browser/content_autofill_driver.h
@@ -50,6 +50,7 @@ class ContentAutofillDriver : public AutofillDriver,
virtual void SendFormDataToRenderer(int query_id,
RendererFormDataAction action,
const FormData& data) OVERRIDE;
+ virtual void PingRenderer() OVERRIDE;
virtual void SendAutofillTypePredictionsToRenderer(
const std::vector<FormStructure*>& forms) OVERRIDE;
virtual void RendererShouldAcceptDataListSuggestion(
diff --git a/components/autofill/content/common/autofill_messages.h b/components/autofill/content/common/autofill_messages.h
index cb9fc6a..f9a99fe 100644
--- a/components/autofill/content/common/autofill_messages.h
+++ b/components/autofill/content/common/autofill_messages.h
@@ -94,6 +94,11 @@ IPC_ENUM_TRAITS_MAX_VALUE(
// Autofill messages sent from the browser to the renderer.
+// Instructs the renderer to immediately return an IPC acknowledging the ping.
+// This is used to correctly sequence events, since IPCs are guaranteed to be
+// processed in order.
+IPC_MESSAGE_ROUTED0(AutofillMsg_Ping)
+
// Instructs the renderer to fill the active form with the given form data.
IPC_MESSAGE_ROUTED2(AutofillMsg_FillForm,
int /* query_id */,
@@ -227,6 +232,9 @@ IPC_MESSAGE_ROUTED5(AutofillHostMsg_QueryFormFieldAutofill,
// Sent when a form is previewed with Autofill suggestions.
IPC_MESSAGE_ROUTED0(AutofillHostMsg_DidPreviewAutofillFormData)
+// Sent immediately after the renderer receives a ping IPC.
+IPC_MESSAGE_ROUTED0(AutofillHostMsg_PingAck)
+
// Sent when a form is filled with Autofill suggestions.
IPC_MESSAGE_ROUTED1(AutofillHostMsg_DidFillAutofillFormData,
base::TimeTicks /* timestamp */)
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc
index bcc9a4a..bfd5731 100644
--- a/components/autofill/content/renderer/autofill_agent.cc
+++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -150,6 +150,7 @@ AutofillAgent::~AutofillAgent() {}
bool AutofillAgent::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(AutofillAgent, message)
+ IPC_MESSAGE_HANDLER(AutofillMsg_Ping, OnPing)
IPC_MESSAGE_HANDLER(AutofillMsg_FillForm, OnFillForm)
IPC_MESSAGE_HANDLER(AutofillMsg_PreviewForm, OnPreviewForm)
IPC_MESSAGE_HANDLER(AutofillMsg_FieldTypePredictionsAvailable,
@@ -454,6 +455,10 @@ void AutofillAgent::OnFillForm(int query_id, const FormData& form) {
base::TimeTicks::Now()));
}
+void AutofillAgent::OnPing() {
+ Send(new AutofillHostMsg_PingAck(routing_id()));
+}
+
void AutofillAgent::OnPreviewForm(int query_id, const FormData& form) {
if (!render_view()->GetWebView() || query_id != autofill_query_id_)
return;
diff --git a/components/autofill/content/renderer/autofill_agent.h b/components/autofill/content/renderer/autofill_agent.h
index 54a7c46..dafcd70 100644
--- a/components/autofill/content/renderer/autofill_agent.h
+++ b/components/autofill/content/renderer/autofill_agent.h
@@ -97,6 +97,7 @@ class AutofillAgent : public content::RenderViewObserver,
void OnFieldTypePredictionsAvailable(
const std::vector<FormDataPredictions>& forms);
void OnFillForm(int query_id, const FormData& form);
+ void OnPing();
void OnPreviewForm(int query_id, const FormData& form);
// For external Autofill selection.
diff --git a/components/autofill/core/browser/autofill_driver.h b/components/autofill/core/browser/autofill_driver.h
index efc5696..748ad6e 100644
--- a/components/autofill/core/browser/autofill_driver.h
+++ b/components/autofill/core/browser/autofill_driver.h
@@ -58,6 +58,9 @@ class AutofillDriver {
RendererFormDataAction action,
const FormData& data) = 0;
+ // Pings renderer. The renderer will return an IPC acknowledging the ping.
+ virtual void PingRenderer() = 0;
+
// Sends the field type predictions specified in |forms| to the renderer. This
// method is a no-op if the renderer is not available or the appropriate
// command-line flag is not set.
@@ -81,7 +84,6 @@ class AutofillDriver {
// Tells the renderer to preview the node with suggested text.
virtual void RendererShouldPreviewFieldWithValue(
const base::string16& value) = 0;
-
};
} // namespace autofill
diff --git a/components/autofill/core/browser/autofill_external_delegate.cc b/components/autofill/core/browser/autofill_external_delegate.cc
index 2337878..b8e4a06 100644
--- a/components/autofill/core/browser/autofill_external_delegate.cc
+++ b/components/autofill/core/browser/autofill_external_delegate.cc
@@ -4,6 +4,7 @@
#include "components/autofill/core/browser/autofill_external_delegate.h"
+#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autocomplete_history_manager.h"
#include "components/autofill/core/browser/autofill_driver.h"
@@ -14,9 +15,8 @@
namespace autofill {
-AutofillExternalDelegate::AutofillExternalDelegate(
- AutofillManager* manager,
- AutofillDriver* driver)
+AutofillExternalDelegate::AutofillExternalDelegate(AutofillManager* manager,
+ AutofillDriver* driver)
: manager_(manager),
driver_(driver),
query_id_(0),
@@ -91,6 +91,18 @@ void AutofillExternalDelegate::OnSuggestionsReturned(
// updated to match.
InsertDataListValues(&values, &labels, &icons, &ids);
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ if (values.empty() &&
+ manager_->ShouldShowAccessAddressBookSuggestion(query_form_,
+ query_field_)) {
+ values.push_back(
+ l10n_util::GetStringUTF16(IDS_AUTOFILL_ACCESS_MAC_CONTACTS));
+ labels.push_back(base::string16());
+ icons.push_back(base::string16());
+ ids.push_back(POPUP_ITEM_ID_MAC_ACCESS_CONTACTS);
+ }
+#endif
+
if (values.empty()) {
// No suggestions, any popup currently showing is obsolete.
manager_->delegate()->HideAutofillPopup();
@@ -157,6 +169,38 @@ void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value,
} else if (identifier == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY) {
// User selected an Autocomplete, so we fill directly.
driver_->RendererShouldFillFieldWithValue(value);
+ } else if (identifier == POPUP_ITEM_ID_MAC_ACCESS_CONTACTS) {
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ // User wants to give Chrome access to user's address book.
+ manager_->AccessAddressBook();
+
+ // There is no deterministic method for deciding whether a blocking dialog
+ // was presented. The following comments and code assume that a blocking
+ // dialog was presented, but still behave correctly if no dialog was
+ // presented.
+
+ // A blocking dialog was presented, and the user has already responded to
+ // the dialog. The presentation of the dialog added an NSEvent to the
+ // NSRunLoop which will cause all windows to lose focus. When the NSEvent
+ // is processed, it will be sent to the renderer which will cause the text
+ // field to lose focus. This returns an IPC to Chrome which will dismiss
+ // the autofill popup. We post a task which we expect to run after the
+ // NSEvent has been processed by the NSRunLoop. It pings the renderer,
+ // which returns an IPC acknowledging the ping. At that time, redisplay
+ // the popup. FIFO processing of IPCs ensures that all side effects of the
+ // NSEvent will have been processed.
+
+ // 10ms sits nicely under the 16ms threshold for 60 fps, and likely gives
+ // the NSApplication run loop sufficient time to process the NSEvent. In
+ // testing, a delay of 0ms was always sufficient.
+ base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10));
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&AutofillExternalDelegate::PingRenderer, GetWeakPtr()),
+ delay);
+#else
+ NOTREACHED();
+#endif
} else {
FillAutofillFormData(identifier, false);
}
@@ -186,6 +230,15 @@ void AutofillExternalDelegate::Reset() {
manager_->delegate()->HideAutofillPopup();
}
+void AutofillExternalDelegate::OnPingAck() {
+ // Reissue the most recent query, which will reopen the autofill popup.
+ manager_->OnQueryFormFieldAutofill(query_id_,
+ query_form_,
+ query_field_,
+ element_bounds_,
+ display_warning_if_disabled_);
+}
+
base::WeakPtr<AutofillExternalDelegate> AutofillExternalDelegate::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
@@ -308,4 +361,10 @@ void AutofillExternalDelegate::InsertDataListValues(
POPUP_ITEM_ID_DATALIST_ENTRY);
}
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+void AutofillExternalDelegate::PingRenderer() {
+ driver_->PingRenderer();
+}
+#endif
+
} // namespace autofill
diff --git a/components/autofill/core/browser/autofill_external_delegate.h b/components/autofill/core/browser/autofill_external_delegate.h
index 672b2d6..3994f64 100644
--- a/components/autofill/core/browser/autofill_external_delegate.h
+++ b/components/autofill/core/browser/autofill_external_delegate.h
@@ -80,6 +80,9 @@ class AutofillExternalDelegate
// values or settings.
void Reset();
+ // The renderer sent an IPC acknowledging an earlier ping IPC.
+ void OnPingAck();
+
protected:
base::WeakPtr<AutofillExternalDelegate> GetWeakPtr();
@@ -111,6 +114,11 @@ class AutofillExternalDelegate
std::vector<base::string16>* icons,
std::vector<int>* unique_ids);
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ // Pings the renderer.
+ void PingRenderer();
+#endif
+
AutofillManager* manager_; // weak.
// Provides driver-level context to the shared code of the component. Must
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index 511b160..8bceedd 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -240,6 +240,28 @@ void AutofillManager::ShowAutofillSettings() {
manager_delegate_->ShowAutofillSettings();
}
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+bool AutofillManager::ShouldShowAccessAddressBookSuggestion(
+ const FormData& form,
+ const FormFieldData& field) {
+ if (!personal_data_)
+ return false;
+ FormStructure* form_structure = NULL;
+ AutofillField* autofill_field = NULL;
+ if (!GetCachedFormAndField(form, field, &form_structure, &autofill_field))
+ return false;
+
+ return personal_data_->ShouldShowAccessAddressBookSuggestion(
+ autofill_field->Type());
+}
+
+bool AutofillManager::AccessAddressBook() {
+ if (!personal_data_)
+ return false;
+ return personal_data_->AccessAddressBook();
+}
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+
bool AutofillManager::OnFormSubmitted(const FormData& form,
const TimeTicks& timestamp) {
if (!IsValidFormData(form))
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h
index 856be0e..84455d2 100644
--- a/components/autofill/core/browser/autofill_manager.h
+++ b/components/autofill/core/browser/autofill_manager.h
@@ -84,6 +84,19 @@ class AutofillManager : public AutofillDownloadManager::Observer {
void ShowAutofillSettings();
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ // Whether the field represented by |fieldData| should show an entry to prompt
+ // the user to give Chrome access to the user's address book.
+ bool ShouldShowAccessAddressBookSuggestion(const FormData& data,
+ const FormFieldData& field_data);
+
+ // If Chrome has not prompted for access to the user's address book, the
+ // method prompts the user for permission and blocks the process. Otherwise,
+ // this method has no effect. The return value reflects whether the user was
+ // prompted with a modal dialog.
+ bool AccessAddressBook();
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+
// Called from our external delegate so they cannot be private.
virtual void FillOrPreviewForm(AutofillDriver::RendererFormDataAction action,
int query_id,
diff --git a/components/autofill/core/browser/personal_data_manager.h b/components/autofill/core/browser/personal_data_manager.h
index 9ddc98e..e82e1a7 100644
--- a/components/autofill/core/browser/personal_data_manager.h
+++ b/components/autofill/core/browser/personal_data_manager.h
@@ -200,6 +200,18 @@ class PersonalDataManager : public KeyedService,
// will only update when Chrome is restarted.
virtual const std::string& GetDefaultCountryCodeForNewAddress() const;
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ // If Chrome has not prompted for access to the user's address book, the
+ // method prompts the user for permission and blocks the process. Otherwise,
+ // this method has no effect. The return value reflects whether the user was
+ // prompted with a modal dialog.
+ bool AccessAddressBook();
+
+ // Whether an autofill suggestion should be displayed to prompt the user to
+ // grant Chrome access to the user's address book.
+ bool ShouldShowAccessAddressBookSuggestion(AutofillType type);
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+
protected:
// Only PersonalDataManagerFactory and certain tests can create instances of
// PersonalDataManager.
diff --git a/components/autofill/core/browser/personal_data_manager_mac.mm b/components/autofill/core/browser/personal_data_manager_mac.mm
index 8cae978..b5d4753 100644
--- a/components/autofill/core/browser/personal_data_manager_mac.mm
+++ b/components/autofill/core/browser/personal_data_manager_mac.mm
@@ -21,8 +21,10 @@
#include "components/autofill/core/browser/autofill_country.h"
#include "components/autofill/core/browser/autofill_profile.h"
#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/phone_number.h"
#include "components/autofill/core/common/autofill_pref_names.h"
+#include "components/autofill/core/common/form_data.h"
#include "grit/components_strings.h"
#include "ui/base/l10n/l10n_util_mac.h"
@@ -31,6 +33,33 @@ namespace {
const char kAddressBookOrigin[] = "OS X Address Book";
+// Whether Chrome has prompted the user for permission to access the user's
+// address book.
+bool HasPromptedForAccessToAddressBook(PrefService* pref_service) {
+ return pref_service->GetBoolean(prefs::kAutofillAuxiliaryProfilesQueried);
+}
+
+ABAddressBook* GetAddressBook(PrefService* pref_service) {
+ bool first_access = !HasPromptedForAccessToAddressBook(pref_service);
+
+ // +[ABAddressBook sharedAddressBook] throws an exception internally in
+ // circumstances that aren't clear. The exceptions are only observed in crash
+ // reports, so it is unknown whether they would be caught by AppKit and nil
+ // returned, or if they would take down the app. In either case, avoid
+ // crashing. http://crbug.com/129022
+ ABAddressBook* addressBook = base::mac::RunBlockIgnoringExceptions(
+ ^{ return [ABAddressBook sharedAddressBook]; });
+ UMA_HISTOGRAM_BOOLEAN("Autofill.AddressBookAvailable", addressBook != nil);
+
+ if (first_access) {
+ UMA_HISTOGRAM_BOOLEAN("Autofill.AddressBookAvailableOnFirstAttempt",
+ addressBook != nil);
+ }
+
+ pref_service->SetBoolean(prefs::kAutofillAuxiliaryProfilesQueried, true);
+ return addressBook;
+}
+
// This implementation makes use of the Address Book API. Profiles are
// generated that correspond to addresses in the "me" card that reside in the
// user's Address Book. The caller passes a vector of profiles into the
@@ -81,20 +110,13 @@ void AuxiliaryProfilesImpl::GetAddressBookMeCard(const std::string& app_locale,
PrefService* pref_service) {
profiles_.clear();
- // +[ABAddressBook sharedAddressBook] throws an exception internally in
- // circumstances that aren't clear. The exceptions are only observed in crash
- // reports, so it is unknown whether they would be caught by AppKit and nil
- // returned, or if they would take down the app. In either case, avoid
- // crashing. http://crbug.com/129022
- ABAddressBook* addressBook = base::mac::RunBlockIgnoringExceptions(^{
- return [ABAddressBook sharedAddressBook];
- });
- UMA_HISTOGRAM_BOOLEAN("Autofill.AddressBookAvailable", addressBook != nil);
- if (!pref_service->GetBoolean(prefs::kAutofillAuxiliaryProfilesQueried)) {
- pref_service->SetBoolean(prefs::kAutofillAuxiliaryProfilesQueried, true);
- UMA_HISTOGRAM_BOOLEAN("Autofill.AddressBookAvailableOnFirstAttempt",
- addressBook != nil);
- }
+ // Chrome has not yet requested address book permissions. Attempting to do so
+ // presents a blocking modal dialog, which is undesirable. Instead, just show
+ // no results.
+ if (!HasPromptedForAccessToAddressBook(pref_service))
+ return;
+
+ ABAddressBook* addressBook = GetAddressBook(pref_service);
ABPerson* me = [addressBook me];
if (!me)
@@ -281,4 +303,43 @@ void PersonalDataManager::LoadAuxiliaryProfiles() const {
impl.GetAddressBookMeCard(app_locale_, pref_service_);
}
+bool PersonalDataManager::AccessAddressBook() {
+ if (!pref_service_->GetBoolean(prefs::kAutofillAuxiliaryProfilesEnabled))
+ return false;
+
+ if (HasPromptedForAccessToAddressBook(pref_service_))
+ return false;
+
+ // Request permissions.
+ GetAddressBook(pref_service_);
+ return true;
+}
+
+bool PersonalDataManager::ShouldShowAccessAddressBookSuggestion(
+ AutofillType type) {
+ if (!pref_service_->GetBoolean(prefs::kAutofillAuxiliaryProfilesEnabled))
+ return false;
+
+ if (HasPromptedForAccessToAddressBook(pref_service_))
+ return false;
+
+ switch (type.group()) {
+ case ADDRESS_BILLING:
+ case ADDRESS_HOME:
+ case EMAIL:
+ case NAME:
+ case NAME_BILLING:
+ case PHONE_BILLING:
+ case PHONE_HOME:
+ return true;
+ case NO_GROUP:
+ case COMPANY:
+ case CREDIT_CARD:
+ case PASSWORD_FIELD:
+ return false;
+ }
+
+ return false;
+}
+
} // namespace autofill
diff --git a/components/autofill/core/browser/popup_item_ids.h b/components/autofill/core/browser/popup_item_ids.h
index 628e000..7a8e843 100644
--- a/components/autofill/core/browser/popup_item_ids.h
+++ b/components/autofill/core/browser/popup_item_ids.h
@@ -16,7 +16,8 @@ enum PopupItemId {
POPUP_ITEM_ID_SEPARATOR = -3,
POPUP_ITEM_ID_CLEAR_FORM = -4,
POPUP_ITEM_ID_AUTOFILL_OPTIONS = -5,
- POPUP_ITEM_ID_DATALIST_ENTRY = -6
+ POPUP_ITEM_ID_DATALIST_ENTRY = -6,
+ POPUP_ITEM_ID_MAC_ACCESS_CONTACTS = -7,
};
} // namespace autofill
diff --git a/components/autofill/core/browser/test_autofill_driver.cc b/components/autofill/core/browser/test_autofill_driver.cc
index ad796c0..f67c1b1 100644
--- a/components/autofill/core/browser/test_autofill_driver.cc
+++ b/components/autofill/core/browser/test_autofill_driver.cc
@@ -39,6 +39,8 @@ void TestAutofillDriver::SendFormDataToRenderer(int query_id,
const FormData& form_data) {
}
+void TestAutofillDriver::PingRenderer() {}
+
void TestAutofillDriver::SendAutofillTypePredictionsToRenderer(
const std::vector<FormStructure*>& forms) {
}
diff --git a/components/autofill/core/browser/test_autofill_driver.h b/components/autofill/core/browser/test_autofill_driver.h
index e515ca7..34a8552 100644
--- a/components/autofill/core/browser/test_autofill_driver.h
+++ b/components/autofill/core/browser/test_autofill_driver.h
@@ -32,6 +32,7 @@ class TestAutofillDriver : public AutofillDriver {
virtual void SendFormDataToRenderer(int query_id,
RendererFormDataAction action,
const FormData& data) OVERRIDE;
+ virtual void PingRenderer() OVERRIDE;
virtual void SendAutofillTypePredictionsToRenderer(
const std::vector<FormStructure*>& forms) OVERRIDE;
virtual void RendererShouldAcceptDataListSuggestion(
diff --git a/components/autofill_strings.grdp b/components/autofill_strings.grdp
index f8e5332..9e1db3f 100644
--- a/components/autofill_strings.grdp
+++ b/components/autofill_strings.grdp
@@ -110,4 +110,11 @@
This type of card is not supported by Google Wallet for this merchant. Please select a different card.
</message>
+ <!-- Autofill on OSX -->
+ <if expr="is_macosx">
+ <message name="IDS_AUTOFILL_ACCESS_MAC_CONTACTS" desc="When the user selects this Autofill entry, the browser prompts the user for access to the user's OSX contacts.">
+ Enable Autofill using Contacts…
+ </message>
+ </if>
+
</grit-part>