Commit adf05659 authored by Kristi Park's avatar Kristi Park Committed by Commit Bot

[NTP] Separate internal custom link updates from user changes

When a default URL scheme is updated after URL validation, it is counted
as a user action. This causes "Undo" to revert the URL scheme update
instead of the user's add/update action.

Add an additional parameter to CustomLinksManager::UpdateLink in order
to distinguish between internal and user changes. Internal changes will
not update the previous state that is restored when
CustomLinksManager::UndoAction is called.

Bug: 896143
Change-Id: I643679fab5e546fac7e41214af6ff8a4ba9c8b53
Reviewed-on: https://chromium-review.googlesource.com/c/1287259
Commit-Queue: Kristi Park <kristipark@chromium.org>
Reviewed-by: default avatarMarc Treib <treib@chromium.org>
Cr-Commit-Position: refs/heads/master@{#600988}
parent 1436aab9
...@@ -324,7 +324,8 @@ bool InstantService::UpdateCustomLink(const GURL& url, ...@@ -324,7 +324,8 @@ bool InstantService::UpdateCustomLink(const GURL& url,
const std::string& new_title) { const std::string& new_title) {
if (most_visited_sites_) { if (most_visited_sites_) {
return most_visited_sites_->UpdateCustomLink(url, new_url, return most_visited_sites_->UpdateCustomLink(url, new_url,
base::UTF8ToUTF16(new_title)); base::UTF8ToUTF16(new_title),
/*is_user_action=*/true);
} }
return false; return false;
} }
...@@ -489,11 +490,14 @@ void InstantService::OnDoesUrlResolveComplete( ...@@ -489,11 +490,14 @@ void InstantService::OnDoesUrlResolveComplete(
// already timed out. // already timed out.
if (duration > if (duration >
base::TimeDelta::FromSeconds(kCustomLinkDialogTimeoutSeconds)) { base::TimeDelta::FromSeconds(kCustomLinkDialogTimeoutSeconds)) {
GURL::Replacements replacements;
replacements.SetSchemeStr(url::kHttpScheme);
GURL new_url = url.ReplaceComponents(replacements);
UpdateCustomLink(url, new_url, /*new_title=*/std::string());
timeout = true; timeout = true;
if (most_visited_sites_) {
GURL::Replacements replacements;
replacements.SetSchemeStr(url::kHttpScheme);
GURL new_url = url.ReplaceComponents(replacements);
most_visited_sites_->UpdateCustomLink(url, new_url, base::string16(),
/*is_user_action=*/false);
}
} }
} }
std::move(callback).Run(resolves, timeout); std::move(callback).Run(resolves, timeout);
......
...@@ -65,10 +65,13 @@ class CustomLinksManager { ...@@ -65,10 +65,13 @@ class CustomLinksManager {
// no longer be considered Most Visited. Returns false and does nothing if // no longer be considered Most Visited. Returns false and does nothing if
// custom links is not initialized, either URL is invalid, |url| does not // custom links is not initialized, either URL is invalid, |url| does not
// exist in the list, |new_url| already exists in the list, or both parameters // exist in the list, |new_url| already exists in the list, or both parameters
// are empty. // are empty. |is_user_action| is true if this was executed by the user (i.e.
// by editing a custom link). Only user actions will update the previous state
// that is restored when CustomLinksManager::UndoAction is called.
virtual bool UpdateLink(const GURL& url, virtual bool UpdateLink(const GURL& url,
const GURL& new_url, const GURL& new_url,
const base::string16& new_title) = 0; const base::string16& new_title,
bool is_user_action) = 0;
// Deletes the link with the specified |url|. Returns false and does nothing // Deletes the link with the specified |url|. Returns false and does nothing
// if custom links is not initialized, |url| is invalid, or |url| does not // if custom links is not initialized, |url| is invalid, or |url| does not
// exist in the list. // exist in the list.
......
...@@ -94,7 +94,8 @@ bool CustomLinksManagerImpl::AddLink(const GURL& url, ...@@ -94,7 +94,8 @@ bool CustomLinksManagerImpl::AddLink(const GURL& url,
bool CustomLinksManagerImpl::UpdateLink(const GURL& url, bool CustomLinksManagerImpl::UpdateLink(const GURL& url,
const GURL& new_url, const GURL& new_url,
const base::string16& new_title) { const base::string16& new_title,
bool is_user_action) {
if (!IsInitialized() || !url.is_valid() || if (!IsInitialized() || !url.is_valid() ||
(new_url.is_empty() && new_title.empty())) { (new_url.is_empty() && new_title.empty())) {
return false; return false;
...@@ -112,7 +113,10 @@ bool CustomLinksManagerImpl::UpdateLink(const GURL& url, ...@@ -112,7 +113,10 @@ bool CustomLinksManagerImpl::UpdateLink(const GURL& url,
return false; return false;
// At this point, we will be modifying at least one of the values. // At this point, we will be modifying at least one of the values.
previous_links_ = current_links_; if (is_user_action) {
// Save the previous state since this was a user update.
previous_links_ = current_links_;
}
if (!new_url.is_empty()) if (!new_url.is_empty())
it->url = new_url; it->url = new_url;
......
...@@ -48,7 +48,8 @@ class CustomLinksManagerImpl : public CustomLinksManager, ...@@ -48,7 +48,8 @@ class CustomLinksManagerImpl : public CustomLinksManager,
bool AddLink(const GURL& url, const base::string16& title) override; bool AddLink(const GURL& url, const base::string16& title) override;
bool UpdateLink(const GURL& url, bool UpdateLink(const GURL& url,
const GURL& new_url, const GURL& new_url,
const base::string16& new_title) override; const base::string16& new_title,
bool is_user_action) override;
bool DeleteLink(const GURL& url) override; bool DeleteLink(const GURL& url) override;
bool UndoAction() override; bool UndoAction() override;
......
...@@ -219,18 +219,20 @@ TEST_F(CustomLinksManagerImplTest, UpdateLink) { ...@@ -219,18 +219,20 @@ TEST_F(CustomLinksManagerImplTest, UpdateLink) {
// Update the link's URL. // Update the link's URL.
EXPECT_TRUE(custom_links_->UpdateLink(GURL(kTestCase1[0].url), GURL(kTestUrl), EXPECT_TRUE(custom_links_->UpdateLink(GURL(kTestCase1[0].url), GURL(kTestUrl),
base::string16())); base::string16(),
/*is_user_action=*/true));
EXPECT_EQ(links_after_update_url, custom_links_->GetLinks()); EXPECT_EQ(links_after_update_url, custom_links_->GetLinks());
// Update the link's title. // Update the link's title.
EXPECT_TRUE(custom_links_->UpdateLink(GURL(kTestUrl), GURL(), EXPECT_TRUE(custom_links_->UpdateLink(GURL(kTestUrl), GURL(),
base::UTF8ToUTF16(kTestTitle))); base::UTF8ToUTF16(kTestTitle),
/*is_user_action=*/true));
EXPECT_EQ(links_after_update_title, custom_links_->GetLinks()); EXPECT_EQ(links_after_update_title, custom_links_->GetLinks());
// Update the link's URL and title. // Update the link's URL and title.
EXPECT_TRUE( EXPECT_TRUE(custom_links_->UpdateLink(GURL(kTestUrl), GURL(kTestCase1[0].url),
custom_links_->UpdateLink(GURL(kTestUrl), GURL(kTestCase1[0].url), base::UTF8ToUTF16(kTestCase1[0].title),
base::UTF8ToUTF16(kTestCase1[0].title))); /*is_user_action=*/true));
EXPECT_EQ(links_after_update_both, custom_links_->GetLinks()); EXPECT_EQ(links_after_update_both, custom_links_->GetLinks());
} }
...@@ -246,20 +248,24 @@ TEST_F(CustomLinksManagerImplTest, UpdateLinkWithInvalidParams) { ...@@ -246,20 +248,24 @@ TEST_F(CustomLinksManagerImplTest, UpdateLinkWithInvalidParams) {
// Try to update a link that does not exist. This should fail and not modify // Try to update a link that does not exist. This should fail and not modify
// the list. // the list.
EXPECT_FALSE(custom_links_->UpdateLink(GURL(kTestUrl), GURL(), EXPECT_FALSE(custom_links_->UpdateLink(GURL(kTestUrl), GURL(),
base::UTF8ToUTF16(kTestTitle))); base::UTF8ToUTF16(kTestTitle),
/*is_user_action=*/true));
EXPECT_EQ(initial_links, custom_links_->GetLinks()); EXPECT_EQ(initial_links, custom_links_->GetLinks());
// Try to pass empty params. This should fail and not modify the list. // Try to pass empty params. This should fail and not modify the list.
EXPECT_FALSE(custom_links_->UpdateLink(GURL(kTestCase1[0].url), GURL(), EXPECT_FALSE(custom_links_->UpdateLink(GURL(kTestCase1[0].url), GURL(),
base::string16())); base::string16(),
/*is_user_action=*/true));
EXPECT_EQ(initial_links, custom_links_->GetLinks()); EXPECT_EQ(initial_links, custom_links_->GetLinks());
// Try to pass an invalid URL. This should fail and not modify the list. // Try to pass an invalid URL. This should fail and not modify the list.
EXPECT_FALSE(custom_links_->UpdateLink(kInvalidUrl, GURL(), EXPECT_FALSE(custom_links_->UpdateLink(kInvalidUrl, GURL(),
base::UTF8ToUTF16(kTestTitle))); base::UTF8ToUTF16(kTestTitle),
/*is_user_action=*/true));
EXPECT_EQ(initial_links, custom_links_->GetLinks()); EXPECT_EQ(initial_links, custom_links_->GetLinks());
EXPECT_FALSE(custom_links_->UpdateLink(GURL(kTestCase1[0].url), kInvalidUrl, EXPECT_FALSE(custom_links_->UpdateLink(GURL(kTestCase1[0].url), kInvalidUrl,
base::string16())); base::string16(),
/*is_user_action=*/true));
EXPECT_EQ(initial_links, custom_links_->GetLinks()); EXPECT_EQ(initial_links, custom_links_->GetLinks());
} }
...@@ -274,7 +280,8 @@ TEST_F(CustomLinksManagerImplTest, UpdateLinkWhenUrlAlreadyExists) { ...@@ -274,7 +280,8 @@ TEST_F(CustomLinksManagerImplTest, UpdateLinkWhenUrlAlreadyExists) {
// Try to update a link with a URL that exists in the list. This should fail // Try to update a link with a URL that exists in the list. This should fail
// and not modify the list. // and not modify the list.
EXPECT_FALSE(custom_links_->UpdateLink( EXPECT_FALSE(custom_links_->UpdateLink(
GURL(kTestCase2[0].url), GURL(kTestCase2[1].url), base::string16())); GURL(kTestCase2[0].url), GURL(kTestCase2[1].url), base::string16(),
/*is_user_action=*/true));
EXPECT_EQ(initial_links, custom_links_->GetLinks()); EXPECT_EQ(initial_links, custom_links_->GetLinks());
} }
...@@ -350,7 +357,8 @@ TEST_F(CustomLinksManagerImplTest, UndoUpdateLink) { ...@@ -350,7 +357,8 @@ TEST_F(CustomLinksManagerImplTest, UndoUpdateLink) {
// Update the link's URL. // Update the link's URL.
EXPECT_TRUE(custom_links_->UpdateLink(GURL(kTestCase1[0].url), GURL(kTestUrl), EXPECT_TRUE(custom_links_->UpdateLink(GURL(kTestCase1[0].url), GURL(kTestUrl),
base::string16())); base::string16(),
/*is_user_action=*/true));
EXPECT_EQ(links_after_update_url, custom_links_->GetLinks()); EXPECT_EQ(links_after_update_url, custom_links_->GetLinks());
// Undo update link. // Undo update link.
...@@ -359,7 +367,8 @@ TEST_F(CustomLinksManagerImplTest, UndoUpdateLink) { ...@@ -359,7 +367,8 @@ TEST_F(CustomLinksManagerImplTest, UndoUpdateLink) {
// Update the link's title. // Update the link's title.
EXPECT_TRUE(custom_links_->UpdateLink(GURL(kTestCase1[0].url), GURL(), EXPECT_TRUE(custom_links_->UpdateLink(GURL(kTestCase1[0].url), GURL(),
base::UTF8ToUTF16(kTestTitle))); base::UTF8ToUTF16(kTestTitle),
/*is_user_action=*/true));
EXPECT_EQ(links_after_update_title, custom_links_->GetLinks()); EXPECT_EQ(links_after_update_title, custom_links_->GetLinks());
// Undo update link. // Undo update link.
...@@ -413,6 +422,48 @@ TEST_F(CustomLinksManagerImplTest, UndoDeleteLinkAfterAdd) { ...@@ -413,6 +422,48 @@ TEST_F(CustomLinksManagerImplTest, UndoDeleteLinkAfterAdd) {
EXPECT_EQ(expected_links, custom_links_->GetLinks()); EXPECT_EQ(expected_links, custom_links_->GetLinks());
} }
TEST_F(CustomLinksManagerImplTest, ShouldNotUndoActionIfInternal) {
NTPTilesVector initial_tiles = FillTestTiles(kTestCase1);
std::vector<Link> initial_links = FillTestLinks(kTestCase1);
std::vector<Link> links_after_update_twice;
links_after_update_twice.emplace_back(
Link{GURL(kTestUrl), base::UTF8ToUTF16(kTestTitle), false});
std::vector<Link> links_after_add_and_update(initial_links);
links_after_add_and_update.emplace_back(Link{
GURL(kTestCase2[1].url), base::UTF8ToUTF16(kTestCase2[1].title), false});
links_after_add_and_update[0].url = GURL(kTestUrl);
links_after_add_and_update[0].is_most_visited = false;
// Initialize.
ASSERT_TRUE(custom_links_->Initialize(initial_tiles));
ASSERT_EQ(initial_links, custom_links_->GetLinks());
// Update twice. Specify that the second update was internal.
EXPECT_TRUE(custom_links_->UpdateLink(GURL(kTestCase1[0].url), GURL(),
base::UTF8ToUTF16(kTestTitle),
/*is_user_action=*/true));
EXPECT_TRUE(custom_links_->UpdateLink(GURL(kTestCase1[0].url), GURL(kTestUrl),
base::string16(),
/*is_user_action=*/false));
EXPECT_EQ(links_after_update_twice, custom_links_->GetLinks());
// Undo should revert to the state before the first action.
EXPECT_TRUE(custom_links_->UndoAction());
EXPECT_EQ(initial_links, custom_links_->GetLinks());
// Add then update. Specify that the update was internal.
EXPECT_TRUE(custom_links_->AddLink(GURL(kTestCase2[1].url),
base::UTF8ToUTF16(kTestCase2[1].title)));
EXPECT_TRUE(custom_links_->UpdateLink(GURL(kTestCase1[0].url), GURL(kTestUrl),
base::string16(),
/*is_user_action=*/false));
EXPECT_EQ(links_after_add_and_update, custom_links_->GetLinks());
// Undo should revert to the state before the first action.
EXPECT_TRUE(custom_links_->UndoAction());
EXPECT_EQ(initial_links, custom_links_->GetLinks());
}
TEST_F(CustomLinksManagerImplTest, ShouldDeleteMostVisitedOnHistoryDeletion) { TEST_F(CustomLinksManagerImplTest, ShouldDeleteMostVisitedOnHistoryDeletion) {
NTPTilesVector initial_tiles = FillTestTiles(kTestCase2); NTPTilesVector initial_tiles = FillTestTiles(kTestCase2);
std::vector<Link> initial_links = FillTestLinks(kTestCase2); std::vector<Link> initial_links = FillTestLinks(kTestCase2);
......
...@@ -301,16 +301,19 @@ bool MostVisitedSites::AddCustomLink(const GURL& url, ...@@ -301,16 +301,19 @@ bool MostVisitedSites::AddCustomLink(const GURL& url,
bool MostVisitedSites::UpdateCustomLink(const GURL& url, bool MostVisitedSites::UpdateCustomLink(const GURL& url,
const GURL& new_url, const GURL& new_url,
const base::string16& new_title) { const base::string16& new_title,
bool is_user_action) {
if (!custom_links_ || !custom_links_enabled_) if (!custom_links_ || !custom_links_enabled_)
return false; return false;
// Initialize custom links if they have not been initialized yet. // Initialize custom links if they have not been initialized yet.
InitializeCustomLinks(); InitializeCustomLinks();
bool success = custom_links_->UpdateLink(url, new_url, new_title); bool success =
custom_links_->UpdateLink(url, new_url, new_title, is_user_action);
if (success) { if (success) {
if (custom_links_action_count_ != -1) // Only update the action count if this was executed by the user.
if (is_user_action && custom_links_action_count_ != -1)
custom_links_action_count_++; custom_links_action_count_++;
BuildCurrentTiles(); BuildCurrentTiles();
} }
......
...@@ -180,10 +180,12 @@ class MostVisitedSites : public history::TopSitesObserver, ...@@ -180,10 +180,12 @@ class MostVisitedSites : public history::TopSitesObserver,
// Updates the URL and/or title of the custom link specified by |url|. If // Updates the URL and/or title of the custom link specified by |url|. If
// |url| does not exist or |new_url| already exists in the custom link list, // |url| does not exist or |new_url| already exists in the custom link list,
// returns false and does nothing. Will initialize custom links if they have // returns false and does nothing. Will initialize custom links if they have
// not been initialized yet. Custom links must be enabled. // not been initialized yet. |is_user_action| is true if this was executed by
// the user (i.e. editing a custom link). Custom links must be enabled.
bool UpdateCustomLink(const GURL& url, bool UpdateCustomLink(const GURL& url,
const GURL& new_url, const GURL& new_url,
const base::string16& new_title); const base::string16& new_title,
bool is_user_action);
// Deletes the custom link with the specified |url|. If |url| does not exist // Deletes the custom link with the specified |url|. If |url| does not exist
// in the custom link list, returns false and does nothing. Will initialize // in the custom link list, returns false and does nothing. Will initialize
// custom links if they have not been initialized yet. Custom links must be // custom links if they have not been initialized yet. Custom links must be
......
...@@ -272,10 +272,11 @@ class MockCustomLinksManager : public CustomLinksManager { ...@@ -272,10 +272,11 @@ class MockCustomLinksManager : public CustomLinksManager {
MOCK_CONST_METHOD0(IsInitialized, bool()); MOCK_CONST_METHOD0(IsInitialized, bool());
MOCK_CONST_METHOD0(GetLinks, const std::vector<CustomLinksManager::Link>&()); MOCK_CONST_METHOD0(GetLinks, const std::vector<CustomLinksManager::Link>&());
MOCK_METHOD2(AddLink, bool(const GURL& url, const base::string16& title)); MOCK_METHOD2(AddLink, bool(const GURL& url, const base::string16& title));
MOCK_METHOD3(UpdateLink, MOCK_METHOD4(UpdateLink,
bool(const GURL& url, bool(const GURL& url,
const GURL& new_url, const GURL& new_url,
const base::string16& new_title)); const base::string16& new_title,
bool is_user_action));
MOCK_METHOD1(DeleteLink, bool(const GURL& url)); MOCK_METHOD1(DeleteLink, bool(const GURL& url));
MOCK_METHOD0(UndoAction, bool()); MOCK_METHOD0(UndoAction, bool());
MOCK_METHOD1(RegisterCallbackForOnChanged, MOCK_METHOD1(RegisterCallbackForOnChanged,
...@@ -1501,7 +1502,8 @@ TEST_P(MostVisitedSitesWithCustomLinksTest, ...@@ -1501,7 +1502,8 @@ TEST_P(MostVisitedSitesWithCustomLinksTest,
// Initialize custom links and complete a custom link action. // Initialize custom links and complete a custom link action.
EXPECT_CALL(*mock_custom_links_, Initialize(_)).WillOnce(Return(true)); EXPECT_CALL(*mock_custom_links_, Initialize(_)).WillOnce(Return(true));
EXPECT_CALL(*mock_custom_links_, UpdateLink(_, _, _)).WillOnce(Return(true)); EXPECT_CALL(*mock_custom_links_, UpdateLink(_, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(*mock_custom_links_, IsInitialized()) EXPECT_CALL(*mock_custom_links_, IsInitialized())
.WillRepeatedly(Return(true)); .WillRepeatedly(Return(true));
EXPECT_CALL(*mock_custom_links_, GetLinks()) EXPECT_CALL(*mock_custom_links_, GetLinks())
...@@ -1509,7 +1511,8 @@ TEST_P(MostVisitedSitesWithCustomLinksTest, ...@@ -1509,7 +1511,8 @@ TEST_P(MostVisitedSitesWithCustomLinksTest,
EXPECT_CALL(mock_observer_, OnURLsAvailable(_)) EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
.WillOnce(SaveArg<0>(&sections)); .WillOnce(SaveArg<0>(&sections));
most_visited_sites_->UpdateCustomLink(GURL("test.com"), GURL("test.com"), most_visited_sites_->UpdateCustomLink(GURL("test.com"), GURL("test.com"),
base::UTF8ToUTF16("test")); base::UTF8ToUTF16("test"),
/*is_user_action=*/true);
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
ASSERT_THAT( ASSERT_THAT(
sections.at(SectionType::PERSONALIZED), sections.at(SectionType::PERSONALIZED),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment