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

Unified Diff: chrome/browser/search_engines/template_url_service.cc

Issue 10381016: Remove the "autogenerate keyword" bit on TemplateURL. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 8 years, 8 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/search_engines/template_url_service.cc
===================================================================
--- chrome/browser/search_engines/template_url_service.cc (revision 135424)
+++ chrome/browser/search_engines/template_url_service.cc (working copy)
@@ -70,7 +70,9 @@
return true;
return (url1 != NULL) && (url2 != NULL) &&
(url1->short_name() == url2->short_name()) &&
- (url1->keyword() == url2->keyword()) &&
+ ((url1->keyword() == url2->keyword()) ||
sky 2012/05/04 23:20:25 Is it worth moving this to a common place for both
Peter Kasting 2012/05/07 17:50:24 Yes, good idea.
+ (url1->IsGoogleSearchURLWithReplaceableKeyword() &&
+ url2->IsGoogleSearchURLWithReplaceableKeyword())) &&
(url1->url() == url2->url()) &&
(url1->suggestions_url() == url2->suggestions_url()) &&
(url1->instant_url() == url2->instant_url()) &&
@@ -90,6 +92,43 @@
return NULL;
}
+// If |change_list| contains ACTION_UPDATEs followed by more ACTION_UPDATEs or
+// ACTION_ADDs for the same GUID, remove all but the last one.
+//
+// This is necessary because when syncing we may first need to migrate the
+// server-provided TemplateURL in some way, then resolve conflicts against a
+// local URL, generating two different UPDATEs. If we send up both UPDATEs, and
+// the server does not coalesce them before sending to other clients, then the
+// first update could cause conflicts on the other clients, resulting in them
+// sending back UPDATEs of their own to try to resolve things, thus causing mass
+// confusion. Since the second UPDATE obviates the need for the first, removing
+// the first locally is safe and avoids any potential for this problem.
+//
+// REVIEWERS: Should we instead do this uniquing at a lower level, or guarantee
+// that the server will coalesce these so the client need not worry?
+void PreventDuplicateGUIDUpdates(SyncChangeList* change_list) {
+ for (size_t i = change_list->size(); i > 1; ) {
+ --i; // Prevent underflow that could occur if we did this in the loop body.
+ const SyncChange& change_i = (*change_list)[i];
+ if ((change_i.change_type() != SyncChange::ACTION_ADD) &&
+ (change_i.change_type() != SyncChange::ACTION_UPDATE))
+ continue;
+ std::string guid(
+ change_i.sync_data().GetSpecifics().search_engine().sync_guid());
+ for (size_t j = 0; j < i; ) {
+ const SyncChange& change_j = (*change_list)[j];
+ if ((change_j.change_type() == SyncChange::ACTION_UPDATE) &&
+ (change_j.sync_data().GetSpecifics().search_engine().sync_guid() ==
+ guid)) {
+ change_list->erase(change_list->begin() + j);
+ --i;
+ } else {
+ ++j;
+ }
+ }
+ }
+}
+
} // namespace
@@ -160,22 +199,8 @@
}
// static
-string16 TemplateURLService::GenerateKeyword(const GURL& url,
- bool autodetected) {
- // Don't autogenerate keywords for referrers that are the result of a form
- // submission (TODO: right now we approximate this by checking for the URL
- // having a query, but we should replace this with a call to WebCore to see if
- // the originating page was actually a form submission), anything other than
- // http, or referrers with a path.
- //
- // If we relax the path constraint, we need to be sure to sanitize the path
- // elements and update AutocompletePopup to look for keywords using the path.
- // See http://b/issue?id=863583.
- if (!url.is_valid() ||
- (autodetected && (url.has_query() || !url.SchemeIs(chrome::kHttpScheme) ||
- ((url.path() != "") && (url.path() != "/")))))
- return string16();
-
+string16 TemplateURLService::GenerateKeyword(const GURL& url) {
+ DCHECK(url.is_valid());
// Strip "www." off the front of the keyword; otherwise the keyword won't work
// properly. See http://code.google.com/p/chromium/issues/detail?id=6984 .
// Special case: if the host was exactly "www." (not sure this can happen but
@@ -231,10 +256,10 @@
const TemplateURL* t_url,
const SearchTermsData& search_terms_data) {
DCHECK(t_url);
+ DCHECK(!t_url->IsExtensionKeyword());
+
const TemplateURLRef& search_ref = t_url->url_ref();
- // Extension keywords don't have host-based search URLs.
- if (!search_ref.IsValidUsingTermsData(search_terms_data) ||
- t_url->IsExtensionKeyword())
+ if (!search_ref.IsValidUsingTermsData(search_terms_data))
return GURL();
if (!search_ref.SupportsReplacementUsingTermsData(search_terms_data))
@@ -334,8 +359,8 @@
}
void TemplateURLService::Add(TemplateURL* template_url) {
- AddNoNotify(template_url, true);
- NotifyObservers();
+ if (AddNoNotify(template_url, true))
+ NotifyObservers();
}
void TemplateURLService::AddAndSetProfile(TemplateURL* template_url,
@@ -348,6 +373,7 @@
const string16& short_name,
const string16& keyword,
const std::string& url) {
+ DCHECK(!keyword.empty());
DCHECK(!url.empty());
template_url->data_.short_name = short_name;
template_url->data_.SetKeyword(keyword);
@@ -454,13 +480,14 @@
// TODO(mpcomplete): If we allow editing extension keywords, then those should
// be persisted to disk and synced.
if (service_.get() && !url->IsExtensionKeyword())
- service_.get()->UpdateKeyword(*url);
+ service_.get()->UpdateKeyword(url->data());
}
void TemplateURLService::ResetTemplateURL(TemplateURL* url,
const string16& title,
const string16& keyword,
const std::string& search_url) {
+ DCHECK(!keyword.empty());
DCHECK(!search_url.empty());
TemplateURLData data(url->data());
data.short_name = title;
@@ -611,7 +638,8 @@
data.created_by_policy = true;
data.id = kInvalidTemplateURLID;
default_search_provider = new TemplateURL(profile_, data);
- AddNoNotify(default_search_provider, true);
+ if (!AddNoNotify(default_search_provider, true))
+ default_search_provider = NULL;
}
}
// Note that this saves the default search provider to prefs.
@@ -809,9 +837,13 @@
if (!turl.get())
continue;
+ // Explicitly don't check for conflicts against extension keywords; in this
+ // case the functions which modify the keyword map know how to handle the
+ // conflicts.
+ // TODO(mpcomplete): If we allow editing extension keywords, then those will
+ // need to undergo conflict resolution.
TemplateURL* existing_keyword_turl =
- GetTemplateURLForKeyword(turl->keyword());
-
+ FindNonExtensionTemplateURLForKeyword(turl->keyword());
if (iter->change_type() == SyncChange::ACTION_DELETE && existing_turl) {
bool delete_default = (existing_turl == GetDefaultSearchProvider());
@@ -829,8 +861,10 @@
} else if (iter->change_type() == SyncChange::ACTION_ADD &&
!existing_turl) {
std::string guid = turl->sync_guid();
- if (existing_keyword_turl)
- ResolveSyncKeywordConflict(turl.get(), &new_changes);
+ if (existing_keyword_turl) {
+ ResolveSyncKeywordConflict(turl.get(), existing_keyword_turl,
+ &new_changes);
+ }
// Force the local ID to kInvalidTemplateURLID so we can add it.
TemplateURLData data(turl->data());
data.id = kInvalidTemplateURLID;
@@ -842,8 +876,10 @@
existing_turl) {
// Possibly resolve a keyword conflict if they have the same keywords but
// are not the same entry.
- if (existing_keyword_turl && existing_keyword_turl != existing_turl)
- ResolveSyncKeywordConflict(turl.get(), &new_changes);
+ if (existing_keyword_turl && existing_keyword_turl != existing_turl) {
+ ResolveSyncKeywordConflict(turl.get(), existing_keyword_turl,
+ &new_changes);
+ }
UpdateNoNotify(existing_turl, *turl);
NotifyObservers();
} else {
@@ -858,6 +894,7 @@
SyncChange::ChangeTypeToString(iter->change_type()));
}
}
+ PreventDuplicateGUIDUpdates(&new_changes);
// If something went wrong, we want to prematurely exit to avoid pushing
// inconsistent data to Sync. We return the last error we received.
@@ -949,8 +986,14 @@
// Keyword conflict is possible in this case. Resolve it first before
// adding the new TemplateURL. Note that we don't remove the local TURL
// from local_data_map in this case as it may still need to be pushed to
- // the cloud.
- ResolveSyncKeywordConflict(sync_turl.get(), &new_changes);
+ // the cloud. We also explicitly don't resolve conflicts against
+ // extension keywords; see comments in ProcessSyncChanges().
+ TemplateURL* existing_keyword_turl =
+ FindNonExtensionTemplateURLForKeyword(sync_turl->keyword());
+ if (existing_keyword_turl) {
+ ResolveSyncKeywordConflict(sync_turl.get(), existing_keyword_turl,
+ &new_changes);
+ }
// Force the local ID to kInvalidTemplateURLID so we can add it.
TemplateURLData data(sync_turl->data());
data.id = kInvalidTemplateURLID;
@@ -969,6 +1012,8 @@
new_changes.push_back(SyncChange(SyncChange::ACTION_ADD, iter->second));
}
+ PreventDuplicateGUIDUpdates(&new_changes);
+
SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
if (error.IsSet())
return error;
@@ -1031,7 +1076,8 @@
se_specifics->set_show_in_default_list(turl.show_in_default_list());
se_specifics->set_suggestions_url(turl.suggestions_url());
se_specifics->set_prepopulate_id(turl.prepopulate_id());
- se_specifics->set_autogenerate_keyword(turl.autogenerate_keyword());
+ // REVIEWERS: Should I instead remove this line entirely?
+ se_specifics->set_autogenerate_keyword(false);
se_specifics->set_instant_url(turl.instant_url());
se_specifics->set_last_modified(turl.last_modified().ToInternalValue());
se_specifics->set_sync_guid(turl.sync_guid());
@@ -1061,8 +1107,15 @@
TemplateURLData data;
data.short_name = UTF8ToUTF16(specifics.short_name());
data.originating_url = GURL(specifics.originating_url());
- data.SetKeyword(UTF8ToUTF16(specifics.keyword()));
- data.SetAutogenerateKeyword(specifics.autogenerate_keyword());
+ string16 keyword(UTF8ToUTF16(specifics.keyword()));
+ // REVIEWERS: Can we ever get to a state where this migration code can be
+ // eliminated?
+ bool reset_keyword =
+ specifics.autogenerate_keyword() || specifics.keyword().empty();
+ if (reset_keyword)
+ keyword = ASCIIToUTF16("dummy"); // Will be replaced below.
+ DCHECK(!keyword.empty());
+ data.SetKeyword(keyword);
data.SetURL(specifics.url());
data.suggestions_url = specifics.suggestions_url();
data.instant_url = specifics.instant_url();
@@ -1082,6 +1135,11 @@
TemplateURL* turl = new TemplateURL(profile, data);
DCHECK(!turl->IsExtensionKeyword());
+ if (reset_keyword) {
+ turl->ResetKeywordIfNecessary(true);
+ SyncData sync_data = CreateSyncDataFromTemplateURL(*turl);
+ change_list->push_back(SyncChange(SyncChange::ACTION_UPDATE, sync_data));
+ }
return turl;
}
@@ -1167,8 +1225,31 @@
}
void TemplateURLService::RemoveFromMaps(TemplateURL* template_url) {
- if (!template_url->keyword().empty())
- keyword_to_template_map_.erase(template_url->keyword());
+ const string16& keyword = template_url->keyword();
+ DCHECK_NE(0U, keyword_to_template_map_.count(keyword));
+ if (keyword_to_template_map_[keyword] == template_url) {
+ // We need to check whether the keyword can now be provided by another
+ // TemplateURL. See the comments in AddToMaps() for more information on
+ // extension keywords and how they can coexist with non-extension keywords.
+ // In the case of more than one extension, we use the most recently
+ // installed (which will be the most recently added, which will have the
+ // highest ID).
+ TemplateURL* best_fallback = NULL;
+ for (TemplateURLVector::const_iterator i(template_urls_.begin());
+ i != template_urls_.end(); ++i) {
+ TemplateURL* turl = *i;
+ // This next statement relies on the fact that there can only be one
+ // non-extension TemplateURL with a given keyword.
+ if ((turl != template_url) && (turl->keyword() == keyword) &&
+ (!best_fallback || !best_fallback->IsExtensionKeyword() ||
+ (turl->IsExtensionKeyword() && (turl->id() > best_fallback->id()))))
+ best_fallback = turl;
+ }
+ if (best_fallback)
+ keyword_to_template_map_[keyword] = best_fallback;
+ else
+ keyword_to_template_map_.erase(keyword);
+ }
// If the keyword we're removing is from an extension, we're now done, since
// it won't be synced or stored in the provider map.
@@ -1198,15 +1279,31 @@
}
void TemplateURLService::AddToMaps(TemplateURL* template_url) {
- if (!template_url->keyword().empty())
- keyword_to_template_map_[template_url->keyword()] = template_url;
+ bool template_extension = template_url->IsExtensionKeyword();
+ const string16& keyword = template_url->keyword();
+ KeywordToTemplateMap::const_iterator i =
+ keyword_to_template_map_.find(keyword);
+ if (i == keyword_to_template_map_.end()) {
+ keyword_to_template_map_[keyword] = template_url;
+ } else {
+ const TemplateURL* existing_url = i->second;
+ // We should only have overlapping keywords when at least one comes from
+ // an extension. In that case, the ranking order is:
+ // Manually-modified keywords > extension keywords > replaceable keywords
+ // When there are multiple extensions, the last-added wins.
+ bool existing_extension = existing_url->IsExtensionKeyword();
+ DCHECK(existing_extension || template_extension);
+ if (existing_extension ?
+ !CanReplace(template_url) : CanReplace(existing_url))
+ keyword_to_template_map_[keyword] = template_url;
+ }
// Extension keywords are not synced, so they don't go into the GUID map,
// and do not use host-based search URLs, so they don't go into the provider
// map, so at this point we're done.
// TODO(mpcomplete): If we allow editing extension keywords, then those should
// be persisted to disk and synced.
- if (template_url->IsExtensionKeyword())
+ if (template_extension)
return;
if (!template_url->sync_guid().empty())
@@ -1326,6 +1423,13 @@
UTF8ToUTF16(prefs->GetString(prefs::kDefaultSearchProviderName));
string16 keyword =
UTF8ToUTF16(prefs->GetString(prefs::kDefaultSearchProviderKeyword));
+ // Force keyword to be non-empty.
+ // TODO(pkasting): This is only necessary as long as we're potentially loading
+ // older prefs where empty keywords are theoretically possible. Eventually
+ // this code can be replaced with a DCHECK(!keyword.empty());.
+ bool update_keyword = keyword.empty();
+ if (update_keyword)
+ keyword = ASCIIToUTF16("dummy");
std::string search_url =
prefs->GetString(prefs::kDefaultSearchProviderSearchURL);
// Force URL to be non-empty. We've never supported this case, but past bugs
@@ -1366,6 +1470,8 @@
}
default_provider->reset(new TemplateURL(profile_, data));
DCHECK(!(*default_provider)->IsExtensionKeyword());
+ if (update_keyword)
+ (*default_provider)->ResetKeywordIfNecessary(true);
return true;
}
@@ -1391,6 +1497,21 @@
t_url->safe_for_autoreplace());
}
+TemplateURL* TemplateURLService::FindNonExtensionTemplateURLForKeyword(
+ const string16& keyword) {
+ TemplateURL* keyword_turl = GetTemplateURLForKeyword(keyword);
+ if (!keyword_turl || !keyword_turl->IsExtensionKeyword())
+ return keyword_turl;
+ // The extension keyword in the model may be hiding a replaceable
+ // non-extension keyword. Look for it.
+ for (TemplateURLVector::const_iterator i(template_urls_.begin());
+ i != template_urls_.end(); ++i) {
+ if (!(*i)->IsExtensionKeyword() && ((*i)->keyword() == keyword))
+ return *i;
+ }
+ return NULL;
+}
+
void TemplateURLService::UpdateNoNotify(TemplateURL* existing_turl,
const TemplateURL& new_values) {
DCHECK(loaded_);
@@ -1404,8 +1525,7 @@
DCHECK(!existing_turl->IsExtensionKeyword());
string16 old_keyword(existing_turl->keyword());
- if (!old_keyword.empty())
- keyword_to_template_map_.erase(old_keyword);
+ keyword_to_template_map_.erase(old_keyword);
if (!existing_turl->sync_guid().empty())
guid_to_template_map_.erase(existing_turl->sync_guid());
@@ -1417,13 +1537,38 @@
provider_map_->Add(existing_turl, search_terms_data);
const string16& keyword = existing_turl->keyword();
- if (!keyword.empty())
+ KeywordToTemplateMap::const_iterator i =
+ keyword_to_template_map_.find(keyword);
+ if (i == keyword_to_template_map_.end()) {
keyword_to_template_map_[keyword] = existing_turl;
+ } else {
+ // We can theoretically reach here in two cases:
+ // * There is an existing extension keyword and sync brings in a rename of
+ // a non-extension keyword to match. In this case we just need to pick
+ // which keyword has priority to update the keyword map.
+ // * Autogeneration of the keyword for a Google default search provider
+ // at load time causes it to conflict with an existing keyword. In this
+ // case we delete the existing keyword if it's replaceable, or else undo
+ // the change in keyword for |existing_turl|.
+ DCHECK(!existing_turl->IsExtensionKeyword());
+ TemplateURL* existing_keyword_turl = i->second;
+ if (existing_keyword_turl->IsExtensionKeyword()) {
+ if (!CanReplace(existing_turl))
+ keyword_to_template_map_[keyword] = existing_turl;
+ } else {
+ if (CanReplace(existing_keyword_turl)) {
+ RemoveNoNotify(existing_keyword_turl);
+ } else {
+ existing_turl->data_.SetKeyword(old_keyword);
+ keyword_to_template_map_[old_keyword] = existing_turl;
+ }
+ }
+ }
if (!existing_turl->sync_guid().empty())
guid_to_template_map_[existing_turl->sync_guid()] = existing_turl;
if (service_.get())
- service_->UpdateKeyword(*existing_turl);
+ service_->UpdateKeyword(existing_turl->data());
// Inform sync of the update.
ProcessTemplateURLChange(existing_turl, SyncChange::ACTION_UPDATE);
@@ -1564,9 +1709,21 @@
string16 original_keyword(t_url->keyword());
t_url->InvalidateCachedValues();
const string16& new_keyword(t_url->keyword());
+ KeywordToTemplateMap::const_iterator i =
+ keyword_to_template_map_.find(new_keyword);
+ if ((i != keyword_to_template_map_.end()) && (i->second != t_url)) {
+ // The new autogenerated keyword conflicts with another TemplateURL.
+ // Overwrite it if it's replaceable; otherwise just reset |t_url|'s
+ // keyword. (This will not prevent |t_url| from auto-updating the
+ // keyword in the future if the conflicting TemplateURL disappears.)
+ if (!CanReplace(i->second)) {
+ t_url->data_.SetKeyword(original_keyword);
+ continue;
+ }
+ RemoveNoNotify(i->second);
+ }
RemoveFromKeywordMapByPointer(t_url);
- if (!new_keyword.empty())
- keyword_to_template_map_[new_keyword] = t_url;
+ keyword_to_template_map_[new_keyword] = t_url;
}
}
@@ -1631,7 +1788,8 @@
TemplateURLData data(new_default_from_prefs->data());
data.created_by_policy = true;
new_template = new TemplateURL(profile_, data);
- AddNoNotify(new_template, true);
+ if (!AddNoNotify(new_template, true))
+ return;
}
SetDefaultSearchProviderNoNotify(new_template);
}
@@ -1644,7 +1802,8 @@
TemplateURLData data(new_default_from_prefs->data());
data.created_by_policy = true;
new_template = new TemplateURL(profile_, data);
- AddNoNotify(new_template, true);
+ if (!AddNoNotify(new_template, true))
+ return;
}
SetDefaultSearchProviderNoNotify(new_template);
} else {
@@ -1686,7 +1845,7 @@
// template urls we ship with.
url->data_.show_in_default_list = true;
if (service_.get())
- service_->UpdateKeyword(*url);
+ service_->UpdateKeyword(url->data());
if (url->url_ref().HasGoogleBaseURLs()) {
GoogleURLTracker::RequestServerCheck();
@@ -1720,7 +1879,7 @@
ProcessTemplateURLChange(url, SyncChange::ACTION_UPDATE);
}
-void TemplateURLService::AddNoNotify(TemplateURL* template_url,
+bool TemplateURLService::AddNoNotify(TemplateURL* template_url,
bool newly_adding) {
DCHECK(template_url);
@@ -1731,6 +1890,27 @@
template_url->data_.id = ++next_id_;
}
+ template_url->ResetKeywordIfNecessary(false);
+ if (!template_url->IsExtensionKeyword()) {
+ // Check whether |template_url|'s keyword conflicts with any already in the
+ // model.
+ TemplateURL* existing_keyword_turl =
+ FindNonExtensionTemplateURLForKeyword(template_url->keyword());
+ if (existing_keyword_turl != NULL) {
+ DCHECK_NE(existing_keyword_turl, template_url);
+ if (CanReplace(existing_keyword_turl)) {
+ RemoveNoNotify(existing_keyword_turl);
+ } else if (CanReplace(template_url)) {
+ delete template_url;
+ return false;
+ } else {
+ string16 new_keyword = UniquifyKeyword(*existing_keyword_turl);
+ ResetTemplateURL(existing_keyword_turl,
+ existing_keyword_turl->short_name(), new_keyword,
+ existing_keyword_turl->url());
+ }
+ }
+ }
template_urls_.push_back(template_url);
AddToMaps(template_url);
@@ -1740,12 +1920,14 @@
// TODO(mpcomplete): If we allow editing extension keywords, then those
// should be persisted to disk and synced.
if (service_.get() && !template_url->IsExtensionKeyword())
- service_->AddKeyword(*template_url);
+ service_->AddKeyword(template_url->data());
// Inform sync of the addition. Note that this will assign a GUID to
// template_url and add it to the guid_to_template_map_.
ProcessTemplateURLChange(template_url, SyncChange::ACTION_ADD);
}
+
+ return true;
}
void TemplateURLService::RemoveNoNotify(TemplateURL* template_url) {
@@ -1863,9 +2045,8 @@
// First, try to return the generated keyword for the TemplateURL.
GURL gurl(turl.url());
if (gurl.is_valid()) {
- string16 keyword_candidate = GenerateKeyword(gurl, true);
- if (!GetTemplateURLForKeyword(keyword_candidate) &&
- !keyword_candidate.empty())
+ string16 keyword_candidate = GenerateKeyword(gurl);
+ if (!GetTemplateURLForKeyword(keyword_candidate))
return keyword_candidate;
}
@@ -1880,20 +2061,18 @@
return keyword_candidate;
}
-bool TemplateURLService::ResolveSyncKeywordConflict(
+void TemplateURLService::ResolveSyncKeywordConflict(
TemplateURL* sync_turl,
+ TemplateURL* local_turl,
SyncChangeList* change_list) {
DCHECK(sync_turl);
+ DCHECK(local_turl);
+ DCHECK(sync_turl->sync_guid() != local_turl->sync_guid());
+ DCHECK(!local_turl->IsExtensionKeyword());
DCHECK(change_list);
- TemplateURL* existing_turl =
- GetTemplateURLForKeyword(sync_turl->keyword());
- // If there is no conflict, or it's just conflicting with itself, return.
- if (!existing_turl || existing_turl->sync_guid() == sync_turl->sync_guid())
- return false;
-
- if (existing_turl->last_modified() > sync_turl->last_modified() ||
- existing_turl->created_by_policy()) {
+ if (local_turl->last_modified() > sync_turl->last_modified() ||
+ local_turl->created_by_policy()) {
string16 new_keyword = UniquifyKeyword(*sync_turl);
DCHECK(!GetTemplateURLForKeyword(new_keyword));
sync_turl->data_.SetKeyword(new_keyword);
@@ -1902,14 +2081,24 @@
SyncData sync_data = CreateSyncDataFromTemplateURL(*sync_turl);
change_list->push_back(SyncChange(SyncChange::ACTION_UPDATE, sync_data));
} else {
- string16 new_keyword = UniquifyKeyword(*existing_turl);
- TemplateURLData data(existing_turl->data());
+ string16 new_keyword = UniquifyKeyword(*local_turl);
+ TemplateURLData data(local_turl->data());
data.SetKeyword(new_keyword);
- TemplateURL new_turl(existing_turl->profile(), data);
- UpdateNoNotify(existing_turl, new_turl);
+ TemplateURL new_turl(local_turl->profile(), data);
+ UpdateNoNotify(local_turl, new_turl);
NotifyObservers();
+ if (!models_associated_) {
+ // We're doing our initial sync, so UpdateNoNotify() won't have generated
+ // an ACTION_UPDATE. If this local URL is one that was just newly brought
+ // down from the sync server, we need to go ahead and generate an update
+ // for it. If it was pre-existing, then this is unnecessary (and in fact
+ // wrong) because MergeDataAndStartSyncing() will later add an ACTION_ADD
+ // for this URL; but in this case, PreventDuplicateGUIDUpdates() will
+ // prune out the ACTION_UPDATE we create here.
+ SyncData sync_data = CreateSyncDataFromTemplateURL(*local_turl);
+ change_list->push_back(SyncChange(SyncChange::ACTION_UPDATE, sync_data));
+ }
}
- return true;
}
TemplateURL* TemplateURLService::FindDuplicateOfSyncTemplateURL(
@@ -1997,7 +2186,7 @@
!template_url->IsExtensionKeyword()) {
template_url->data_.sync_guid = guid::GenerateGUID();
if (service_.get())
- service_->UpdateKeyword(*template_url);
+ service_->UpdateKeyword(template_url->data());
}
}
}

Powered by Google App Engine
This is Rietveld 408576698