Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(221)

Side by Side Diff: chrome/browser/autofill/personal_data_manager_mac.mm

Issue 12434004: Move remaining Autofill code to //components/autofill. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix long lines Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/autofill/personal_data_manager.h"
6
7 #include <math.h>
8
9 #import <AddressBook/AddressBook.h>
10
11 #include "base/format_macros.h"
12 #include "base/guid.h"
13 #include "base/logging.h"
14 #import "base/mac/scoped_nsexception_enabler.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/memory/scoped_vector.h"
17 #include "base/stringprintf.h"
18 #include "base/sys_string_conversions.h"
19 #include "chrome/browser/autofill/autofill_country.h"
20 #include "chrome/browser/autofill/autofill_profile.h"
21 #include "chrome/browser/autofill/phone_number.h"
22 #include "grit/generated_resources.h"
23 #include "ui/base/l10n/l10n_util_mac.h"
24
25 namespace {
26
27 // This implementation makes use of the Address Book API. Profiles are
28 // generated that correspond to addresses in the "me" card that reside in the
29 // user's Address Book. The caller passes a vector of profiles into the
30 // the constructer and then initiate the fetch from the Mac Address Book "me"
31 // card using the main |GetAddressBookMeCard()| method. This clears any
32 // existing addresses and populates new addresses derived from the data found
33 // in the "me" card.
34 class AuxiliaryProfilesImpl {
35 public:
36 // Constructor takes a reference to the |profiles| that will be filled in
37 // by the subsequent call to |GetAddressBookMeCard()|. |profiles| may not
38 // be NULL.
39 explicit AuxiliaryProfilesImpl(ScopedVector<AutofillProfile>* profiles)
40 : profiles_(*profiles) {
41 }
42 virtual ~AuxiliaryProfilesImpl() {}
43
44 // Import the "me" card from the Mac Address Book and fill in |profiles_|.
45 void GetAddressBookMeCard();
46
47 private:
48 void GetAddressBookNames(ABPerson* me,
49 NSString* addressLabelRaw,
50 AutofillProfile* profile);
51 void GetAddressBookAddress(NSDictionary* address, AutofillProfile* profile);
52 void GetAddressBookEmail(ABPerson* me,
53 NSString* addressLabelRaw,
54 AutofillProfile* profile);
55 void GetAddressBookPhoneNumbers(ABPerson* me,
56 NSString* addressLabelRaw,
57 AutofillProfile* profile);
58
59 private:
60 // A reference to the profiles this class populates.
61 ScopedVector<AutofillProfile>& profiles_;
62
63 DISALLOW_COPY_AND_ASSIGN(AuxiliaryProfilesImpl);
64 };
65
66 // This method uses the |ABAddressBook| system service to fetch the "me" card
67 // from the active user's address book. It looks for the user address
68 // information and translates it to the internal list of |AutofillProfile| data
69 // structures.
70 void AuxiliaryProfilesImpl::GetAddressBookMeCard() {
71 profiles_.clear();
72
73 // +[ABAddressBook sharedAddressBook] throws an exception internally in
74 // circumstances that aren't clear. The exceptions are only observed in crash
75 // reports, so it is unknown whether they would be caught by AppKit and nil
76 // returned, or if they would take down the app. In either case, avoid
77 // crashing. http://crbug.com/129022
78 ABAddressBook* addressBook = base::mac::RunBlockIgnoringExceptions(^{
79 return [ABAddressBook sharedAddressBook];
80 });
81 ABPerson* me = [addressBook me];
82 if (!me)
83 return;
84
85 ABMultiValue* addresses = [me valueForProperty:kABAddressProperty];
86
87 // The number of characters at the end of the GUID to reserve for
88 // distinguishing addresses within the "me" card. Cap the number of addresses
89 // we will fetch to the number that can be distinguished by this fragment of
90 // the GUID.
91 const size_t kNumAddressGUIDChars = 2;
92 const size_t kNumHexDigits = 16;
93 const size_t kMaxAddressCount = pow(kNumHexDigits, kNumAddressGUIDChars);
94 NSUInteger count = MIN([addresses count], kMaxAddressCount);
95 for (NSUInteger i = 0; i < count; i++) {
96 NSDictionary* address = [addresses valueAtIndex:i];
97 NSString* addressLabelRaw = [addresses labelAtIndex:i];
98
99 // Create a new profile where the guid is set to the guid portion of the
100 // |kABUIDProperty| taken from from the "me" address. The format of
101 // the |kABUIDProperty| is "<guid>:ABPerson", so we're stripping off the
102 // raw guid here and using it directly, with one modification: we update the
103 // last |kNumAddressGUIDChars| characters in the GUID to reflect the address
104 // variant. Note that we capped the number of addresses above, so this is
105 // safe.
106 const size_t kGUIDLength = 36U;
107 const size_t kTrimmedGUIDLength = kGUIDLength - kNumAddressGUIDChars;
108 std::string guid = base::SysNSStringToUTF8(
109 [me valueForProperty:kABUIDProperty]).substr(0, kTrimmedGUIDLength);
110
111 // The format string to print |kNumAddressGUIDChars| hexadecimal characters,
112 // left-padded with 0's.
113 const std::string kAddressGUIDFormat =
114 base::StringPrintf("%%0%" PRIuS "X", kNumAddressGUIDChars);
115 guid += base::StringPrintf(kAddressGUIDFormat.c_str(), i);
116 DCHECK_EQ(kGUIDLength, guid.size());
117
118 scoped_ptr<AutofillProfile> profile(new AutofillProfile(guid));
119 DCHECK(base::IsValidGUID(profile->guid()));
120
121 // Fill in name and company information.
122 GetAddressBookNames(me, addressLabelRaw, profile.get());
123
124 // Fill in address information.
125 GetAddressBookAddress(address, profile.get());
126
127 // Fill in email information.
128 GetAddressBookEmail(me, addressLabelRaw, profile.get());
129
130 // Fill in phone number information.
131 GetAddressBookPhoneNumbers(me, addressLabelRaw, profile.get());
132
133 profiles_.push_back(profile.release());
134 }
135 }
136
137 // Name and company information is stored once in the Address Book against
138 // multiple addresses. We replicate that information for each profile.
139 // We only propagate the company name to work profiles.
140 void AuxiliaryProfilesImpl::GetAddressBookNames(
141 ABPerson* me,
142 NSString* addressLabelRaw,
143 AutofillProfile* profile) {
144 NSString* firstName = [me valueForProperty:kABFirstNameProperty];
145 NSString* middleName = [me valueForProperty:kABMiddleNameProperty];
146 NSString* lastName = [me valueForProperty:kABLastNameProperty];
147 NSString* companyName = [me valueForProperty:kABOrganizationProperty];
148
149 profile->SetRawInfo(NAME_FIRST, base::SysNSStringToUTF16(firstName));
150 profile->SetRawInfo(NAME_MIDDLE, base::SysNSStringToUTF16(middleName));
151 profile->SetRawInfo(NAME_LAST, base::SysNSStringToUTF16(lastName));
152 if ([addressLabelRaw isEqualToString:kABAddressWorkLabel])
153 profile->SetRawInfo(COMPANY_NAME, base::SysNSStringToUTF16(companyName));
154 }
155
156 // Addresss information from the Address Book may span multiple lines.
157 // If it does then we represent the address with two lines in the profile. The
158 // second line we join with commas.
159 // For example: "c/o John Doe\n1122 Other Avenue\nApt #7" translates to
160 // line 1: "c/o John Doe", line 2: "1122 Other Avenue, Apt #7".
161 void AuxiliaryProfilesImpl::GetAddressBookAddress(NSDictionary* address,
162 AutofillProfile* profile) {
163 if (NSString* addressField = [address objectForKey:kABAddressStreetKey]) {
164 // If there are newlines in the address, split into two lines.
165 if ([addressField rangeOfCharacterFromSet:
166 [NSCharacterSet newlineCharacterSet]].location != NSNotFound) {
167 NSArray* chunks = [addressField componentsSeparatedByCharactersInSet:
168 [NSCharacterSet newlineCharacterSet]];
169 DCHECK([chunks count] > 1);
170
171 NSString* separator = l10n_util::GetNSString(
172 IDS_AUTOFILL_MAC_ADDRESS_LINE_SEPARATOR);
173
174 NSString* addressField1 = [chunks objectAtIndex:0];
175 NSString* addressField2 =
176 [[chunks subarrayWithRange:NSMakeRange(1, [chunks count] - 1)]
177 componentsJoinedByString:separator];
178 profile->SetRawInfo(ADDRESS_HOME_LINE1,
179 base::SysNSStringToUTF16(addressField1));
180 profile->SetRawInfo(ADDRESS_HOME_LINE2,
181 base::SysNSStringToUTF16(addressField2));
182 } else {
183 profile->SetRawInfo(ADDRESS_HOME_LINE1,
184 base::SysNSStringToUTF16(addressField));
185 }
186 }
187
188 if (NSString* city = [address objectForKey:kABAddressCityKey])
189 profile->SetRawInfo(ADDRESS_HOME_CITY, base::SysNSStringToUTF16(city));
190
191 if (NSString* state = [address objectForKey:kABAddressStateKey])
192 profile->SetRawInfo(ADDRESS_HOME_STATE, base::SysNSStringToUTF16(state));
193
194 if (NSString* zip = [address objectForKey:kABAddressZIPKey])
195 profile->SetRawInfo(ADDRESS_HOME_ZIP, base::SysNSStringToUTF16(zip));
196
197 if (NSString* country = [address objectForKey:kABAddressCountryKey]) {
198 profile->SetInfo(ADDRESS_HOME_COUNTRY,
199 base::SysNSStringToUTF16(country),
200 AutofillCountry::ApplicationLocale());
201 }
202 }
203
204 // Fills in email address matching current address label. Note that there may
205 // be multiple matching email addresses for a given label. We take the
206 // first we find (topmost) as preferred.
207 void AuxiliaryProfilesImpl::GetAddressBookEmail(
208 ABPerson* me,
209 NSString* addressLabelRaw,
210 AutofillProfile* profile) {
211 ABMultiValue* emailAddresses = [me valueForProperty:kABEmailProperty];
212 NSString* emailAddress = nil;
213 for (NSUInteger j = 0, emailCount = [emailAddresses count];
214 j < emailCount; j++) {
215 NSString* emailAddressLabelRaw = [emailAddresses labelAtIndex:j];
216 if ([emailAddressLabelRaw isEqualToString:addressLabelRaw]) {
217 emailAddress = [emailAddresses valueAtIndex:j];
218 break;
219 }
220 }
221 profile->SetRawInfo(EMAIL_ADDRESS, base::SysNSStringToUTF16(emailAddress));
222 }
223
224 // Fills in telephone numbers. Each of these are special cases.
225 // We match two cases: home/tel, work/tel.
226 // Note, we traverse in reverse order so that top values in address book
227 // take priority.
228 void AuxiliaryProfilesImpl::GetAddressBookPhoneNumbers(
229 ABPerson* me,
230 NSString* addressLabelRaw,
231 AutofillProfile* profile) {
232 ABMultiValue* phoneNumbers = [me valueForProperty:kABPhoneProperty];
233 for (NSUInteger k = 0, phoneCount = [phoneNumbers count];
234 k < phoneCount; k++) {
235 NSUInteger reverseK = phoneCount - k - 1;
236 NSString* phoneLabelRaw = [phoneNumbers labelAtIndex:reverseK];
237 if ([addressLabelRaw isEqualToString:kABAddressHomeLabel] &&
238 [phoneLabelRaw isEqualToString:kABPhoneHomeLabel]) {
239 string16 homePhone = base::SysNSStringToUTF16(
240 [phoneNumbers valueAtIndex:reverseK]);
241 profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER, homePhone);
242 } else if ([addressLabelRaw isEqualToString:kABAddressWorkLabel] &&
243 [phoneLabelRaw isEqualToString:kABPhoneWorkLabel]) {
244 string16 workPhone = base::SysNSStringToUTF16(
245 [phoneNumbers valueAtIndex:reverseK]);
246 profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER, workPhone);
247 } else if ([phoneLabelRaw isEqualToString:kABPhoneMobileLabel] ||
248 [phoneLabelRaw isEqualToString:kABPhoneMainLabel]) {
249 string16 phone = base::SysNSStringToUTF16(
250 [phoneNumbers valueAtIndex:reverseK]);
251 profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER, phone);
252 }
253 }
254 }
255
256 } // namespace
257
258 // Populate |auxiliary_profiles_| with the Address Book data.
259 void PersonalDataManager::LoadAuxiliaryProfiles() {
260 AuxiliaryProfilesImpl impl(&auxiliary_profiles_);
261 impl.GetAddressBookMeCard();
262 }
OLDNEW
« no previous file with comments | « chrome/browser/autofill/personal_data_manager_factory.cc ('k') | chrome/browser/autofill/personal_data_manager_observer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698