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