recently_closed_tabs_handler.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/recently_closed_tabs_handler.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/tab_restore_service_delegate.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/tab_restore_service_factory.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/host_desktop.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/new_tab_ui.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/web_contents_view.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_ui.h" 194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/base/webui/web_ui_util.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/session_restore.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabToValue(const TabRestoreService::Tab& tab, 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DictionaryValue* dictionary) { 29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const sessions::SerializedNavigationEntry& current_navigation = 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab.navigations.at(tab.current_navigation_index); 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NewTabUI::SetUrlTitleAndDirection(dictionary, current_navigation.title(), 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_navigation.virtual_url()); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dictionary->SetString("type", "tab"); 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dictionary->SetDouble("timestamp", tab.timestamp.ToDoubleT()); 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WindowToValue(const TabRestoreService::Window& window, 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DictionaryValue* dictionary) { 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!window.tabs.empty()); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<ListValue> tab_values(new ListValue()); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < window.tabs.size(); ++i) { 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DictionaryValue* tab_value = new DictionaryValue(); 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabToValue(window.tabs[i], tab_value); 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_values->Append(tab_value); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dictionary->SetString("type", "window"); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dictionary->SetDouble("timestamp", window.timestamp.ToDoubleT()); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dictionary->Set("tabs", tab_values.release()); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RecentlyClosedTabsHandler::RegisterMessages() { 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui()->RegisterMessageCallback("getRecentlyClosedTabs", 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&RecentlyClosedTabsHandler::HandleGetRecentlyClosedTabs, 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this))); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui()->RegisterMessageCallback("reopenTab", 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&RecentlyClosedTabsHandler::HandleReopenTab, 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this))); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui()->RegisterMessageCallback("clearRecentlyClosed", 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&RecentlyClosedTabsHandler::HandleClearRecentlyClosed, 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this))); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RecentlyClosedTabsHandler::~RecentlyClosedTabsHandler() { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_restore_service_) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_restore_service_->RemoveObserver(this); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RecentlyClosedTabsHandler::HandleReopenTab(const ListValue* args) { 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!tab_restore_service_) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double session_to_restore = 0.0; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(args->GetDouble(0, &session_to_restore)); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Find and remove the corresponding tab entry from TabRestoreService. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We take ownership of the returned tab. 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<TabRestoreService::Tab> tab_entry( 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_restore_service_->RemoveTabEntryById(static_cast<int>( 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) session_to_restore))); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_entry.get() == NULL) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // RestoreForeignSessionTab needs a SessionTab. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SessionTab session_tab; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) session_tab.current_navigation_index = tab_entry->current_navigation_index; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) session_tab.navigations = tab_entry->navigations; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SessionRestore::RestoreForeignSessionTab(web_ui()->GetWebContents(), 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) session_tab, NEW_FOREGROUND_TAB); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double index = -1.0; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(args->GetDouble(1, &index)); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There are actually less than 20 restore tab items displayed in the UI. 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("NewTabPage.SessionRestore", 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<int>(index), 20); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabRestoreServiceDelegate* delegate = 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabRestoreServiceDelegate::FindDelegateForWebContents( 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui()->GetWebContents()); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!delegate) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chrome::HostDesktopType host_desktop_type = 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chrome::GetHostDesktopTypeForNativeView( 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) web_ui()->GetWebContents()->GetView()->GetNativeView()); 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WindowOpenDisposition disposition = webui::GetDispositionFromClick(args, 2); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_restore_service_->RestoreEntryById(delegate, 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<int>(session_to_restore), 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) host_desktop_type, 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) disposition); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The current tab has been nuked at this point; don't touch any member 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // variables. 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RecentlyClosedTabsHandler::HandleClearRecentlyClosed( 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ListValue* args) { 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnsureTabRestoreService(); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_restore_service_) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_restore_service_->ClearEntries(); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RecentlyClosedTabsHandler::HandleGetRecentlyClosedTabs( 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ListValue* args) { 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnsureTabRestoreService(); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_restore_service_) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabRestoreServiceChanged(tab_restore_service_); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RecentlyClosedTabsHandler::TabRestoreServiceChanged( 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabRestoreService* service) { 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ListValue list_value; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabRestoreService::Entries entries = service->entries(); 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CreateRecentlyClosedValues(entries, &list_value); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui()->CallJavascriptFunction("ntp.setRecentlyClosedTabs", list_value); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RecentlyClosedTabsHandler::TabRestoreServiceDestroyed( 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabRestoreService* service) { 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_restore_service_ = NULL; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RecentlyClosedTabsHandler::CreateRecentlyClosedValues( 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const TabRestoreService::Entries& entries, ListValue* entry_list_value) { 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int max_count = 10; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int added_count = 0; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We filter the list of recently closed to only show 'interesting' entries, 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // where an interesting entry is either a closed window or a closed tab 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // whose selected navigation is not the new tab ui. 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (TabRestoreService::Entries::const_iterator it = entries.begin(); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != entries.end() && added_count < max_count; ++it) { 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabRestoreService::Entry* entry = *it; 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<DictionaryValue> entry_dict(new DictionaryValue()); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (entry->type == TabRestoreService::TAB) { 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabToValue(*static_cast<TabRestoreService::Tab*>(entry), 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_dict.get()); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(entry->type, TabRestoreService::WINDOW); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WindowToValue(*static_cast<TabRestoreService::Window*>(entry), 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_dict.get()); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_dict->SetInteger("sessionId", entry->id); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_list_value->Append(entry_dict.release()); 172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ++added_count; 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RecentlyClosedTabsHandler::EnsureTabRestoreService() { 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_restore_service_) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_restore_service_ = 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabRestoreServiceFactory::GetForProfile(Profile::FromWebUI(web_ui())); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TabRestoreServiceFactory::GetForProfile() can return NULL (i.e., when in 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Off the Record mode) 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_restore_service_) { 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This does nothing if the tabs have already been loaded or they 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // shouldn't be loaded. 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_restore_service_->LoadTabsFromLastSession(); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_restore_service_->AddObserver(this); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 192