1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/webui/ntp/recently_closed_tabs_handler.h"
8 #include "base/bind_helpers.h"
9 #include "base/metrics/histogram.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/sessions/tab_restore_service_delegate.h"
12 #include "chrome/browser/sessions/tab_restore_service_factory.h"
13 #include "chrome/browser/ui/host_desktop.h"
14 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
15 #include "chrome/common/url_constants.h"
16 #include "content/public/browser/web_contents.h"
17 #include "content/public/browser/web_contents_view.h"
18 #include "content/public/browser/web_ui.h"
19 #include "ui/base/webui/web_ui_util.h"
21 #if defined(OS_ANDROID)
22 #include "chrome/browser/sessions/session_restore.h"
27 void TabToValue(const TabRestoreService::Tab
& tab
,
28 base::DictionaryValue
* dictionary
) {
29 const sessions::SerializedNavigationEntry
& current_navigation
=
30 tab
.navigations
.at(tab
.current_navigation_index
);
31 NewTabUI::SetUrlTitleAndDirection(dictionary
, current_navigation
.title(),
32 current_navigation
.virtual_url());
33 dictionary
->SetString("type", "tab");
34 dictionary
->SetDouble("timestamp", tab
.timestamp
.ToDoubleT());
37 void WindowToValue(const TabRestoreService::Window
& window
,
38 base::DictionaryValue
* dictionary
) {
39 DCHECK(!window
.tabs
.empty());
41 scoped_ptr
<base::ListValue
> tab_values(new base::ListValue());
42 for (size_t i
= 0; i
< window
.tabs
.size(); ++i
) {
43 base::DictionaryValue
* tab_value
= new base::DictionaryValue();
44 TabToValue(window
.tabs
[i
], tab_value
);
45 tab_values
->Append(tab_value
);
48 dictionary
->SetString("type", "window");
49 dictionary
->SetDouble("timestamp", window
.timestamp
.ToDoubleT());
50 dictionary
->Set("tabs", tab_values
.release());
55 void RecentlyClosedTabsHandler::RegisterMessages() {
56 web_ui()->RegisterMessageCallback("getRecentlyClosedTabs",
57 base::Bind(&RecentlyClosedTabsHandler::HandleGetRecentlyClosedTabs
,
58 base::Unretained(this)));
59 web_ui()->RegisterMessageCallback("reopenTab",
60 base::Bind(&RecentlyClosedTabsHandler::HandleReopenTab
,
61 base::Unretained(this)));
62 web_ui()->RegisterMessageCallback("clearRecentlyClosed",
63 base::Bind(&RecentlyClosedTabsHandler::HandleClearRecentlyClosed
,
64 base::Unretained(this)));
67 RecentlyClosedTabsHandler::~RecentlyClosedTabsHandler() {
68 if (tab_restore_service_
)
69 tab_restore_service_
->RemoveObserver(this);
72 void RecentlyClosedTabsHandler::HandleReopenTab(const base::ListValue
* args
) {
73 if (!tab_restore_service_
)
76 double session_to_restore
= 0.0;
77 CHECK(args
->GetDouble(0, &session_to_restore
));
79 #if defined(OS_ANDROID)
80 // Find and remove the corresponding tab entry from TabRestoreService.
81 // We take ownership of the returned tab.
82 scoped_ptr
<TabRestoreService::Tab
> tab_entry(
83 tab_restore_service_
->RemoveTabEntryById(static_cast<int>(
84 session_to_restore
)));
85 if (tab_entry
.get() == NULL
)
88 // RestoreForeignSessionTab needs a SessionTab.
89 SessionTab session_tab
;
90 session_tab
.current_navigation_index
= tab_entry
->current_navigation_index
;
91 session_tab
.navigations
= tab_entry
->navigations
;
93 SessionRestore::RestoreForeignSessionTab(web_ui()->GetWebContents(),
94 session_tab
, NEW_FOREGROUND_TAB
);
97 CHECK(args
->GetDouble(1, &index
));
99 // There are actually less than 20 restore tab items displayed in the UI.
100 UMA_HISTOGRAM_ENUMERATION("NewTabPage.SessionRestore",
101 static_cast<int>(index
), 20);
103 TabRestoreServiceDelegate
* delegate
=
104 TabRestoreServiceDelegate::FindDelegateForWebContents(
105 web_ui()->GetWebContents());
108 chrome::HostDesktopType host_desktop_type
=
109 chrome::GetHostDesktopTypeForNativeView(
110 web_ui()->GetWebContents()->GetView()->GetNativeView());
111 WindowOpenDisposition disposition
= webui::GetDispositionFromClick(args
, 2);
112 tab_restore_service_
->RestoreEntryById(delegate
,
113 static_cast<int>(session_to_restore
),
116 // The current tab has been nuked at this point; don't touch any member
121 void RecentlyClosedTabsHandler::HandleClearRecentlyClosed(
122 const base::ListValue
* args
) {
123 EnsureTabRestoreService();
124 if (tab_restore_service_
)
125 tab_restore_service_
->ClearEntries();
128 void RecentlyClosedTabsHandler::HandleGetRecentlyClosedTabs(
129 const base::ListValue
* args
) {
130 EnsureTabRestoreService();
131 if (tab_restore_service_
)
132 TabRestoreServiceChanged(tab_restore_service_
);
135 void RecentlyClosedTabsHandler::TabRestoreServiceChanged(
136 TabRestoreService
* service
) {
137 base::ListValue list_value
;
138 TabRestoreService::Entries entries
= service
->entries();
139 CreateRecentlyClosedValues(entries
, &list_value
);
141 web_ui()->CallJavascriptFunction("ntp.setRecentlyClosedTabs", list_value
);
144 void RecentlyClosedTabsHandler::TabRestoreServiceDestroyed(
145 TabRestoreService
* service
) {
146 tab_restore_service_
= NULL
;
150 void RecentlyClosedTabsHandler::CreateRecentlyClosedValues(
151 const TabRestoreService::Entries
& entries
,
152 base::ListValue
* entry_list_value
) {
153 const int max_count
= 10;
155 // We filter the list of recently closed to only show 'interesting' entries,
156 // where an interesting entry is either a closed window or a closed tab
157 // whose selected navigation is not the new tab ui.
158 for (TabRestoreService::Entries::const_iterator it
= entries
.begin();
159 it
!= entries
.end() && added_count
< max_count
; ++it
) {
160 TabRestoreService::Entry
* entry
= *it
;
161 scoped_ptr
<base::DictionaryValue
> entry_dict(new base::DictionaryValue());
162 if (entry
->type
== TabRestoreService::TAB
) {
163 TabToValue(*static_cast<TabRestoreService::Tab
*>(entry
),
166 DCHECK_EQ(entry
->type
, TabRestoreService::WINDOW
);
167 WindowToValue(*static_cast<TabRestoreService::Window
*>(entry
),
171 entry_dict
->SetInteger("sessionId", entry
->id
);
172 entry_list_value
->Append(entry_dict
.release());
177 void RecentlyClosedTabsHandler::EnsureTabRestoreService() {
178 if (tab_restore_service_
)
181 tab_restore_service_
=
182 TabRestoreServiceFactory::GetForProfile(Profile::FromWebUI(web_ui()));
184 // TabRestoreServiceFactory::GetForProfile() can return NULL (i.e., when in
185 // Off the Record mode)
186 if (tab_restore_service_
) {
187 // This does nothing if the tabs have already been loaded or they
188 // shouldn't be loaded.
189 tab_restore_service_
->LoadTabsFromLastSession();
190 tab_restore_service_
->AddObserver(this);