OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/autofill/core/browser/personal_data_manager.h" | 5 #include "components/autofill/core/browser/personal_data_manager.h" |
6 | 6 |
7 #include <math.h> | 7 #include <math.h> |
8 | 8 |
9 #import <AddressBook/AddressBook.h> | 9 #import <AddressBook/AddressBook.h> |
10 | 10 |
(...skipping 13 matching lines...) Expand all Loading... |
24 #include "components/autofill/core/browser/form_structure.h" | 24 #include "components/autofill/core/browser/form_structure.h" |
25 #include "components/autofill/core/browser/phone_number.h" | 25 #include "components/autofill/core/browser/phone_number.h" |
26 #include "components/autofill/core/common/autofill_pref_names.h" | 26 #include "components/autofill/core/common/autofill_pref_names.h" |
27 #include "components/autofill/core/common/form_data.h" | 27 #include "components/autofill/core/common/form_data.h" |
28 #include "grit/components_strings.h" | 28 #include "grit/components_strings.h" |
29 #include "ui/base/l10n/l10n_util_mac.h" | 29 #include "ui/base/l10n/l10n_util_mac.h" |
30 | 30 |
31 namespace autofill { | 31 namespace autofill { |
32 namespace { | 32 namespace { |
33 | 33 |
| 34 // There is an uncommon sequence of events that causes the Address Book |
| 35 // permissions dialog to appear more than once for a given install of Chrome. |
| 36 // 1. Chrome has previously presented the Address Book permissions dialog. |
| 37 // 2. Chrome is launched. |
| 38 // 3. Chrome performs an auto-update, and changes its binary. |
| 39 // 4. Chrome attempts to access the Address Book for the first time since (2). |
| 40 // This sequence of events is rare because Chrome attempts to acess the Address |
| 41 // Book when the user focuses most form fields, so (4) generally occurs before |
| 42 // (3). For more details, see crbug.com/381763. |
| 43 // |
| 44 // When this sequence of events does occur, Chrome should not attempt to access |
| 45 // the Address Book unless the user explicitly asks Chrome to do so. The |
| 46 // jarring nature of the permissions dialog is worse than the potential benefit |
| 47 // of pulling information from the Address Book. |
| 48 // |
| 49 // This variable is set to true after the Address Book is accessed for the |
| 50 // first time. |
| 51 static bool g_accessed_address_book = false; |
| 52 // This variable is set to true after the Chrome binary has been changed. |
| 53 static bool g_binary_changed = false; |
| 54 // Metrics for skipping the prompt are only recorded once per launch of Chrome. |
| 55 static bool g_recorded_skip_metrics = false; |
| 56 |
34 const char kAddressBookOrigin[] = "OS X Address Book"; | 57 const char kAddressBookOrigin[] = "OS X Address Book"; |
35 | 58 |
36 // Whether Chrome has prompted the user for permission to access the user's | 59 // Whether Chrome has prompted the user for permission to access the user's |
37 // address book. | 60 // address book. |
38 bool HasPromptedForAccessToAddressBook(PrefService* pref_service) { | 61 bool HasPromptedForAccessToAddressBook(PrefService* pref_service) { |
39 return pref_service->GetBoolean(prefs::kAutofillMacAddressBookQueried); | 62 return pref_service->GetBoolean(prefs::kAutofillMacAddressBookQueried); |
40 } | 63 } |
41 | 64 |
42 // Whether the user wants Chrome to use the AddressBook to populate Autofill | 65 // Whether the user wants Chrome to use the AddressBook to populate Autofill |
43 // entries. | 66 // entries. |
44 bool ShouldUseAddressBook(PrefService* pref_service) { | 67 bool ShouldUseAddressBook(PrefService* pref_service) { |
45 return pref_service->GetBoolean(prefs::kAutofillUseMacAddressBook); | 68 return pref_service->GetBoolean(prefs::kAutofillUseMacAddressBook); |
46 } | 69 } |
47 | 70 |
| 71 // Records a UMA metric indicating whether an attempt to access the Address |
| 72 // Book was skipped beccause doing so would cause the Address Book permissions |
| 73 // prompt to incorrectly appear. |
| 74 void RecordSkipReprompt(bool skip) { |
| 75 if (g_recorded_skip_metrics) |
| 76 return; |
| 77 g_recorded_skip_metrics = true; |
| 78 UMA_HISTOGRAM_BOOLEAN("Autofill.AddressBookReprompt", skip); |
| 79 } |
| 80 |
48 ABAddressBook* GetAddressBook(PrefService* pref_service) { | 81 ABAddressBook* GetAddressBook(PrefService* pref_service) { |
49 bool first_access = !HasPromptedForAccessToAddressBook(pref_service); | 82 bool first_access = !HasPromptedForAccessToAddressBook(pref_service); |
50 | 83 |
51 // +[ABAddressBook sharedAddressBook] throws an exception internally in | 84 // +[ABAddressBook sharedAddressBook] throws an exception internally in |
52 // circumstances that aren't clear. The exceptions are only observed in crash | 85 // circumstances that aren't clear. The exceptions are only observed in crash |
53 // reports, so it is unknown whether they would be caught by AppKit and nil | 86 // reports, so it is unknown whether they would be caught by AppKit and nil |
54 // returned, or if they would take down the app. In either case, avoid | 87 // returned, or if they would take down the app. In either case, avoid |
55 // crashing. http://crbug.com/129022 | 88 // crashing. http://crbug.com/129022 |
56 ABAddressBook* addressBook = base::mac::RunBlockIgnoringExceptions( | 89 ABAddressBook* addressBook = base::mac::RunBlockIgnoringExceptions( |
57 ^{ return [ABAddressBook sharedAddressBook]; }); | 90 ^{ return [ABAddressBook sharedAddressBook]; }); |
58 UMA_HISTOGRAM_BOOLEAN("Autofill.AddressBookAvailable", addressBook != nil); | 91 UMA_HISTOGRAM_BOOLEAN("Autofill.AddressBookAvailable", addressBook != nil); |
59 | 92 |
60 if (first_access) { | 93 if (first_access) { |
61 UMA_HISTOGRAM_BOOLEAN("Autofill.AddressBookAvailableOnFirstAttempt", | 94 UMA_HISTOGRAM_BOOLEAN("Autofill.AddressBookAvailableOnFirstAttempt", |
62 addressBook != nil); | 95 addressBook != nil); |
63 } | 96 } |
64 | 97 |
| 98 g_accessed_address_book = true; |
65 pref_service->SetBoolean(prefs::kAutofillMacAddressBookQueried, true); | 99 pref_service->SetBoolean(prefs::kAutofillMacAddressBookQueried, true); |
66 return addressBook; | 100 return addressBook; |
67 } | 101 } |
68 | 102 |
69 // This implementation makes use of the Address Book API. Profiles are | 103 // This implementation makes use of the Address Book API. Profiles are |
70 // generated that correspond to addresses in the "me" card that reside in the | 104 // generated that correspond to addresses in the "me" card that reside in the |
71 // user's Address Book. The caller passes a vector of profiles into the | 105 // user's Address Book. The caller passes a vector of profiles into the |
72 // the constructer and then initiate the fetch from the Mac Address Book "me" | 106 // the constructer and then initiate the fetch from the Mac Address Book "me" |
73 // card using the main |GetAddressBookMeCard()| method. This clears any | 107 // card using the main |GetAddressBookMeCard()| method. This clears any |
74 // existing addresses and populates new addresses derived from the data found | 108 // existing addresses and populates new addresses derived from the data found |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
114 // structures. | 148 // structures. |
115 void AuxiliaryProfilesImpl::GetAddressBookMeCard(const std::string& app_locale, | 149 void AuxiliaryProfilesImpl::GetAddressBookMeCard(const std::string& app_locale, |
116 PrefService* pref_service) { | 150 PrefService* pref_service) { |
117 profiles_.clear(); | 151 profiles_.clear(); |
118 | 152 |
119 // The user does not want Chrome to use the AddressBook to populate Autofill | 153 // The user does not want Chrome to use the AddressBook to populate Autofill |
120 // entries. | 154 // entries. |
121 if (!ShouldUseAddressBook(pref_service)) | 155 if (!ShouldUseAddressBook(pref_service)) |
122 return; | 156 return; |
123 | 157 |
| 158 // See the comment at the definition of g_accessed_address_book for an |
| 159 // explanation of this logic. |
| 160 if (g_binary_changed && !g_accessed_address_book) { |
| 161 RecordSkipReprompt(true); |
| 162 return; |
| 163 } |
| 164 RecordSkipReprompt(false); |
| 165 |
124 ABAddressBook* addressBook = GetAddressBook(pref_service); | 166 ABAddressBook* addressBook = GetAddressBook(pref_service); |
125 | 167 |
126 ABPerson* me = [addressBook me]; | 168 ABPerson* me = [addressBook me]; |
127 if (!me) | 169 if (!me) |
128 return; | 170 return; |
129 | 171 |
130 ABMultiValue* addresses = [me valueForProperty:kABAddressProperty]; | 172 ABMultiValue* addresses = [me valueForProperty:kABAddressProperty]; |
131 | 173 |
132 // The number of characters at the end of the GUID to reserve for | 174 // The number of characters at the end of the GUID to reserve for |
133 // distinguishing addresses within the "me" card. Cap the number of addresses | 175 // distinguishing addresses within the "me" card. Cap the number of addresses |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
336 case NO_GROUP: | 378 case NO_GROUP: |
337 case COMPANY: | 379 case COMPANY: |
338 case CREDIT_CARD: | 380 case CREDIT_CARD: |
339 case PASSWORD_FIELD: | 381 case PASSWORD_FIELD: |
340 return false; | 382 return false; |
341 } | 383 } |
342 | 384 |
343 return false; | 385 return false; |
344 } | 386 } |
345 | 387 |
| 388 void PersonalDataManager::BinaryChanging() { |
| 389 g_binary_changed = true; |
| 390 } |
| 391 |
346 } // namespace autofill | 392 } // namespace autofill |
OLD | NEW |