Skip to content

Commit

Permalink
Implement recently closed tabs API
Browse files Browse the repository at this point in the history
Change-Id: Id0d6b9de9e8ca125b097a4f2b22f20e00a4aeba2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2708623
Commit-Queue: Yuheng Huang <yuhengh@chromium.org>
Reviewed-by: Roman Arora <romanarora@chromium.org>
Reviewed-by: Thomas Lukaszewicz <tluk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#859122}
  • Loading branch information
Yuheng Huang authored and Chromium LUCI CQ committed Mar 2, 2021
1 parent 6bdcccb commit e56b95b
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 7 deletions.
58 changes: 54 additions & 4 deletions chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc
Expand Up @@ -19,6 +19,7 @@
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/favicon/favicon_utils.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/tab_restore_service_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
Expand All @@ -31,13 +32,14 @@
namespace {
constexpr base::TimeDelta kTabsChangeDelay =
base::TimeDelta::FromMilliseconds(50);
constexpr int kMaxRecentlyClosedTabCount = 100;

#if BUILDFLAG(IS_CHROMEOS_ASH)
constexpr char kFeedbackCategoryTag[] = "FromTabSearch";
#else
constexpr char kFeedbackCategoryTag[] = "FromTabSearchBrowser";
#endif
}
} // namespace

TabSearchPageHandler::TabSearchPageHandler(
mojo::PendingReceiver<tab_search::mojom::PageHandler> receiver,
Expand Down Expand Up @@ -171,14 +173,49 @@ tab_search::mojom::ProfileDataPtr TabSearchPageHandler::CreateProfileData() {
window->height = browser->window()->GetContentsSize().height();
for (int i = 0; i < tab_strip_model->count(); ++i) {
window->tabs.push_back(
GetTabData(tab_strip_model, tab_strip_model->GetWebContentsAt(i), i));
GetTab(tab_strip_model, tab_strip_model->GetWebContentsAt(i), i));
}
profile_data->windows.push_back(std::move(window));
}

CreateRecentlyClosedTabs(profile_data->recently_closed_tabs);
return profile_data;
}

tab_search::mojom::TabPtr TabSearchPageHandler::GetTabData(
void TabSearchPageHandler::CreateRecentlyClosedTabs(
std::vector<tab_search::mojom::RecentlyClosedTabPtr>&
recently_closed_tabs) {
sessions::TabRestoreService* tab_restore_service =
TabRestoreServiceFactory::GetForProfile(browser_->profile());
// TabRestoreService is only available for non off the record profiles.
if (tab_restore_service) {
// Flatten tab restore service entries into tabs
for (auto& entry : tab_restore_service->entries()) {
if (entry->type == sessions::TabRestoreService::Type::WINDOW) {
sessions::TabRestoreService::Window* window =
static_cast<sessions::TabRestoreService::Window*>(entry.get());
for (auto& tab : window->tabs) {
if (tab->navigations.size() == 0)
continue;
if (recently_closed_tabs.size() >= kMaxRecentlyClosedTabCount)
break;
recently_closed_tabs.push_back(GetRecentlyClosedTab(tab.get()));
}
} else if (entry->type == sessions::TabRestoreService::Type::TAB) {
sessions::TabRestoreService::Tab* tab =
static_cast<sessions::TabRestoreService::Tab*>(entry.get());
if (tab->navigations.size() == 0)
continue;
if (recently_closed_tabs.size() >= kMaxRecentlyClosedTabCount)
break;
recently_closed_tabs.push_back(GetRecentlyClosedTab(tab));
}
}
}
DCHECK(recently_closed_tabs.size() <= kMaxRecentlyClosedTabCount);
}

tab_search::mojom::TabPtr TabSearchPageHandler::GetTab(
TabStripModel* tab_strip_model,
content::WebContents* contents,
int index) {
Expand Down Expand Up @@ -214,6 +251,19 @@ tab_search::mojom::TabPtr TabSearchPageHandler::GetTabData(
return tab_data;
}

tab_search::mojom::RecentlyClosedTabPtr
TabSearchPageHandler::GetRecentlyClosedTab(
sessions::TabRestoreService::Tab* tab) {
auto recently_closed_tab = tab_search::mojom::RecentlyClosedTab::New();
DCHECK(tab->navigations.size() > 0);
sessions::SerializedNavigationEntry& entry =
tab->navigations[tab->current_navigation_index];
recently_closed_tab->title = base::UTF16ToUTF8(entry.title());
recently_closed_tab->url = entry.original_request_url().spec();
recently_closed_tab->last_active_time_ticks = entry.timestamp();
return recently_closed_tab;
}

void TabSearchPageHandler::OnTabStripModelChanged(
TabStripModel* tab_strip_model,
const TabStripModelChange& change,
Expand Down Expand Up @@ -247,7 +297,7 @@ void TabSearchPageHandler::TabChangedAt(content::WebContents* contents,
if (!browser)
return;
TRACE_EVENT0("browser", "custom_metric:TabSearchPageHandler:TabChangedAt");
page_->TabUpdated(GetTabData(browser->tab_strip_model(), contents, index));
page_->TabUpdated(GetTab(browser->tab_strip_model(), contents, index));
}

void TabSearchPageHandler::ScheduleDebounce() {
Expand Down
14 changes: 11 additions & 3 deletions chrome/browser/ui/webui/tab_search/tab_search_page_handler.h
Expand Up @@ -13,6 +13,7 @@
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
#include "chrome/browser/ui/webui/tab_search/tab_search.mojom.h"
#include "components/sessions/core/tab_restore_service.h"
#include "content/public/browser/web_contents_observer.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
Expand Down Expand Up @@ -87,9 +88,16 @@ class TabSearchPageHandler : public tab_search::mojom::PageHandler,

tab_search::mojom::ProfileDataPtr CreateProfileData();

tab_search::mojom::TabPtr GetTabData(TabStripModel* tab_strip_model,
content::WebContents* contents,
int index);
void CreateRecentlyClosedTabs(
std::vector<tab_search::mojom::RecentlyClosedTabPtr>&
recently_closed_tabs);

tab_search::mojom::TabPtr GetTab(TabStripModel* tab_strip_model,
content::WebContents* contents,
int index);
tab_search::mojom::RecentlyClosedTabPtr GetRecentlyClosedTab(
sessions::TabRestoreService::Tab* tab);

// Returns tab details required to perform an action on the tab.
base::Optional<TabDetails> GetTabDetails(int32_t tab_id);

Expand Down
Expand Up @@ -10,11 +10,14 @@
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/sessions/chrome_tab_restore_service_client.h"
#include "chrome/browser/sessions/tab_restore_service_factory.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/test/base/browser_with_test_window_test.h"
#include "chrome/test/base/test_browser_window.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "components/sessions/core/tab_restore_service_impl.h"
#include "components/sync_preferences/pref_service_syncable.h"
#include "content/public/test/test_web_ui.h"
#include "testing/gmock/include/gmock/gmock.h"
Expand Down Expand Up @@ -71,6 +74,13 @@ void ExpectNewTab(const tab_search::mojom::Tab* tab,
EXPECT_GT(tab->last_active_time_ticks, base::TimeTicks());
}

void ExpectRecentlyClosedTab(const tab_search::mojom::RecentlyClosedTab* tab,
const std::string url,
const std::string title) {
EXPECT_EQ(url, tab->url);
EXPECT_EQ(title, tab->title);
}

void ExpectProfileTabs(tab_search::mojom::ProfileData* profile_tabs) {
ASSERT_EQ(2u, profile_tabs->windows.size());
auto* window1 = profile_tabs->windows[0].get();
Expand Down Expand Up @@ -158,6 +168,14 @@ class TabSearchPageHandlerTest : public BrowserWithTestWindowTest {
void FireTimer() { handler_->mock_debounce_timer()->Fire(); }
bool IsTimerRunning() { return handler_->mock_debounce_timer()->IsRunning(); }

static std::unique_ptr<KeyedService> GetTabRestoreService(
content::BrowserContext* browser_context) {
return std::make_unique<sessions::TabRestoreServiceImpl>(
std::make_unique<ChromeTabRestoreServiceClient>(
Profile::FromBrowserContext(browser_context)),
nullptr, nullptr);
}

protected:
void AddTabWithTitle(Browser* browser,
const GURL url,
Expand Down Expand Up @@ -346,6 +364,35 @@ TEST_F(TabSearchPageHandlerTest, CloseTab) {
ASSERT_EQ(1, browser2()->tab_strip_model()->count());
}

TEST_F(TabSearchPageHandlerTest, RecentlyClosedTab) {
TabRestoreServiceFactory::GetInstance()->SetTestingFactory(
profile(),
base::BindRepeating(&TabSearchPageHandlerTest::GetTabRestoreService));
AddTabWithTitle(browser1(), GURL(kTabUrl1), kTabName1);
AddTabWithTitle(browser1(), GURL(kTabUrl2), kTabName2);
AddTabWithTitle(browser2(), GURL(kTabUrl3), kTabName3);
AddTabWithTitle(browser2(), GURL(kTabUrl4), kTabName4);
AddTabWithTitle(browser3(), GURL(kTabUrl5), kTabName5);

int tab_id = extensions::ExtensionTabUtil::GetTabId(
browser1()->tab_strip_model()->GetWebContentsAt(0));
handler()->CloseTab(tab_id);
browser2()->tab_strip_model()->CloseAllTabs();
browser3()->tab_strip_model()->CloseAllTabs();
tab_search::mojom::PageHandler::GetProfileDataCallback callback =
base::BindLambdaForTesting(
[&](tab_search::mojom::ProfileDataPtr profile_tabs) {
auto& tabs = profile_tabs->recently_closed_tabs;
ASSERT_EQ(3u, tabs.size());
ExpectRecentlyClosedTab(tabs[0].get(), kTabUrl4, kTabName4);
ExpectRecentlyClosedTab(tabs[1].get(), kTabUrl3, kTabName3);
ExpectRecentlyClosedTab(tabs[2].get(), kTabUrl2, kTabName2);
});
handler()->GetProfileData(std::move(callback));
EXPECT_CALL(page_, TabUpdated(_)).Times(2);
EXPECT_CALL(page_, TabsRemoved(_)).Times(3);
}

// TODO(crbug.com/1128855): Fix the test for Lacros build.
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#define MAYBE_ShowFeedbackPage DISABLED_ShowFeedbackPage
Expand Down

0 comments on commit e56b95b

Please sign in to comment.