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

Side by Side Diff: components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc

Issue 2624883002: [Sync] ApplySyncChanges autofill implementation. (Closed)
Patch Set: Updates for Max. Created 3 years, 11 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
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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/webdata/autocomplete_sync_bridge.h" 5 #include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h"
6 6
7 #include <algorithm>
8 #include <set>
7 #include <unordered_set> 9 #include <unordered_set>
8 #include <utility> 10 #include <utility>
9 #include <vector> 11 #include <vector>
10 12
11 #include "base/bind.h" 13 #include "base/bind.h"
12 #include "base/memory/ptr_util.h" 14 #include "base/memory/ptr_util.h"
13 #include "base/strings/utf_string_conversions.h" 15 #include "base/strings/utf_string_conversions.h"
14 #include "components/autofill/core/browser/proto/autofill_sync.pb.h" 16 #include "components/autofill/core/browser/proto/autofill_sync.pb.h"
15 #include "components/autofill/core/browser/webdata/autofill_metadata_change_list .h" 17 #include "components/autofill/core/browser/webdata/autofill_metadata_change_list .h"
16 #include "components/autofill/core/browser/webdata/autofill_table.h" 18 #include "components/autofill/core/browser/webdata/autofill_table.h"
17 #include "components/autofill/core/browser/webdata/autofill_webdata_backend.h" 19 #include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
18 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" 20 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
19 #include "components/sync/model/entity_data.h" 21 #include "components/sync/model/entity_data.h"
20 #include "components/sync/model/model_type_change_processor.h" 22 #include "components/sync/model/model_type_change_processor.h"
21 #include "components/sync/model/mutable_data_batch.h" 23 #include "components/sync/model/mutable_data_batch.h"
22 #include "net/base/escape.h" 24 #include "net/base/escape.h"
23 25
26 using base::Optional;
27 using base::Time;
28 using sync_pb::AutofillSpecifics;
29 using syncer::EntityChange;
30 using syncer::EntityChangeList;
31 using syncer::EntityData;
32 using syncer::EntityDataMap;
33 using syncer::MetadataChangeList;
34 using syncer::ModelError;
35 using syncer::ModelTypeChangeProcessor;
36 using syncer::MutableDataBatch;
37
24 namespace autofill { 38 namespace autofill {
25 39
26 namespace { 40 namespace {
27 41
28 const char kAutocompleteEntryNamespaceTag[] = "autofill_entry|"; 42 const char kAutocompleteEntryNamespaceTag[] = "autofill_entry|";
29 const char kAutocompleteTagDelimiter[] = "|"; 43 const char kAutocompleteTagDelimiter[] = "|";
30 44
45 // Simplify checking for optional errors and returning only when present.
46 #define RETURN_IF_ERROR(x) \
47 if (Optional<ModelError> ret_val = x) { \
48 return ret_val; \
49 }
50
31 void* UserDataKey() { 51 void* UserDataKey() {
32 // Use the address of a static that COMDAT folding won't ever collide 52 // Use the address of a static that COMDAT folding won't ever collide
33 // with something else. 53 // with something else.
34 static int user_data_key = 0; 54 static int user_data_key = 0;
35 return reinterpret_cast<void*>(&user_data_key); 55 return reinterpret_cast<void*>(&user_data_key);
36 } 56 }
37 57
38 std::unique_ptr<syncer::EntityData> CreateEntityData( 58 std::unique_ptr<EntityData> CreateEntityData(const AutofillEntry& entry) {
39 const AutofillEntry& entry) { 59 auto entity_data = base::MakeUnique<EntityData>();
40 auto entity_data = base::MakeUnique<syncer::EntityData>();
41 entity_data->non_unique_name = base::UTF16ToUTF8(entry.key().name()); 60 entity_data->non_unique_name = base::UTF16ToUTF8(entry.key().name());
42 sync_pb::AutofillSpecifics* autofill = 61 AutofillSpecifics* autofill = entity_data->specifics.mutable_autofill();
43 entity_data->specifics.mutable_autofill();
44 autofill->set_name(base::UTF16ToUTF8(entry.key().name())); 62 autofill->set_name(base::UTF16ToUTF8(entry.key().name()));
45 autofill->set_value(base::UTF16ToUTF8(entry.key().value())); 63 autofill->set_value(base::UTF16ToUTF8(entry.key().value()));
46 autofill->add_usage_timestamp(entry.date_created().ToInternalValue()); 64 autofill->add_usage_timestamp(entry.date_created().ToInternalValue());
47 if (entry.date_created() != entry.date_last_used()) 65 if (entry.date_created() != entry.date_last_used())
48 autofill->add_usage_timestamp(entry.date_last_used().ToInternalValue()); 66 autofill->add_usage_timestamp(entry.date_last_used().ToInternalValue());
49 return entity_data; 67 return entity_data;
50 } 68 }
51 69
52 std::string BuildSerializedStorageKey(const std::string& name, 70 std::string BuildSerializedStorageKey(const std::string& name,
53 const std::string& value) { 71 const std::string& value) {
54 AutofillSyncStorageKey proto; 72 AutofillSyncStorageKey proto;
55 proto.set_name(name); 73 proto.set_name(name);
56 proto.set_value(value); 74 proto.set_value(value);
57 return proto.SerializeAsString(); 75 return proto.SerializeAsString();
58 } 76 }
59 77
60 std::string GetStorageKeyFromModel(const AutofillKey& key) { 78 std::string GetStorageKeyFromModel(const AutofillKey& key) {
61 return BuildSerializedStorageKey(base::UTF16ToUTF8(key.name()), 79 return BuildSerializedStorageKey(base::UTF16ToUTF8(key.name()),
62 base::UTF16ToUTF8(key.value())); 80 base::UTF16ToUTF8(key.value()));
63 } 81 }
64 82
83 AutofillEntry MergeEntryDates(const AutofillEntry& entry1,
84 const AutofillEntry& entry2) {
85 DCHECK(entry1.key() == entry2.key());
86 return AutofillEntry(
87 entry1.key(), std::min(entry1.date_created(), entry2.date_created()),
88 std::max(entry1.date_last_used(), entry2.date_last_used()));
89 }
90
91 bool ParseStorageKey(const std::string& storage_key, AutofillKey* out_key) {
92 AutofillSyncStorageKey proto;
93 if (proto.ParseFromString(storage_key)) {
94 *out_key = AutofillKey(base::UTF8ToUTF16(proto.name()),
95 base::UTF8ToUTF16((proto.value())));
96 return true;
97 } else {
98 return false;
99 }
100 }
101
102 AutofillEntry CreateAutofillEntry(const AutofillSpecifics& autofill_specifics) {
103 AutofillKey key(base::UTF8ToUTF16(autofill_specifics.name()),
104 base::UTF8ToUTF16(autofill_specifics.value()));
105 Time date_created, date_last_used;
106 const google::protobuf::RepeatedField<int64_t>& timestamps =
107 autofill_specifics.usage_timestamp();
108 if (!timestamps.empty()) {
109 auto iter_pair = std::minmax_element(timestamps.begin(), timestamps.end());
110 date_created = Time::FromInternalValue(*iter_pair.first);
111 date_last_used = Time::FromInternalValue(*iter_pair.second);
112 }
113 return AutofillEntry(key, date_created, date_last_used);
114 }
115
116 // This is used to respond to ApplySyncChanges() and MergeSyncData(). Attempts
117 // to lazily load local data, and then react to sync data by maintain internal
maxbogue 2017/01/12 22:54:07 maintaining
skym 2017/01/13 16:46:44 Done.
118 // state until flush calls are made, at which point the applicable modifications
119 // should be sent towards local and sync directions.
120 class SyncDifferenceTracker {
121 public:
122 explicit SyncDifferenceTracker(AutofillTable* table) : table_(table) {}
123
124 Optional<ModelError> IncorporateRemoteSpecifics(
125 const std::string& storage_key,
126 const AutofillSpecifics& specifics) {
127 if (!specifics.has_value()) {
128 // A long time ago autofill had a different format, and it's possible we
129 // could encounter some of that legacy data. It is not useful to us,
130 // because an autofill entry with no value will not place any text in a
131 // form for the user. So drop all of these on the floor.
132 DVLOG(1) << "Dropping old-style autofill profile change.";
133 return {};
134 }
135
136 const AutofillEntry remote = CreateAutofillEntry(specifics);
137 DCHECK_EQ(storage_key, GetStorageKeyFromModel(remote.key()));
138
139 Optional<AutofillEntry> local;
140 if (!ReadEntry(remote.key(), &local)) {
141 return ModelError(FROM_HERE, "Failed reading from WebDatabase.");
142 } else if (!local) {
143 save_to_local_.push_back(remote);
144 } else if (remote != local.value()) {
145 if (specifics.usage_timestamp().empty()) {
146 // Skip merging if there are no timestamps. We don't want to wipe out
147 // a local value of |date_created| if the remote copy is oddly formed.
148 save_to_sync_.push_back(local.value());
149 } else {
150 const AutofillEntry merged = MergeEntryDates(local.value(), remote);
151 save_to_local_.push_back(merged);
152 save_to_sync_.push_back(merged);
153 }
154 unique_to_local_.erase(local.value());
155 }
156 return {};
157 }
158
159 Optional<ModelError> IncorporateRemoteDelete(const std::string& storage_key) {
160 AutofillKey key;
161 if (!ParseStorageKey(storage_key, &key)) {
162 return ModelError(FROM_HERE, "Failed parsing storage key.");
163 }
164 delete_from_local_.insert(key);
165 return {};
166 }
167
168 Optional<ModelError> FlushToLocal(AutofillWebDataBackend* web_data_backend) {
169 for (const AutofillKey& key : delete_from_local_) {
170 if (!table_->RemoveFormElement(key.name(), key.value())) {
171 return ModelError(FROM_HERE, "Failed deleting from WebDatabase");
172 }
173 }
174 if (!table_->UpdateAutofillEntries(save_to_local_)) {
175 return ModelError(FROM_HERE, "Failed updating WebDatabase");
176 }
177 if (!delete_from_local_.empty() || !save_to_local_.empty()) {
178 web_data_backend->NotifyOfMultipleAutofillChanges();
179 }
180 return {};
181 }
182
183 Optional<ModelError> FlushToSync(
184 bool include_local_only,
185 std::unique_ptr<MetadataChangeList> metadata_change_list,
186 ModelTypeChangeProcessor* change_processor) {
187 for (const AutofillEntry& entry : save_to_sync_) {
188 change_processor->Put(GetStorageKeyFromModel(entry.key()),
189 CreateEntityData(entry),
190 metadata_change_list.get());
191 }
192 if (include_local_only) {
193 if (!InitializeIfNeeded()) {
194 return ModelError(FROM_HERE, "Failed reading from WebDatabase.");
195 }
196 for (const AutofillEntry& entry : unique_to_local_) {
197 // This should never be true because only ApplySyncChanges should be
198 // calling IncorporateRemoteDelete, while only MergeSyncData should be
199 // passing in true for |include_local_only|. If this requirement
200 // changes, this DCHECK can change to act as a filter.
201 DCHECK(delete_from_local_.find(entry.key()) ==
202 delete_from_local_.end());
203 change_processor->Put(GetStorageKeyFromModel(entry.key()),
204 CreateEntityData(entry),
205 metadata_change_list.get());
206 }
207 }
208 return static_cast<AutofillMetadataChangeList*>(metadata_change_list.get())
209 ->TakeError();
210 }
211
212 private:
213 // There are three major outcomes of this method.
214 // 1. An error is encountered reading from the db, false is returned.
215 // 2. The entry is not found, |entry| will not be touched.
216 // 3. The entry is found, |entry| will be set.
217 bool ReadEntry(const AutofillKey& key, Optional<AutofillEntry>* entry) {
218 if (!InitializeIfNeeded()) {
219 return false;
220 }
221 auto iter = unique_to_local_.find(AutofillEntry(key, Time(), Time()));
222 if (iter != unique_to_local_.end()) {
223 *entry = *iter;
224 }
225 return true;
226 }
227
228 bool InitializeIfNeeded() {
229 if (initialized_) {
230 return true;
231 }
232
233 std::vector<AutofillEntry> vector;
234 if (!table_->GetAllAutofillEntries(&vector)) {
235 return false;
236 }
237
238 unique_to_local_ = std::set<AutofillEntry>(vector.begin(), vector.end());
239 initialized_ = true;
240 return true;
241 }
242
243 AutofillTable* table_;
244
245 // This class attempts to lazily load data from |table_|. This field tracks
246 // if that has happened or not yet. To facilitate this, the first usage of
247 // |unique_to_local_| should typically be done through ReadEntry().
maxbogue 2017/01/12 22:54:07 My previous comment here was wrong. What I meant t
skym 2017/01/13 16:46:44 Done.
248 bool initialized_ = false;
249
250 // Important to note that because AutofillEntry's operator > simply compares
maxbogue 2017/01/12 22:54:08 the most nit of nits: s/>/<
skym 2017/01/13 16:46:43 Done.
251 // contained AutofillKeys, this acts as a map<AutofillKey, AutofillEntry>.
252 // This initially contains all local data, but as sync data is encountered,
253 // entries are removed from here.
254 std::set<AutofillEntry> unique_to_local_;
255
256 std::set<AutofillKey> delete_from_local_;
257 std::vector<AutofillEntry> save_to_local_;
258
259 // Contains merged data for entries that existed on both sync and local sides
260 // and need to be saved back to sync.
261 std::vector<AutofillEntry> save_to_sync_;
262
263 DISALLOW_COPY_AND_ASSIGN(SyncDifferenceTracker);
264 };
265
65 } // namespace 266 } // namespace
66 267
67 // static 268 // static
68 void AutocompleteSyncBridge::CreateForWebDataServiceAndBackend( 269 void AutocompleteSyncBridge::CreateForWebDataServiceAndBackend(
69 AutofillWebDataService* web_data_service, 270 AutofillWebDataService* web_data_service,
70 AutofillWebDataBackend* web_data_backend) { 271 AutofillWebDataBackend* web_data_backend) {
71 web_data_service->GetDBUserData()->SetUserData( 272 web_data_service->GetDBUserData()->SetUserData(
72 UserDataKey(), 273 UserDataKey(),
73 new AutocompleteSyncBridge( 274 new AutocompleteSyncBridge(
74 web_data_backend, 275 web_data_backend, base::Bind(&ModelTypeChangeProcessor::Create)));
75 base::Bind(&syncer::ModelTypeChangeProcessor::Create)));
76 } 276 }
77 277
78 // static 278 // static
79 AutocompleteSyncBridge* AutocompleteSyncBridge::FromWebDataService( 279 AutocompleteSyncBridge* AutocompleteSyncBridge::FromWebDataService(
80 AutofillWebDataService* web_data_service) { 280 AutofillWebDataService* web_data_service) {
81 return static_cast<AutocompleteSyncBridge*>( 281 return static_cast<AutocompleteSyncBridge*>(
82 web_data_service->GetDBUserData()->GetUserData(UserDataKey())); 282 web_data_service->GetDBUserData()->GetUserData(UserDataKey()));
83 } 283 }
84 284
85 AutocompleteSyncBridge::AutocompleteSyncBridge( 285 AutocompleteSyncBridge::AutocompleteSyncBridge(
86 AutofillWebDataBackend* backend, 286 AutofillWebDataBackend* backend,
87 const ChangeProcessorFactory& change_processor_factory) 287 const ChangeProcessorFactory& change_processor_factory)
88 : ModelTypeSyncBridge(change_processor_factory, syncer::AUTOFILL), 288 : ModelTypeSyncBridge(change_processor_factory, syncer::AUTOFILL),
89 web_data_backend_(backend), 289 web_data_backend_(backend),
90 scoped_observer_(this) { 290 scoped_observer_(this) {
91 DCHECK(web_data_backend_); 291 DCHECK(web_data_backend_);
92 292
93 scoped_observer_.Add(web_data_backend_); 293 scoped_observer_.Add(web_data_backend_);
94 } 294 }
95 295
96 AutocompleteSyncBridge::~AutocompleteSyncBridge() { 296 AutocompleteSyncBridge::~AutocompleteSyncBridge() {
97 DCHECK(thread_checker_.CalledOnValidThread()); 297 DCHECK(thread_checker_.CalledOnValidThread());
98 } 298 }
99 299
100 std::unique_ptr<syncer::MetadataChangeList> 300 std::unique_ptr<MetadataChangeList>
101 AutocompleteSyncBridge::CreateMetadataChangeList() { 301 AutocompleteSyncBridge::CreateMetadataChangeList() {
102 DCHECK(thread_checker_.CalledOnValidThread()); 302 DCHECK(thread_checker_.CalledOnValidThread());
103 return base::MakeUnique<AutofillMetadataChangeList>(GetAutofillTable(), 303 return base::MakeUnique<AutofillMetadataChangeList>(GetAutofillTable(),
104 syncer::AUTOFILL); 304 syncer::AUTOFILL);
105 } 305 }
106 306
107 base::Optional<syncer::ModelError> AutocompleteSyncBridge::MergeSyncData( 307 Optional<syncer::ModelError> AutocompleteSyncBridge::MergeSyncData(
108 std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, 308 std::unique_ptr<MetadataChangeList> metadata_change_list,
109 syncer::EntityDataMap entity_data_map) { 309 EntityDataMap entity_data_map) {
110 DCHECK(thread_checker_.CalledOnValidThread()); 310 DCHECK(thread_checker_.CalledOnValidThread());
111 NOTIMPLEMENTED(); 311
312 // TODO(skym, crbug.com/680218): Uncomment and add unit tests.
313 /*SyncDifferenceTracker tracker(GetAutofillTable());
314 for (auto kv : entity_data_map) {
315 // TODO(skym, crbug.com/680550): Does this need to handle deletes?
maxbogue 2017/01/12 22:54:07 Re offline discussion: no! :)
skym 2017/01/13 16:46:44 Done.
316 DCHECK(kv.second->specifics.has_autofill());
317 RETURN_IF_ERROR(tracker.IncorporateRemoteSpecifics(
318 kv.first, kv.second->specifics.autofill()));
319 }
320
321 RETURN_IF_ERROR(tracker.FlushToLocal(web_data_backend_));
322 RETURN_IF_ERROR(tracker.FlushToSync(true, std::move(metadata_change_list),
323 change_processor()));
324 web_data_backend_->RemoveExpiredFormElements();
325 web_data_backend_->NotifyThatSyncHasStarted(syncer::AUTOFILL);*/
112 return {}; 326 return {};
113 } 327 }
114 328
115 base::Optional<syncer::ModelError> AutocompleteSyncBridge::ApplySyncChanges( 329 Optional<ModelError> AutocompleteSyncBridge::ApplySyncChanges(
116 std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, 330 std::unique_ptr<MetadataChangeList> metadata_change_list,
117 syncer::EntityChangeList entity_changes) { 331 EntityChangeList entity_changes) {
118 DCHECK(thread_checker_.CalledOnValidThread()); 332 DCHECK(thread_checker_.CalledOnValidThread());
119 NOTIMPLEMENTED(); 333
334 SyncDifferenceTracker tracker(GetAutofillTable());
335 for (const EntityChange& change : entity_changes) {
336 if (change.type() == EntityChange::ACTION_DELETE) {
337 RETURN_IF_ERROR(tracker.IncorporateRemoteDelete(change.storage_key()));
338 } else {
339 DCHECK(change.data().specifics.has_autofill());
340 RETURN_IF_ERROR(tracker.IncorporateRemoteSpecifics(
341 change.storage_key(), change.data().specifics.autofill()));
342 }
343 }
344
345 RETURN_IF_ERROR(tracker.FlushToLocal(web_data_backend_));
346 RETURN_IF_ERROR(tracker.FlushToSync(false, std::move(metadata_change_list),
347 change_processor()));
348 web_data_backend_->RemoveExpiredFormElements();
120 return {}; 349 return {};
121 } 350 }
122 351
123 void AutocompleteSyncBridge::AutocompleteSyncBridge::GetData( 352 void AutocompleteSyncBridge::AutocompleteSyncBridge::GetData(
124 StorageKeyList storage_keys, 353 StorageKeyList storage_keys,
125 DataCallback callback) { 354 DataCallback callback) {
126 DCHECK(thread_checker_.CalledOnValidThread()); 355 DCHECK(thread_checker_.CalledOnValidThread());
127 std::vector<AutofillEntry> entries; 356 std::vector<AutofillEntry> entries;
128 if (!GetAutofillTable()->GetAllAutofillEntries(&entries)) { 357 if (!GetAutofillTable()->GetAllAutofillEntries(&entries)) {
129 change_processor()->ReportError(FROM_HERE, 358 change_processor()->ReportError(FROM_HERE,
130 "Failed to load entries from table."); 359 "Failed to load entries from table.");
131 return; 360 return;
132 } 361 }
133 362
134 std::unordered_set<std::string> keys_set; 363 std::unordered_set<std::string> keys_set(storage_keys.begin(),
135 for (const auto& key : storage_keys) { 364 storage_keys.end());
136 keys_set.insert(key); 365 auto batch = base::MakeUnique<MutableDataBatch>();
137 }
138
139 auto batch = base::MakeUnique<syncer::MutableDataBatch>();
140 for (const AutofillEntry& entry : entries) { 366 for (const AutofillEntry& entry : entries) {
141 std::string key = GetStorageKeyFromModel(entry.key()); 367 std::string key = GetStorageKeyFromModel(entry.key());
142 if (keys_set.find(key) != keys_set.end()) { 368 if (keys_set.find(key) != keys_set.end()) {
143 batch->Put(key, CreateEntityData(entry)); 369 batch->Put(key, CreateEntityData(entry));
144 } 370 }
145 } 371 }
146 callback.Run(std::move(batch)); 372 callback.Run(std::move(batch));
147 } 373 }
148 374
149 void AutocompleteSyncBridge::GetAllData(DataCallback callback) { 375 void AutocompleteSyncBridge::GetAllData(DataCallback callback) {
150 DCHECK(thread_checker_.CalledOnValidThread()); 376 DCHECK(thread_checker_.CalledOnValidThread());
151 377
152 std::vector<AutofillEntry> entries; 378 std::vector<AutofillEntry> entries;
153 if (!GetAutofillTable()->GetAllAutofillEntries(&entries)) { 379 if (!GetAutofillTable()->GetAllAutofillEntries(&entries)) {
154 change_processor()->ReportError(FROM_HERE, 380 change_processor()->ReportError(FROM_HERE,
155 "Failed to load entries from table."); 381 "Failed to load entries from table.");
156 return; 382 return;
157 } 383 }
158 384
159 auto batch = base::MakeUnique<syncer::MutableDataBatch>(); 385 auto batch = base::MakeUnique<MutableDataBatch>();
160 for (const AutofillEntry& entry : entries) { 386 for (const AutofillEntry& entry : entries) {
161 batch->Put(GetStorageKeyFromModel(entry.key()), CreateEntityData(entry)); 387 batch->Put(GetStorageKeyFromModel(entry.key()), CreateEntityData(entry));
162 } 388 }
163 callback.Run(std::move(batch)); 389 callback.Run(std::move(batch));
164 } 390 }
165 391
166 std::string AutocompleteSyncBridge::GetClientTag( 392 std::string AutocompleteSyncBridge::GetClientTag(
167 const syncer::EntityData& entity_data) { 393 const EntityData& entity_data) {
168 DCHECK(entity_data.specifics.has_autofill()); 394 DCHECK(entity_data.specifics.has_autofill());
169 const sync_pb::AutofillSpecifics specifics = entity_data.specifics.autofill(); 395 const AutofillSpecifics specifics = entity_data.specifics.autofill();
170 return std::string(kAutocompleteEntryNamespaceTag) + 396 return std::string(kAutocompleteEntryNamespaceTag) +
171 net::EscapePath(specifics.name()) + 397 net::EscapePath(specifics.name()) +
172 std::string(kAutocompleteTagDelimiter) + 398 std::string(kAutocompleteTagDelimiter) +
173 net::EscapePath(specifics.value()); 399 net::EscapePath(specifics.value());
174 } 400 }
175 401
176 std::string AutocompleteSyncBridge::GetStorageKey( 402 std::string AutocompleteSyncBridge::GetStorageKey(
177 const syncer::EntityData& entity_data) { 403 const EntityData& entity_data) {
178 DCHECK(entity_data.specifics.has_autofill()); 404 DCHECK(entity_data.specifics.has_autofill());
179 const sync_pb::AutofillSpecifics specifics = entity_data.specifics.autofill(); 405 const AutofillSpecifics specifics = entity_data.specifics.autofill();
180 return BuildSerializedStorageKey(specifics.name(), specifics.value()); 406 return BuildSerializedStorageKey(specifics.name(), specifics.value());
181 } 407 }
182 408
183 // AutofillWebDataServiceObserverOnDBThread implementation. 409 // AutofillWebDataServiceObserverOnDBThread implementation.
184 void AutocompleteSyncBridge::AutofillEntriesChanged( 410 void AutocompleteSyncBridge::AutofillEntriesChanged(
185 const AutofillChangeList& changes) { 411 const AutofillChangeList& changes) {
186 DCHECK(thread_checker_.CalledOnValidThread()); 412 DCHECK(thread_checker_.CalledOnValidThread());
187 } 413 }
188 414
189 // static
190 AutofillEntry AutocompleteSyncBridge::CreateAutofillEntry(
191 const sync_pb::AutofillSpecifics& autofill_specifics) {
192 AutofillKey key(base::UTF8ToUTF16(autofill_specifics.name()),
193 base::UTF8ToUTF16(autofill_specifics.value()));
194 base::Time date_created, date_last_used;
195 const google::protobuf::RepeatedField<int64_t>& timestamps =
196 autofill_specifics.usage_timestamp();
197 if (!timestamps.empty()) {
198 date_created = base::Time::FromInternalValue(*timestamps.begin());
199 date_last_used = base::Time::FromInternalValue(*timestamps.rbegin());
200 }
201 return AutofillEntry(key, date_created, date_last_used);
202 }
203
204 AutofillTable* AutocompleteSyncBridge::GetAutofillTable() const { 415 AutofillTable* AutocompleteSyncBridge::GetAutofillTable() const {
205 return AutofillTable::FromWebDatabase(web_data_backend_->GetDatabase()); 416 return AutofillTable::FromWebDatabase(web_data_backend_->GetDatabase());
206 } 417 }
207 418
208 } // namespace autofill 419 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698