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. 4 5 #include "chrome/browser/extensions/api/session_restore/session_restore_api.h" 6 7 #include <vector> 8 9 #include "base/i18n/rtl.h" 10 #include "base/lazy_instance.h" 11 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "chrome/browser/extensions/extension_function_registry.h" 14 #include "chrome/browser/extensions/extension_tab_util.h" 15 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/sessions/session_restore.h" 17 #include "chrome/browser/sessions/tab_restore_service_delegate.h" 18 #include "chrome/browser/sessions/tab_restore_service_factory.h" 19 #include "chrome/browser/sync/glue/session_model_associator.h" 20 #include "chrome/browser/sync/glue/synced_session.h" 21 #include "chrome/browser/sync/profile_sync_service.h" 22 #include "chrome/browser/sync/profile_sync_service_factory.h" 23 #include "chrome/browser/ui/browser.h" 24 #include "chrome/browser/ui/browser_finder.h" 25 #include "chrome/browser/ui/host_desktop.h" 26 #include "chrome/browser/ui/tabs/tab_strip_model.h" 27 #include "content/public/browser/web_contents.h" 28 #include "ui/base/layout.h" 29 30 31 namespace { 32 33 const unsigned int kMaxRecentlyClosedSessionResults = 25; 34 const char kRecentlyClosedListEmpty[] = 35 "There are no recently closed sessions."; 36 const char kInvalidSessionId[] = "Invalid session id."; 37 const char kNoBrowserToRestoreSession[] = 38 "There are no browser windows to restore the session."; 39 40 } // namespace 41 42 namespace extensions { 43 44 namespace GetRecentlyClosed = api::session_restore::GetRecentlyClosed; 45 namespace Restore = api::session_restore::Restore; 46 namespace tabs = api::tabs; 47 namespace windows = api::windows; 48 namespace session_restore = api::session_restore; 49 50 scoped_ptr<tabs::Tab> SessionRestoreGetRecentlyClosedFunction::CreateTabModel( 51 const TabRestoreService::Tab& tab, int selected_index) { 52 scoped_ptr<tabs::Tab> tab_struct(new tabs::Tab); 53 const sessions::SerializedNavigationEntry& current_navigation = 54 tab.navigations[tab.current_navigation_index]; 55 GURL gurl = current_navigation.virtual_url(); 56 std::string title = UTF16ToUTF8(current_navigation.title()); 57 58 tab_struct->url.reset(new std::string(gurl.spec())); 59 tab_struct->title.reset(new std::string(title.empty() ? gurl.spec() : title)); 60 tab_struct->index = tab.tabstrip_index; 61 tab_struct->pinned = tab.pinned; 62 tab_struct->id = tab.id; 63 tab_struct->window_id = tab.browser_id; 64 tab_struct->index = tab.tabstrip_index; 65 tab_struct->pinned = tab.pinned; 66 tab_struct->selected = tab.tabstrip_index == selected_index; 67 tab_struct->active = false; 68 tab_struct->highlighted = false; 69 tab_struct->incognito = false; 70 ExtensionTabUtil::ScrubTabForExtension(GetExtension(), 71 tab_struct.get()); 72 return tab_struct.Pass(); 73 } 74 75 scoped_ptr<windows::Window> 76 SessionRestoreGetRecentlyClosedFunction::CreateWindowModel( 77 const TabRestoreService::Window& window) { 78 scoped_ptr<windows::Window> window_struct(new windows::Window); 79 DCHECK(!window.tabs.empty()); 80 81 scoped_ptr<std::vector<linked_ptr<tabs::Tab> > > tabs( 82 new std::vector<linked_ptr<tabs::Tab> >); 83 for (size_t i = 0; i < window.tabs.size(); ++i) { 84 tabs->push_back(make_linked_ptr(CreateTabModel(window.tabs[i], 85 window.selected_tab_index).release())); 86 } 87 window_struct->tabs.reset(tabs.release()); 88 window_struct->incognito = false; 89 window_struct->always_on_top = false; 90 window_struct->focused = false; 91 window_struct->type = windows::Window::TYPE_NORMAL; 92 window_struct->state = windows::Window::STATE_NORMAL; 93 return window_struct.Pass(); 94 } 95 96 scoped_ptr<session_restore::ClosedEntry> 97 SessionRestoreGetRecentlyClosedFunction::CreateEntryModel( 98 const TabRestoreService::Entry* entry) { 99 scoped_ptr<session_restore::ClosedEntry> entry_struct( 100 new session_restore::ClosedEntry); 101 switch (entry->type) { 102 case TabRestoreService::TAB: 103 entry_struct->tab.reset(CreateTabModel( 104 *static_cast<const TabRestoreService::Tab*>(entry), -1).release()); 105 break; 106 case TabRestoreService::WINDOW: 107 entry_struct->window.reset(CreateWindowModel( 108 *static_cast<const TabRestoreService::Window*>(entry)).release()); 109 break; 110 default: 111 NOTREACHED(); 112 } 113 entry_struct->timestamp = entry->timestamp.ToTimeT(); 114 entry_struct->id = entry->id; 115 return entry_struct.Pass(); 116 } 117 118 bool SessionRestoreGetRecentlyClosedFunction::RunImpl() { 119 scoped_ptr<GetRecentlyClosed::Params> params( 120 GetRecentlyClosed::Params::Create(*args_)); 121 EXTENSION_FUNCTION_VALIDATE(params.get()); 122 unsigned int max_results = kMaxRecentlyClosedSessionResults; 123 if (params->options && params->options->max_results) 124 max_results = *params->options->max_results; 125 EXTENSION_FUNCTION_VALIDATE(max_results >= 0 && 126 max_results <= kMaxRecentlyClosedSessionResults); 127 128 std::vector<linked_ptr<session_restore::ClosedEntry> > result; 129 TabRestoreService* tab_restore_service = 130 TabRestoreServiceFactory::GetForProfile(profile()); 131 DCHECK(tab_restore_service); 132 133 // List of entries. They are ordered from most to least recent. 134 // We prune the list to contain max 25 entries at any time and removes 135 // uninteresting entries. 136 TabRestoreService::Entries entries = tab_restore_service->entries(); 137 for (TabRestoreService::Entries::const_iterator it = entries.begin(); 138 it != entries.end() && result.size() < max_results; ++it) { 139 TabRestoreService::Entry* entry = *it; 140 if (!params->options || params->options->entry_type == 141 GetRecentlyClosed::Params::Options::ENTRY_TYPE_NONE) { 142 // Include both tabs and windows if type is not defined. 143 result.push_back(make_linked_ptr(CreateEntryModel(entry).release())); 144 } else if ( 145 (params->options->entry_type == 146 GetRecentlyClosed::Params::Options::ENTRY_TYPE_TAB && 147 entry->type == TabRestoreService::TAB) || 148 (params->options->entry_type == 149 GetRecentlyClosed::Params::Options::ENTRY_TYPE_WINDOW && 150 entry->type == TabRestoreService::WINDOW)) { 151 result.push_back(make_linked_ptr(CreateEntryModel(entry).release())); 152 } 153 } 154 155 results_ = GetRecentlyClosed::Results::Create(result); 156 return true; 157 } 158 159 bool SessionRestoreRestoreFunction::RunImpl() { 160 scoped_ptr<Restore::Params> params(Restore::Params::Create(*args_)); 161 EXTENSION_FUNCTION_VALIDATE(params.get()); 162 163 Browser* browser = 164 chrome::FindBrowserWithProfile(profile(), 165 chrome::HOST_DESKTOP_TYPE_NATIVE); 166 if (!browser) { 167 error_ = kNoBrowserToRestoreSession; 168 return false; 169 } 170 171 TabRestoreService* tab_restore_service = 172 TabRestoreServiceFactory::GetForProfile(profile()); 173 TabRestoreServiceDelegate* delegate = 174 TabRestoreServiceDelegate::FindDelegateForWebContents( 175 browser->tab_strip_model()->GetActiveWebContents()); 176 DCHECK(delegate); 177 chrome::HostDesktopType host_desktop_type = browser->host_desktop_type(); 178 TabRestoreService::Entries entries = tab_restore_service->entries(); 179 180 if (entries.empty()) { 181 error_ = kRecentlyClosedListEmpty; 182 return false; 183 } 184 185 if (!params->id) { 186 tab_restore_service->RestoreMostRecentEntry(delegate, host_desktop_type); 187 return true; 188 } 189 190 // Check if the recently closed list contains an entry with the provided id. 191 bool is_valid_id = false; 192 for (TabRestoreService::Entries::iterator it = entries.begin(); 193 it != entries.end(); ++it) { 194 if ((*it)->id == *params->id) { 195 is_valid_id = true; 196 break; 197 } 198 199 // For Window entries, see if the ID matches a tab. If so, report true for 200 // the window as the Entry. 201 if ((*it)->type == TabRestoreService::WINDOW) { 202 std::vector<TabRestoreService::Tab>& tabs = 203 static_cast<TabRestoreService::Window*>(*it)->tabs; 204 for (std::vector<TabRestoreService::Tab>::iterator tab_it = tabs.begin(); 205 tab_it != tabs.end(); ++tab_it) { 206 if ((*tab_it).id == *params->id) { 207 is_valid_id = true; 208 break; 209 } 210 } 211 } 212 } 213 214 if (!is_valid_id) { 215 error_ = kInvalidSessionId; 216 return false; 217 } 218 219 tab_restore_service->RestoreEntryById(delegate, *params->id, 220 host_desktop_type, UNKNOWN); 221 return true; 222 } 223 224 SessionRestoreAPI::SessionRestoreAPI(Profile* profile) { 225 } 226 227 SessionRestoreAPI::~SessionRestoreAPI() { 228 } 229 230 static base::LazyInstance<ProfileKeyedAPIFactory<SessionRestoreAPI> > 231 g_factory = LAZY_INSTANCE_INITIALIZER; 232 233 // static 234 ProfileKeyedAPIFactory<SessionRestoreAPI>* 235 SessionRestoreAPI::GetFactoryInstance() { 236 return &g_factory.Get(); 237 } 238 239 } // namespace extensions 240