summaryrefslogtreecommitdiffstats
path: root/components/autofill
diff options
context:
space:
mode:
authorerikchen@chromium.org <erikchen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-12 12:49:15 +0000
committererikchen@chromium.org <erikchen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-12 12:49:15 +0000
commit8527a78f1482a20d3e4deef87f97335d4a2ff565 (patch)
tree2451be5591918455145cf2ceff9ad3f9a0411256 /components/autofill
parent30ea1296c8d4958df079a9232a4516bc8aad266e (diff)
downloadchromium_src-8527a78f1482a20d3e4deef87f97335d4a2ff565.zip
chromium_src-8527a78f1482a20d3e4deef87f97335d4a2ff565.tar.gz
chromium_src-8527a78f1482a20d3e4deef87f97335d4a2ff565.tar.bz2
Revert "Revert 3 mac autofill CLs."
The reverted CLs are no longer suspected of causing a renderer crash. https://code.google.com/p/chromium/issues/detail?id=382144 This reverts commit dbf46869b07c09eb74515ba2c8e9a727b0a09c65. TBR=isherman@chromium.org BUG=382144 Review URL: https://codereview.chromium.org/329293002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@276643 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'components/autofill')
-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.cc101
-rw-r--r--components/autofill/core/browser/autofill_external_delegate.h8
-rw-r--r--components/autofill/core/browser/autofill_manager.cc67
-rw-r--r--components/autofill/core/browser/autofill_manager.h17
-rw-r--r--components/autofill/core/browser/autofill_manager_unittest.cc14
-rw-r--r--components/autofill/core/browser/autofill_test_utils.cc11
-rw-r--r--components/autofill/core/browser/personal_data_manager.cc8
-rw-r--r--components/autofill/core/browser/personal_data_manager.h12
-rw-r--r--components/autofill/core/browser/personal_data_manager_mac.mm90
-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/core/common/autofill_pref_names.cc21
-rw-r--r--components/autofill/core/common/autofill_pref_names.h3
20 files changed, 346 insertions, 41 deletions
diff --git a/components/autofill/content/browser/content_autofill_driver.cc b/components/autofill/content/browser/content_autofill_driver.cc
index af74877..6707177 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 0bb6934..e0294f5 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 6d48fb5..525bc3f 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,
@@ -455,6 +456,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 bd66234..57777c8 100644
--- a/components/autofill/core/browser/autofill_external_delegate.cc
+++ b/components/autofill/core/browser/autofill_external_delegate.cc
@@ -4,6 +4,8 @@
#include "components/autofill/core/browser/autofill_external_delegate.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram.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"
@@ -12,11 +14,35 @@
#include "grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+namespace {
+
+enum AccessAddressBookEventType {
+ // An Autofill entry was shown that prompts the user to give Chrome access to
+ // the user's Address Book.
+ SHOWED_ACCESS_ADDRESS_BOOK_ENTRY = 0,
+
+ // The user selected the Autofill entry which prompts Chrome to access the
+ // user's Address Book.
+ SELECTED_ACCESS_ADDRESS_BOOK_ENTRY = 1,
+
+ // Always keep this at the end.
+ ACCESS_ADDRESS_BOOK_ENTRY_MAX,
+};
+
+// Emits an entry for the histogram.
+void EmitHistogram(AccessAddressBookEventType type) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Autofill.MacAddressBook", type, ACCESS_ADDRESS_BOOK_ENTRY_MAX);
+}
+
+} // namespace
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+
namespace autofill {
-AutofillExternalDelegate::AutofillExternalDelegate(
- AutofillManager* manager,
- AutofillDriver* driver)
+AutofillExternalDelegate::AutofillExternalDelegate(AutofillManager* manager,
+ AutofillDriver* driver)
: manager_(manager),
driver_(driver),
query_id_(0),
@@ -91,6 +117,20 @@ 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::ASCIIToUTF16("macContactsIcon"));
+ ids.push_back(POPUP_ITEM_ID_MAC_ACCESS_CONTACTS);
+
+ EmitHistogram(SHOWED_ACCESS_ADDRESS_BOOK_ENTRY);
+ }
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+
if (values.empty()) {
// No suggestions, any popup currently showing is obsolete.
manager_->client()->HideAutofillPopup();
@@ -155,6 +195,40 @@ 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)
+ EmitHistogram(SELECTED_ACCESS_ADDRESS_BOOK_ENTRY);
+
+ // 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 // defined(OS_MACOSX) && !defined(OS_IOS)
} else {
FillAutofillFormData(identifier, false);
}
@@ -184,6 +258,15 @@ void AutofillExternalDelegate::Reset() {
manager_->client()->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();
}
@@ -217,7 +300,7 @@ void AutofillExternalDelegate::ApplyAutofillWarnings(
// suggestions to show, show a warning instead. Otherwise, clear out the
// list of suggestions.
if (!unique_ids->empty() && (*unique_ids)[0] > 0) {
- // If autofill is disabled and we had suggestions, show a warning instead.
+ // If Autofill is disabled and we had suggestions, show a warning instead.
values->assign(
1, l10n_util::GetStringUTF16(IDS_AUTOFILL_WARNING_FORM_DISABLED));
labels->assign(1, base::string16());
@@ -231,8 +314,8 @@ void AutofillExternalDelegate::ApplyAutofillWarnings(
}
} else if (unique_ids->size() > 1 &&
(*unique_ids)[0] == POPUP_ITEM_ID_WARNING_MESSAGE) {
- // If we received a warning instead of suggestions from autofill but regular
- // suggestions from autocomplete, don't show the autofill warning.
+ // If we received a warning instead of suggestions from Autofill but regular
+ // suggestions from autocomplete, don't show the Autofill warning.
values->erase(values->begin());
labels->erase(labels->begin());
icons->erase(icons->begin());
@@ -306,4 +389,10 @@ void AutofillExternalDelegate::InsertDataListValues(
POPUP_ITEM_ID_DATALIST_ENTRY);
}
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+void AutofillExternalDelegate::PingRenderer() {
+ driver_->PingRenderer();
+}
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+
} // namespace autofill
diff --git a/components/autofill/core/browser/autofill_external_delegate.h b/components/autofill/core/browser/autofill_external_delegate.h
index 672b2d6..b1e4111 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 // defined(OS_MACOSX) && !defined(OS_IOS)
+
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 50ed127..370a8f0 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -212,7 +212,7 @@ void AutofillManager::RegisterProfilePrefs(
#endif // defined(OS_MACOSX) || defined(OS_ANDROID)
#if defined(OS_MACOSX)
registry->RegisterBooleanPref(
- prefs::kAutofillAuxiliaryProfilesQueried,
+ prefs::kAutofillMacAddressBookQueried,
false,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
#endif // defined(OS_MACOSX)
@@ -224,7 +224,50 @@ void AutofillManager::RegisterProfilePrefs(
prefs::kAutofillNegativeUploadRate,
kAutofillNegativeUploadRateDefaultValue,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ registry->RegisterBooleanPref(
+ prefs::kAutofillUseMacAddressBook,
+ false,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+}
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+void AutofillManager::MigrateUserPrefs(PrefService* prefs) {
+ const PrefService::Preference* pref =
+ prefs->FindPreference(prefs::kAutofillUseMacAddressBook);
+
+ // If the pref is not its default value, then the migration has already been
+ // performed.
+ if (!pref->IsDefaultValue())
+ return;
+
+ // Whether Chrome has already tried to access the user's Address Book.
+ const PrefService::Preference* pref_accessed =
+ prefs->FindPreference(prefs::kAutofillMacAddressBookQueried);
+ // Whether the user wants to use the Address Book to populate Autofill.
+ const PrefService::Preference* pref_enabled =
+ prefs->FindPreference(prefs::kAutofillAuxiliaryProfilesEnabled);
+
+ if (pref_accessed->IsDefaultValue() && pref_enabled->IsDefaultValue()) {
+ // This is likely a new user. Reset the default value to prevent the
+ // migration from happening again.
+ prefs->SetBoolean(prefs::kAutofillUseMacAddressBook,
+ prefs->GetBoolean(prefs::kAutofillUseMacAddressBook));
+ return;
+ }
+
+ bool accessed;
+ bool enabled;
+ bool success = pref_accessed->GetValue()->GetAsBoolean(&accessed);
+ DCHECK(success);
+ success = pref_enabled->GetValue()->GetAsBoolean(&enabled);
+ DCHECK(success);
+
+ prefs->SetBoolean(prefs::kAutofillUseMacAddressBook, accessed && enabled);
}
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
void AutofillManager::SetExternalDelegate(AutofillExternalDelegate* delegate) {
// TODO(jrg): consider passing delegate into the ctor. That won't
@@ -238,6 +281,28 @@ void AutofillManager::ShowAutofillSettings() {
client_->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 b179606..120b14d 100644
--- a/components/autofill/core/browser/autofill_manager.h
+++ b/components/autofill/core/browser/autofill_manager.h
@@ -73,6 +73,10 @@ class AutofillManager : public AutofillDownloadManager::Observer {
// Registers our Enable/Disable Autofill pref.
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ static void MigrateUserPrefs(PrefService* prefs);
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+
AutofillManager(AutofillDriver* driver,
AutofillClient* client,
const std::string& app_locale,
@@ -84,6 +88,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/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc
index 731e58a..a8d3573 100644
--- a/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -1551,8 +1551,14 @@ TEST_F(AutofillManagerTest, FillAddressForm) {
// Test that we correctly fill an address form from an auxiliary profile.
TEST_F(AutofillManagerTest, FillAddressFormFromAuxiliaryProfile) {
personal_data_.ClearAutofillProfiles();
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ autofill_client_.GetPrefs()->SetBoolean(
+ ::autofill::prefs::kAutofillUseMacAddressBook, true);
+#else
autofill_client_.GetPrefs()->SetBoolean(
::autofill::prefs::kAutofillAuxiliaryProfilesEnabled, true);
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+
personal_data_.CreateTestAuxiliaryProfiles();
// Set up our form data.
@@ -2474,12 +2480,12 @@ TEST_F(AutofillManagerTest, AuxiliaryProfilesReset) {
PrefService* prefs = autofill_client_.GetPrefs();
#if defined(OS_MACOSX) || defined(OS_ANDROID)
// Auxiliary profiles is implemented on Mac and Android only.
- // OSX: enables Mac Address Book integration.
+ // OSX: This preference exists for legacy reasons. It is no longer used.
// Android: enables integration with user's contact profile.
ASSERT_TRUE(
prefs->GetBoolean(::autofill::prefs::kAutofillAuxiliaryProfilesEnabled));
- prefs->SetBoolean(
- ::autofill::prefs::kAutofillAuxiliaryProfilesEnabled, false);
+ prefs->SetBoolean(::autofill::prefs::kAutofillAuxiliaryProfilesEnabled,
+ false);
prefs->ClearPref(::autofill::prefs::kAutofillAuxiliaryProfilesEnabled);
ASSERT_TRUE(
prefs->GetBoolean(::autofill::prefs::kAutofillAuxiliaryProfilesEnabled));
@@ -2490,7 +2496,7 @@ TEST_F(AutofillManagerTest, AuxiliaryProfilesReset) {
prefs->ClearPref(::autofill::prefs::kAutofillAuxiliaryProfilesEnabled);
ASSERT_FALSE(
prefs->GetBoolean(::autofill::prefs::kAutofillAuxiliaryProfilesEnabled));
-#endif
+#endif // defined(OS_MACOSX) || defined(OS_ANDROID)
}
TEST_F(AutofillManagerTest, DeterminePossibleFieldTypesForUpload) {
diff --git a/components/autofill/core/browser/autofill_test_utils.cc b/components/autofill/core/browser/autofill_test_utils.cc
index 081defa..0393d86 100644
--- a/components/autofill/core/browser/autofill_test_utils.cc
+++ b/components/autofill/core/browser/autofill_test_utils.cc
@@ -206,12 +206,17 @@ void DisableSystemServices(PrefService* prefs) {
// Use a mock Keychain rather than the OS one to store credit card data.
#if defined(OS_MACOSX)
OSCrypt::UseMockKeychain(true);
-#endif
+#endif // defined(OS_MACOSX)
- // Disable auxiliary profiles for unit testing. These reach out to system
- // services on the Mac.
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ // Don't use the Address Book on Mac, as it reaches out to system services.
+ if (prefs)
+ prefs->SetBoolean(prefs::kAutofillUseMacAddressBook, false);
+#else
+ // Disable auxiliary profiles for unit testing by default.
if (prefs)
prefs->SetBoolean(prefs::kAutofillAuxiliaryProfilesEnabled, false);
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
}
} // namespace test
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index 1d4173e..5454b1c 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -525,9 +525,13 @@ bool PersonalDataManager::IsDataLoaded() const {
}
const std::vector<AutofillProfile*>& PersonalDataManager::GetProfiles() const {
- if (!pref_service_->GetBoolean(prefs::kAutofillAuxiliaryProfilesEnabled)) {
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ if (!pref_service_->GetBoolean(prefs::kAutofillUseMacAddressBook))
return web_profiles();
- }
+#else
+ if (!pref_service_->GetBoolean(prefs::kAutofillAuxiliaryProfilesEnabled))
+ return web_profiles();
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
profiles_.clear();
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..2be22fc 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,39 @@ 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::kAutofillMacAddressBookQueried);
+}
+
+// Whether the user wants Chrome to use the AddressBook to populate Autofill
+// entries.
+bool ShouldUseAddressBook(PrefService* pref_service) {
+ return pref_service->GetBoolean(prefs::kAutofillUseMacAddressBook);
+}
+
+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::kAutofillMacAddressBookQueried, 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 +116,12 @@ 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);
- }
+ // The user does not want Chrome to use the AddressBook to populate Autofill
+ // entries.
+ if (!ShouldUseAddressBook(pref_service))
+ return;
+
+ ABAddressBook* addressBook = GetAddressBook(pref_service);
ABPerson* me = [addressBook me];
if (!me)
@@ -281,4 +308,39 @@ void PersonalDataManager::LoadAuxiliaryProfiles() const {
impl.GetAddressBookMeCard(app_locale_, pref_service_);
}
+bool PersonalDataManager::AccessAddressBook() {
+ // The user is attempting to give Chrome access to the user's Address Book.
+ // This implicitly acknowledges that the user wants to use auxiliary
+ // profiles.
+ pref_service_->SetBoolean(prefs::kAutofillUseMacAddressBook, true);
+
+ // Request permissions.
+ GetAddressBook(pref_service_);
+ return true;
+}
+
+bool PersonalDataManager::ShouldShowAccessAddressBookSuggestion(
+ AutofillType type) {
+ 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/core/common/autofill_pref_names.cc b/components/autofill/core/common/autofill_pref_names.cc
index d7385bb3..f35cb77 100644
--- a/components/autofill/core/common/autofill_pref_names.cc
+++ b/components/autofill/core/common/autofill_pref_names.cc
@@ -7,25 +7,30 @@
namespace autofill {
namespace prefs {
-// Boolean that is true when auxiliary Autofill profiles are enabled.
-// Currently applies to Address Book "me" card on Mac. False on Win and Linux.
+// Boolean that is true when auxiliary Autofill profiles are enabled. This pref
+// is only relevant to Android.
const char kAutofillAuxiliaryProfilesEnabled[] =
"autofill.auxiliary_profiles_enabled";
-// Boolean that is true when at least one read request for auxiliary Autofill
-// profiles has been issued. Currently applies only to auxiliary profiles on
-// Mac.
-const char kAutofillAuxiliaryProfilesQueried[] =
- "autofill.auxiliary_profiles_queried";
-
// Boolean that is true if Autofill is enabled and allowed to save profile data.
const char kAutofillEnabled[] = "autofill.enabled";
+// Boolean that is true when Chrome has attempted to access the user's Address
+// Book on Mac. This preference is important since the first time Chrome
+// attempts to access the user's Address Book, Cocoa presents a blocking dialog
+// to the user.
+const char kAutofillMacAddressBookQueried[] =
+ "autofill.auxiliary_profiles_queried";
+
// Double that indicates negative (for not matched forms) upload rate.
const char kAutofillNegativeUploadRate[] = "autofill.negative_upload_rate";
// Double that indicates positive (for matched forms) upload rate.
const char kAutofillPositiveUploadRate[] = "autofill.positive_upload_rate";
+// Whether Autofill should try to use the Mac Address Book. If this value is
+// true, then kAutofillMacAddressBookQueried is expected to also be true.
+const char kAutofillUseMacAddressBook[] = "autofill.use_mac_address_book";
+
} // namespace prefs
} // namespace autofill
diff --git a/components/autofill/core/common/autofill_pref_names.h b/components/autofill/core/common/autofill_pref_names.h
index 50af375f..fb580a6 100644
--- a/components/autofill/core/common/autofill_pref_names.h
+++ b/components/autofill/core/common/autofill_pref_names.h
@@ -11,10 +11,11 @@ namespace prefs {
// Alphabetical list of preference names specific to the Autofill
// component. Keep alphabetized, and document each in the .cc file.
extern const char kAutofillAuxiliaryProfilesEnabled[];
-extern const char kAutofillAuxiliaryProfilesQueried[];
extern const char kAutofillEnabled[];
+extern const char kAutofillMacAddressBookQueried[];
extern const char kAutofillNegativeUploadRate[];
extern const char kAutofillPositiveUploadRate[];
+extern const char kAutofillUseMacAddressBook[];
} // namespace prefs
} // namespace autofill