OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "chrome/browser/sync/glue/autofill_model_associator.h" | 5 #include "chrome/browser/sync/glue/autofill_model_associator.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/task.h" | 9 #include "base/task.h" |
10 #include "base/time.h" | 10 #include "base/time.h" |
11 #include "base/string_number_conversions.h" | 11 #include "base/string_number_conversions.h" |
12 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
13 #include "chrome/browser/autofill/autofill_profile.h" | 13 #include "chrome/browser/autofill/autofill_profile.h" |
14 #include "chrome/browser/browser_thread.h" | 14 #include "chrome/browser/browser_thread.h" |
| 15 #include "chrome/browser/guid.h" |
15 #include "chrome/browser/profile.h" | 16 #include "chrome/browser/profile.h" |
16 #include "chrome/browser/sync/engine/syncapi.h" | 17 #include "chrome/browser/sync/engine/syncapi.h" |
17 #include "chrome/browser/sync/glue/autofill_change_processor.h" | 18 #include "chrome/browser/sync/glue/autofill_change_processor.h" |
18 #include "chrome/browser/sync/profile_sync_service.h" | 19 #include "chrome/browser/sync/profile_sync_service.h" |
19 #include "chrome/browser/sync/protocol/autofill_specifics.pb.h" | 20 #include "chrome/browser/sync/protocol/autofill_specifics.pb.h" |
20 #include "chrome/browser/webdata/web_database.h" | 21 #include "chrome/browser/webdata/web_database.h" |
21 #include "net/base/escape.h" | 22 #include "net/base/escape.h" |
22 | 23 |
23 using base::TimeTicks; | 24 using base::TimeTicks; |
24 | 25 |
25 namespace browser_sync { | 26 namespace browser_sync { |
26 | 27 |
27 const char kAutofillTag[] = "google_chrome_autofill"; | 28 const char kAutofillTag[] = "google_chrome_autofill"; |
28 const char kAutofillEntryNamespaceTag[] = "autofill_entry|"; | 29 const char kAutofillEntryNamespaceTag[] = "autofill_entry|"; |
29 const char kAutofillProfileNamespaceTag[] = "autofill_profile|"; | |
30 | |
31 static const int kMaxNumAttemptsToFindUniqueLabel = 100; | |
32 | 30 |
33 struct AutofillModelAssociator::DataBundle { | 31 struct AutofillModelAssociator::DataBundle { |
34 std::set<AutofillKey> current_entries; | 32 std::set<AutofillKey> current_entries; |
35 std::vector<AutofillEntry> new_entries; | 33 std::vector<AutofillEntry> new_entries; |
36 std::set<string16> current_profiles; | 34 std::set<string16> current_profiles; |
37 std::vector<AutoFillProfile*> updated_profiles; | 35 std::vector<AutoFillProfile*> updated_profiles; |
38 std::vector<AutoFillProfile*> new_profiles; // We own these pointers. | 36 std::vector<AutoFillProfile*> new_profiles; // We own these pointers. |
39 ~DataBundle() { STLDeleteElements(&new_profiles); } | 37 ~DataBundle() { STLDeleteElements(&new_profiles); } |
40 }; | 38 }; |
41 | 39 |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
116 node.SetTitle(UTF8ToWide(tag)); | 114 node.SetTitle(UTF8ToWide(tag)); |
117 AutofillChangeProcessor::WriteAutofillEntry(*ix, &node); | 115 AutofillChangeProcessor::WriteAutofillEntry(*ix, &node); |
118 Associate(&tag, node.GetId()); | 116 Associate(&tag, node.GetId()); |
119 } | 117 } |
120 | 118 |
121 current_entries->insert(ix->key()); | 119 current_entries->insert(ix->key()); |
122 } | 120 } |
123 return true; | 121 return true; |
124 } | 122 } |
125 | 123 |
126 bool AutofillModelAssociator::TraverseAndAssociateChromeAutoFillProfiles( | |
127 sync_api::WriteTransaction* write_trans, | |
128 const sync_api::ReadNode& autofill_root, | |
129 const std::vector<AutoFillProfile*>& all_profiles_from_db, | |
130 std::set<string16>* current_profiles, | |
131 std::vector<AutoFillProfile*>* updated_profiles) { | |
132 const std::vector<AutoFillProfile*>& profiles = all_profiles_from_db; | |
133 for (std::vector<AutoFillProfile*>::const_iterator ix = profiles.begin(); | |
134 ix != profiles.end(); ++ix) { | |
135 string16 label((*ix)->Label()); | |
136 std::string tag(ProfileLabelToTag(label)); | |
137 | |
138 sync_api::ReadNode node(write_trans); | |
139 if (node.InitByClientTagLookup(syncable::AUTOFILL, tag)) { | |
140 const sync_pb::AutofillSpecifics& autofill(node.GetAutofillSpecifics()); | |
141 DCHECK(autofill.has_profile()); | |
142 DCHECK_EQ(ProfileLabelToTag(UTF8ToUTF16(autofill.profile().label())), | |
143 tag); | |
144 int64 sync_id = node.GetId(); | |
145 if (id_map_.find(tag) != id_map_.end()) { | |
146 // We just looked up something we already associated. Move aside. | |
147 label = MakeUniqueLabel(label, string16(), write_trans); | |
148 if (label.empty()) { | |
149 return false; | |
150 } | |
151 tag = ProfileLabelToTag(label); | |
152 // TODO(dhollowa): Replace with |AutoFillProfile::set_guid|. | |
153 // http://crbug.com/58813 | |
154 (*ix)->set_label(label); | |
155 if (!MakeNewAutofillProfileSyncNode(write_trans, autofill_root, | |
156 tag, **ix, &sync_id)) { | |
157 return false; | |
158 } | |
159 updated_profiles->push_back(*ix); | |
160 } else { | |
161 // Overwrite local with cloud state. | |
162 if (OverwriteProfileWithServerData(*ix, autofill.profile())) | |
163 updated_profiles->push_back(*ix); | |
164 sync_id = node.GetId(); | |
165 } | |
166 | |
167 Associate(&tag, sync_id); | |
168 } else { | |
169 int64 id; | |
170 if (!MakeNewAutofillProfileSyncNode(write_trans, autofill_root, | |
171 tag, **ix, &id)) { | |
172 return false; | |
173 } | |
174 Associate(&tag, id); | |
175 } | |
176 current_profiles->insert(label); | |
177 } | |
178 return true; | |
179 } | |
180 | |
181 // static | |
182 string16 AutofillModelAssociator::MakeUniqueLabel( | |
183 const string16& non_unique_label, | |
184 const string16& existing_unique_label, | |
185 sync_api::BaseTransaction* trans) { | |
186 if (!non_unique_label.empty() && non_unique_label == existing_unique_label) { | |
187 return existing_unique_label; | |
188 } | |
189 int unique_id = 1; // Priming so we start by appending "2". | |
190 while (unique_id++ < kMaxNumAttemptsToFindUniqueLabel) { | |
191 string16 suffix(base::IntToString16(unique_id)); | |
192 string16 unique_label = non_unique_label + suffix; | |
193 if (unique_label == existing_unique_label) | |
194 return unique_label; // We'll use the one we already have. | |
195 sync_api::ReadNode node(trans); | |
196 if (node.InitByClientTagLookup(syncable::AUTOFILL, | |
197 ProfileLabelToTag(unique_label))) { | |
198 continue; | |
199 } | |
200 return unique_label; | |
201 } | |
202 | |
203 LOG(ERROR) << "Couldn't create unique tag for autofill node. Srsly?!"; | |
204 return string16(); | |
205 } | |
206 | |
207 bool AutofillModelAssociator::MakeNewAutofillProfileSyncNode( | 124 bool AutofillModelAssociator::MakeNewAutofillProfileSyncNode( |
208 sync_api::WriteTransaction* trans, const sync_api::BaseNode& autofill_root, | 125 sync_api::WriteTransaction* trans, const sync_api::BaseNode& autofill_root, |
209 const std::string& tag, const AutoFillProfile& profile, int64* sync_id) { | 126 const std::string& tag, const AutoFillProfile& profile, int64* sync_id) { |
210 sync_api::WriteNode node(trans); | 127 sync_api::WriteNode node(trans); |
211 if (!node.InitUniqueByCreation(syncable::AUTOFILL, autofill_root, tag)) { | 128 if (!node.InitUniqueByCreation(syncable::AUTOFILL, autofill_root, tag)) { |
212 LOG(ERROR) << "Failed to create autofill sync node."; | 129 LOG(ERROR) << "Failed to create autofill sync node."; |
213 return false; | 130 return false; |
214 } | 131 } |
215 node.SetTitle(UTF8ToWide(tag)); | 132 node.SetTitle(UTF8ToWide(tag)); |
216 AutofillChangeProcessor::WriteAutofillProfile(profile, &node); | 133 AutofillChangeProcessor::WriteAutofillProfile(profile, &node); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 sync_service_->backend()->GetUserShareHandle()); | 175 sync_service_->backend()->GetUserShareHandle()); |
259 | 176 |
260 sync_api::ReadNode autofill_root(&trans); | 177 sync_api::ReadNode autofill_root(&trans); |
261 if (!autofill_root.InitByTagLookup(kAutofillTag)) { | 178 if (!autofill_root.InitByTagLookup(kAutofillTag)) { |
262 LOG(ERROR) << "Server did not create the top-level autofill node. We " | 179 LOG(ERROR) << "Server did not create the top-level autofill node. We " |
263 << "might be running against an out-of-date server."; | 180 << "might be running against an out-of-date server."; |
264 return false; | 181 return false; |
265 } | 182 } |
266 | 183 |
267 if (!TraverseAndAssociateChromeAutofillEntries(&trans, autofill_root, | 184 if (!TraverseAndAssociateChromeAutofillEntries(&trans, autofill_root, |
268 entries, &bundle.current_entries, &bundle.new_entries) || | 185 entries, &bundle.current_entries, &bundle.new_entries)) { |
269 !TraverseAndAssociateChromeAutoFillProfiles(&trans, autofill_root, | 186 return false; |
270 profiles.get(), &bundle.current_profiles, | 187 } |
271 &bundle.updated_profiles) || | 188 if(IsUpgrading()) { |
272 !TraverseAndAssociateAllSyncNodes(&trans, autofill_root, &bundle)) { | 189 if(!TraverseAndAssociateAllSyncNodes( |
273 return false; | 190 &trans, |
| 191 autofill_root, |
| 192 &bundle, |
| 193 profiles.get())) { |
| 194 return false; |
| 195 } |
274 } | 196 } |
275 } | 197 } |
276 | 198 |
277 // Since we're on the DB thread, we don't have to worry about updating | 199 // Since we're on the DB thread, we don't have to worry about updating |
278 // the autofill database after closing the write transaction, since | 200 // the autofill database after closing the write transaction, since |
279 // this is the only thread that writes to the database. We also don't have | 201 // this is the only thread that writes to the database. We also don't have |
280 // to worry about the sync model getting out of sync, because changes are | 202 // to worry about the sync model getting out of sync, because changes are |
281 // propogated to the ChangeProcessor on this thread. | 203 // propogated to the ChangeProcessor on this thread. |
282 if (!SaveChangesToWebData(bundle)) { | 204 if (!SaveChangesToWebData(bundle)) { |
283 LOG(ERROR) << "Failed to update autofill entries."; | 205 LOG(ERROR) << "Failed to update autofill entries."; |
(...skipping 28 matching lines...) Expand all Loading... |
312 return false; | 234 return false; |
313 if (!web_database_->UpdateAutoFillProfile(*bundle.updated_profiles[i])) | 235 if (!web_database_->UpdateAutoFillProfile(*bundle.updated_profiles[i])) |
314 return false; | 236 return false; |
315 } | 237 } |
316 return true; | 238 return true; |
317 } | 239 } |
318 | 240 |
319 bool AutofillModelAssociator::TraverseAndAssociateAllSyncNodes( | 241 bool AutofillModelAssociator::TraverseAndAssociateAllSyncNodes( |
320 sync_api::WriteTransaction* write_trans, | 242 sync_api::WriteTransaction* write_trans, |
321 const sync_api::ReadNode& autofill_root, | 243 const sync_api::ReadNode& autofill_root, |
322 DataBundle* bundle) { | 244 DataBundle* bundle, |
| 245 std::vector<AutoFillProfile*>& all_profiles_from_db) { |
323 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
324 | 247 |
325 int64 sync_child_id = autofill_root.GetFirstChildId(); | 248 int64 sync_child_id = autofill_root.GetFirstChildId(); |
326 while (sync_child_id != sync_api::kInvalidId) { | 249 while (sync_child_id != sync_api::kInvalidId) { |
327 sync_api::ReadNode sync_child(write_trans); | 250 sync_api::ReadNode sync_child(write_trans); |
328 if (!sync_child.InitByIdLookup(sync_child_id)) { | 251 if (!sync_child.InitByIdLookup(sync_child_id)) { |
329 LOG(ERROR) << "Failed to fetch child node."; | 252 LOG(ERROR) << "Failed to fetch child node."; |
330 return false; | 253 return false; |
331 } | 254 } |
332 const sync_pb::AutofillSpecifics& autofill( | 255 const sync_pb::AutofillSpecifics& autofill( |
333 sync_child.GetAutofillSpecifics()); | 256 sync_child.GetAutofillSpecifics()); |
334 | 257 |
335 if (autofill.has_value()) | 258 if (autofill.has_value()) |
336 AddNativeEntryIfNeeded(autofill, bundle, sync_child); | 259 AddNativeEntryIfNeeded(autofill, bundle, sync_child); |
337 else if (autofill.has_profile()) | 260 else if (autofill.has_profile()) { |
338 AddNativeProfileIfNeeded(autofill.profile(), bundle, sync_child); | 261 DCHECK(IsUpgrading()); |
| 262 AddNativeProfileIfNeeded( |
| 263 autofill.profile(), |
| 264 bundle, sync_child, |
| 265 all_profiles_from_db); |
| 266 } |
339 else | 267 else |
340 NOTREACHED() << "AutofillSpecifics has no autofill data!"; | 268 NOTREACHED() << "AutofillSpecifics has no autofill data!"; |
341 | 269 |
342 sync_child_id = sync_child.GetSuccessorId(); | 270 sync_child_id = sync_child.GetSuccessorId(); |
343 } | 271 } |
344 return true; | 272 return true; |
345 } | 273 } |
346 | 274 |
| 275 // [TODO] fix the p1 and p2. |
| 276 bool CompareAutofillProfiles(const AutoFillProfile& p1, |
| 277 const AutoFillProfile& p2) |
| 278 { |
| 279 if(p1.Compare(p2) == 0) |
| 280 return true; |
| 281 else return false; |
| 282 } |
| 283 |
| 284 // Define the functor to be used as the predicate in find_if call. |
| 285 struct CompareProfiles : |
| 286 public std::binary_function<AutoFillProfile*, |
| 287 AutoFillProfile*, |
| 288 bool> { |
| 289 bool operator() (AutoFillProfile* p1, AutoFillProfile* p2) const { |
| 290 return CompareAutofillProfiles(*p1, *p2); |
| 291 } |
| 292 |
| 293 }; |
| 294 |
| 295 AutoFillProfile* AutofillModelAssociator::FindCorrespondingNodeFromWebDB( |
| 296 const sync_pb::AutofillProfileSpecifics& profile, |
| 297 const std::vector<AutoFillProfile*>& all_profiles_from_db) { |
| 298 |
| 299 static std::string guid(guid::GenerateGUID()); |
| 300 AutoFillProfile p; |
| 301 p.set_guid(guid); |
| 302 if(!OverwriteProfileWithServerData(&p, profile)) |
| 303 { |
| 304 // Not a big deal. We encountered an error. Just say this profile does not |
| 305 // exist. |
| 306 LOG(ERROR) << " Profile could not be associated"; |
| 307 return NULL; |
| 308 } |
| 309 |
| 310 // Now instantiate the functor and call find_if. |
| 311 std::vector<AutoFillProfile*>::const_iterator ix = |
| 312 std::find_if(all_profiles_from_db.begin(), |
| 313 all_profiles_from_db.end(), |
| 314 std::bind2nd(CompareProfiles(), &p)); |
| 315 |
| 316 return (ix == all_profiles_from_db.end()) ? NULL : *ix; |
| 317 } |
| 318 |
347 void AutofillModelAssociator::AddNativeEntryIfNeeded( | 319 void AutofillModelAssociator::AddNativeEntryIfNeeded( |
348 const sync_pb::AutofillSpecifics& autofill, DataBundle* bundle, | 320 const sync_pb::AutofillSpecifics& autofill, DataBundle* bundle, |
349 const sync_api::ReadNode& node) { | 321 const sync_api::ReadNode& node) { |
350 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
351 AutofillKey key(UTF8ToUTF16(autofill.name()), UTF8ToUTF16(autofill.value())); | 323 AutofillKey key(UTF8ToUTF16(autofill.name()), UTF8ToUTF16(autofill.value())); |
352 | 324 |
353 if (bundle->current_entries.find(key) == bundle->current_entries.end()) { | 325 if (bundle->current_entries.find(key) == bundle->current_entries.end()) { |
354 std::vector<base::Time> timestamps; | 326 std::vector<base::Time> timestamps; |
355 int timestamps_count = autofill.usage_timestamp_size(); | 327 int timestamps_count = autofill.usage_timestamp_size(); |
356 for (int c = 0; c < timestamps_count; ++c) { | 328 for (int c = 0; c < timestamps_count; ++c) { |
357 timestamps.push_back(base::Time::FromInternalValue( | 329 timestamps.push_back(base::Time::FromInternalValue( |
358 autofill.usage_timestamp(c))); | 330 autofill.usage_timestamp(c))); |
359 } | 331 } |
360 std::string tag(KeyToTag(key.name(), key.value())); | 332 std::string tag(KeyToTag(key.name(), key.value())); |
361 Associate(&tag, node.GetId()); | 333 Associate(&tag, node.GetId()); |
362 bundle->new_entries.push_back(AutofillEntry(key, timestamps)); | 334 bundle->new_entries.push_back(AutofillEntry(key, timestamps)); |
363 } | 335 } |
364 } | 336 } |
365 | 337 |
366 void AutofillModelAssociator::AddNativeProfileIfNeeded( | 338 void AutofillModelAssociator::AddNativeProfileIfNeeded( |
367 const sync_pb::AutofillProfileSpecifics& profile, DataBundle* bundle, | 339 const sync_pb::AutofillProfileSpecifics& profile, |
368 const sync_api::ReadNode& node) { | 340 DataBundle* bundle, |
| 341 const sync_api::ReadNode& node, |
| 342 std::vector<AutoFillProfile*>& all_profiles_from_db) { |
| 343 |
369 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 344 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
370 if (bundle->current_profiles.find(UTF8ToUTF16(profile.label())) == | 345 |
371 bundle->current_profiles.end()) { | 346 scoped_ptr<AutoFillProfile> profile_in_web_db(FindCorrespondingNodeFromWebDB( |
372 std::string tag(ProfileLabelToTag(UTF8ToUTF16(profile.label()))); | 347 profile, all_profiles_from_db)); |
373 Associate(&tag, node.GetId()); | 348 |
374 AutoFillProfile* p = personal_data_-> | 349 if(profile_in_web_db.get() != NULL) { |
375 CreateNewEmptyAutoFillProfileForDBThread(UTF8ToUTF16(profile.label())); | 350 int64 sync_id = node.GetId(); |
| 351 Associate(&(profile_in_web_db->guid()), sync_id); |
| 352 return; |
| 353 } else { // Create a new node. |
| 354 std::string guid = guid::GenerateGUID(); |
| 355 Associate(&guid, node.GetId()); |
| 356 AutoFillProfile* p = new AutoFillProfile(guid); |
376 OverwriteProfileWithServerData(p, profile); | 357 OverwriteProfileWithServerData(p, profile); |
377 bundle->new_profiles.push_back(p); | 358 bundle->new_profiles.push_back(p); |
378 } | 359 } |
379 } | 360 } |
380 | 361 |
381 bool AutofillModelAssociator::DisassociateModels() { | 362 bool AutofillModelAssociator::DisassociateModels() { |
| 363 |
382 id_map_.clear(); | 364 id_map_.clear(); |
383 id_map_inverse_.clear(); | 365 id_map_inverse_.clear(); |
384 return true; | 366 return true; |
385 } | 367 } |
386 | 368 |
387 bool AutofillModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) { | 369 bool AutofillModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) { |
388 DCHECK(has_nodes); | 370 DCHECK(has_nodes); |
389 *has_nodes = false; | 371 *has_nodes = false; |
390 int64 autofill_sync_id; | 372 int64 autofill_sync_id; |
391 if (!GetSyncIdForTaggedNode(kAutofillTag, &autofill_sync_id)) { | 373 if (!GetSyncIdForTaggedNode(kAutofillTag, &autofill_sync_id)) { |
(...skipping 18 matching lines...) Expand all Loading... |
410 } | 392 } |
411 | 393 |
412 void AutofillModelAssociator::AbortAssociation() { | 394 void AutofillModelAssociator::AbortAssociation() { |
413 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 395 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
414 AutoLock lock(abort_association_pending_lock_); | 396 AutoLock lock(abort_association_pending_lock_); |
415 abort_association_pending_ = true; | 397 abort_association_pending_ = true; |
416 } | 398 } |
417 | 399 |
418 const std::string* | 400 const std::string* |
419 AutofillModelAssociator::GetChromeNodeFromSyncId(int64 sync_id) { | 401 AutofillModelAssociator::GetChromeNodeFromSyncId(int64 sync_id) { |
420 return NULL; | 402 SyncIdToAutofillMap::const_iterator iter = id_map_inverse_.find(sync_id); |
| 403 return iter == id_map_inverse_.end() ? NULL : &(iter->second); |
421 } | 404 } |
422 | 405 |
423 bool AutofillModelAssociator::InitSyncNodeFromChromeId( | 406 bool AutofillModelAssociator::InitSyncNodeFromChromeId( |
424 std::string node_id, | 407 std::string node_id, |
425 sync_api::BaseNode* sync_node) { | 408 sync_api::BaseNode* sync_node) { |
426 return false; | 409 return false; |
427 } | 410 } |
428 | 411 |
429 int64 AutofillModelAssociator::GetSyncIdFromChromeId( | 412 int64 AutofillModelAssociator::GetSyncIdFromChromeId( |
430 const std::string autofill) { | 413 const std::string autofill) { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
469 | 452 |
470 // static | 453 // static |
471 std::string AutofillModelAssociator::KeyToTag(const string16& name, | 454 std::string AutofillModelAssociator::KeyToTag(const string16& name, |
472 const string16& value) { | 455 const string16& value) { |
473 std::string ns(kAutofillEntryNamespaceTag); | 456 std::string ns(kAutofillEntryNamespaceTag); |
474 return ns + EscapePath(UTF16ToUTF8(name)) + "|" + | 457 return ns + EscapePath(UTF16ToUTF8(name)) + "|" + |
475 EscapePath(UTF16ToUTF8(value)); | 458 EscapePath(UTF16ToUTF8(value)); |
476 } | 459 } |
477 | 460 |
478 // static | 461 // static |
479 std::string AutofillModelAssociator::ProfileLabelToTag(const string16& label) { | |
480 std::string ns(kAutofillProfileNamespaceTag); | |
481 return ns + EscapePath(UTF16ToUTF8(label)); | |
482 } | |
483 | |
484 // static | |
485 bool AutofillModelAssociator::MergeTimestamps( | 462 bool AutofillModelAssociator::MergeTimestamps( |
486 const sync_pb::AutofillSpecifics& autofill, | 463 const sync_pb::AutofillSpecifics& autofill, |
487 const std::vector<base::Time>& timestamps, | 464 const std::vector<base::Time>& timestamps, |
488 std::vector<base::Time>* new_timestamps) { | 465 std::vector<base::Time>* new_timestamps) { |
489 DCHECK(new_timestamps); | 466 DCHECK(new_timestamps); |
490 std::set<base::Time> timestamp_union(timestamps.begin(), | 467 std::set<base::Time> timestamp_union(timestamps.begin(), |
491 timestamps.end()); | 468 timestamps.end()); |
492 | 469 |
493 size_t timestamps_count = autofill.usage_timestamp_size(); | 470 size_t timestamps_count = autofill.usage_timestamp_size(); |
494 | 471 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
536 diff = MergeField(p, ADDRESS_HOME_ZIP, s.address_home_zip()) || diff; | 513 diff = MergeField(p, ADDRESS_HOME_ZIP, s.address_home_zip()) || diff; |
537 diff = MergeField(p, EMAIL_ADDRESS, s.email_address()) || diff; | 514 diff = MergeField(p, EMAIL_ADDRESS, s.email_address()) || diff; |
538 diff = MergeField(p, COMPANY_NAME, s.company_name()) || diff; | 515 diff = MergeField(p, COMPANY_NAME, s.company_name()) || diff; |
539 diff = MergeField(p, PHONE_FAX_WHOLE_NUMBER, s.phone_fax_whole_number()) | 516 diff = MergeField(p, PHONE_FAX_WHOLE_NUMBER, s.phone_fax_whole_number()) |
540 || diff; | 517 || diff; |
541 diff = MergeField(p, PHONE_HOME_WHOLE_NUMBER, s.phone_home_whole_number()) | 518 diff = MergeField(p, PHONE_HOME_WHOLE_NUMBER, s.phone_home_whole_number()) |
542 || diff; | 519 || diff; |
543 return diff; | 520 return diff; |
544 } | 521 } |
545 | 522 |
| 523 bool AutofillModelAssociator::IsUpgrading() |
| 524 { |
| 525 return true; |
| 526 } |
| 527 |
546 } // namespace browser_sync | 528 } // namespace browser_sync |
OLD | NEW |