Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / extensions / api / sessions / sessions_api.cc
blob94930c5f8b9d2100c09ab3cbceccb7dd42109fbc
1 // Copyright 2013 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/extensions/api/sessions/sessions_api.h"
7 #include <vector>
9 #include "base/i18n/rtl.h"
10 #include "base/lazy_instance.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/time/time.h"
16 #include "chrome/browser/extensions/api/sessions/session_id.h"
17 #include "chrome/browser/extensions/api/tabs/windows_util.h"
18 #include "chrome/browser/extensions/extension_tab_util.h"
19 #include "chrome/browser/extensions/window_controller.h"
20 #include "chrome/browser/extensions/window_controller_list.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/search/search.h"
23 #include "chrome/browser/sessions/session_restore.h"
24 #include "chrome/browser/sessions/tab_restore_service_factory.h"
25 #include "chrome/browser/sync/profile_sync_service.h"
26 #include "chrome/browser/sync/profile_sync_service_factory.h"
27 #include "chrome/browser/ui/browser.h"
28 #include "chrome/browser/ui/browser_finder.h"
29 #include "chrome/browser/ui/browser_tab_restore_service_delegate.h"
30 #include "chrome/browser/ui/host_desktop.h"
31 #include "chrome/browser/ui/tabs/tab_strip_model.h"
32 #include "chrome/common/pref_names.h"
33 #include "components/sessions/content/content_live_tab.h"
34 #include "components/sync_driver/glue/synced_session.h"
35 #include "components/sync_driver/open_tabs_ui_delegate.h"
36 #include "components/url_formatter/url_formatter.h"
37 #include "content/public/browser/web_contents.h"
38 #include "extensions/browser/extension_function_dispatcher.h"
39 #include "extensions/browser/extension_function_registry.h"
40 #include "extensions/browser/extension_system.h"
41 #include "extensions/common/error_utils.h"
42 #include "ui/base/layout.h"
44 namespace extensions {
46 namespace GetRecentlyClosed = api::sessions::GetRecentlyClosed;
47 namespace GetDevices = api::sessions::GetDevices;
48 namespace Restore = api::sessions::Restore;
49 namespace tabs = api::tabs;
50 namespace windows = api::windows;
52 const char kNoRecentlyClosedSessionsError[] =
53 "There are no recently closed sessions.";
54 const char kInvalidSessionIdError[] = "Invalid session id: \"*\".";
55 const char kNoBrowserToRestoreSession[] =
56 "There are no browser windows to restore the session.";
57 const char kSessionSyncError[] = "Synced sessions are not available.";
58 const char kRestoreInIncognitoError[] =
59 "Can not restore sessions in incognito mode.";
61 // Comparator function for use with std::sort that will sort sessions by
62 // descending modified_time (i.e., most recent first).
63 bool SortSessionsByRecency(const sync_driver::SyncedSession* s1,
64 const sync_driver::SyncedSession* s2) {
65 return s1->modified_time > s2->modified_time;
68 // Comparator function for use with std::sort that will sort tabs in a window
69 // by descending timestamp (i.e., most recent first).
70 bool SortTabsByRecency(const sessions::SessionTab* t1,
71 const sessions::SessionTab* t2) {
72 return t1->timestamp > t2->timestamp;
75 scoped_ptr<tabs::Tab> CreateTabModelHelper(
76 Profile* profile,
77 const sessions::SerializedNavigationEntry& current_navigation,
78 const std::string& session_id,
79 int index,
80 bool pinned,
81 int selected_index,
82 const Extension* extension) {
83 scoped_ptr<tabs::Tab> tab_struct(new tabs::Tab);
85 const GURL& url = current_navigation.virtual_url();
86 std::string title = base::UTF16ToUTF8(current_navigation.title());
88 tab_struct->session_id.reset(new std::string(session_id));
89 tab_struct->url.reset(new std::string(url.spec()));
90 tab_struct->fav_icon_url.reset(
91 new std::string(current_navigation.favicon_url().spec()));
92 if (!title.empty()) {
93 tab_struct->title.reset(new std::string(title));
94 } else {
95 const std::string languages =
96 profile->GetPrefs()->GetString(prefs::kAcceptLanguages);
97 tab_struct->title.reset(new std::string(
98 base::UTF16ToUTF8(url_formatter::FormatUrl(url, languages))));
100 tab_struct->index = index;
101 tab_struct->pinned = pinned;
102 // Note: |selected_index| from the sync sessions model is what we call
103 // "active" in extensions terminology. "selected" is deprecated because it's
104 // not clear whether it means "active" (user can see) or "highlighted" (user
105 // has highlighted, since you can select tabs without bringing them into the
106 // foreground).
107 tab_struct->active = index == selected_index;
108 ExtensionTabUtil::ScrubTabForExtension(extension, tab_struct.get());
109 return tab_struct.Pass();
112 scoped_ptr<windows::Window> CreateWindowModelHelper(
113 scoped_ptr<std::vector<linked_ptr<tabs::Tab>>> tabs,
114 const std::string& session_id,
115 const windows::WindowType& type,
116 const windows::WindowState& state) {
117 scoped_ptr<windows::Window> window_struct(new windows::Window);
118 window_struct->tabs = tabs.Pass();
119 window_struct->session_id.reset(new std::string(session_id));
120 window_struct->incognito = false;
121 window_struct->always_on_top = false;
122 window_struct->focused = false;
123 window_struct->type = type;
124 window_struct->state = state;
125 return window_struct.Pass();
128 scoped_ptr<api::sessions::Session> CreateSessionModelHelper(
129 int last_modified,
130 scoped_ptr<tabs::Tab> tab,
131 scoped_ptr<windows::Window> window) {
132 scoped_ptr<api::sessions::Session> session_struct(new api::sessions::Session);
133 session_struct->last_modified = last_modified;
134 if (tab)
135 session_struct->tab = tab.Pass();
136 else if (window)
137 session_struct->window = window.Pass();
138 else
139 NOTREACHED();
140 return session_struct.Pass();
143 bool is_tab_entry(const sessions::TabRestoreService::Entry* entry) {
144 return entry->type == sessions::TabRestoreService::TAB;
147 bool is_window_entry(const sessions::TabRestoreService::Entry* entry) {
148 return entry->type == sessions::TabRestoreService::WINDOW;
151 scoped_ptr<tabs::Tab> SessionsGetRecentlyClosedFunction::CreateTabModel(
152 const sessions::TabRestoreService::Tab& tab,
153 int session_id,
154 int selected_index) {
155 return CreateTabModelHelper(GetProfile(),
156 tab.navigations[tab.current_navigation_index],
157 base::IntToString(session_id),
158 tab.tabstrip_index,
159 tab.pinned,
160 selected_index,
161 extension());
164 scoped_ptr<windows::Window>
165 SessionsGetRecentlyClosedFunction::CreateWindowModel(
166 const sessions::TabRestoreService::Window& window,
167 int session_id) {
168 DCHECK(!window.tabs.empty());
170 scoped_ptr<std::vector<linked_ptr<tabs::Tab> > > tabs(
171 new std::vector<linked_ptr<tabs::Tab> >);
172 for (size_t i = 0; i < window.tabs.size(); ++i) {
173 tabs->push_back(make_linked_ptr(
174 CreateTabModel(window.tabs[i], window.tabs[i].id,
175 window.selected_tab_index).release()));
178 return CreateWindowModelHelper(tabs.Pass(), base::IntToString(session_id),
179 windows::WINDOW_TYPE_NORMAL,
180 windows::WINDOW_STATE_NORMAL);
183 scoped_ptr<api::sessions::Session>
184 SessionsGetRecentlyClosedFunction::CreateSessionModel(
185 const sessions::TabRestoreService::Entry* entry) {
186 scoped_ptr<tabs::Tab> tab;
187 scoped_ptr<windows::Window> window;
188 switch (entry->type) {
189 case sessions::TabRestoreService::TAB:
190 tab = CreateTabModel(
191 *static_cast<const sessions::TabRestoreService::Tab*>(entry),
192 entry->id, -1);
193 break;
194 case sessions::TabRestoreService::WINDOW:
195 window = CreateWindowModel(
196 *static_cast<const sessions::TabRestoreService::Window*>(entry),
197 entry->id);
198 break;
199 default:
200 NOTREACHED();
202 return CreateSessionModelHelper(entry->timestamp.ToTimeT(),
203 tab.Pass(),
204 window.Pass());
207 bool SessionsGetRecentlyClosedFunction::RunSync() {
208 scoped_ptr<GetRecentlyClosed::Params> params(
209 GetRecentlyClosed::Params::Create(*args_));
210 EXTENSION_FUNCTION_VALIDATE(params);
211 int max_results = api::sessions::MAX_SESSION_RESULTS;
212 if (params->filter && params->filter->max_results)
213 max_results = *params->filter->max_results;
214 EXTENSION_FUNCTION_VALIDATE(max_results >= 0 &&
215 max_results <= api::sessions::MAX_SESSION_RESULTS);
217 std::vector<linked_ptr<api::sessions::Session> > result;
218 sessions::TabRestoreService* tab_restore_service =
219 TabRestoreServiceFactory::GetForProfile(GetProfile());
221 // TabRestoreServiceFactory::GetForProfile() can return NULL (i.e., when in
222 // incognito mode)
223 if (!tab_restore_service) {
224 DCHECK_NE(GetProfile(), GetProfile()->GetOriginalProfile())
225 << "sessions::TabRestoreService expected for normal profiles";
226 results_ = GetRecentlyClosed::Results::Create(
227 std::vector<linked_ptr<api::sessions::Session> >());
228 return true;
231 // List of entries. They are ordered from most to least recent.
232 // We prune the list to contain max 25 entries at any time and removes
233 // uninteresting entries.
234 sessions::TabRestoreService::Entries entries = tab_restore_service->entries();
235 for (sessions::TabRestoreService::Entries::const_iterator it =
236 entries.begin();
237 it != entries.end() && static_cast<int>(result.size()) < max_results;
238 ++it) {
239 sessions::TabRestoreService::Entry* entry = *it;
240 result.push_back(make_linked_ptr(CreateSessionModel(entry).release()));
243 results_ = GetRecentlyClosed::Results::Create(result);
244 return true;
247 scoped_ptr<tabs::Tab> SessionsGetDevicesFunction::CreateTabModel(
248 const std::string& session_tag,
249 const sessions::SessionTab& tab,
250 int tab_index,
251 int selected_index) {
252 std::string session_id = SessionId(session_tag, tab.tab_id.id()).ToString();
253 return CreateTabModelHelper(
254 GetProfile(),
255 tab.navigations[tab.normalized_navigation_index()],
256 session_id,
257 tab_index,
258 tab.pinned,
259 selected_index,
260 extension());
263 scoped_ptr<windows::Window> SessionsGetDevicesFunction::CreateWindowModel(
264 const sessions::SessionWindow& window, const std::string& session_tag) {
265 DCHECK(!window.tabs.empty());
267 // Prune tabs that are not syncable or are NewTabPage. Then, sort the tabs
268 // from most recent to least recent.
269 std::vector<const sessions::SessionTab*> tabs_in_window;
270 for (size_t i = 0; i < window.tabs.size(); ++i) {
271 const sessions::SessionTab* tab = window.tabs[i];
272 if (tab->navigations.empty())
273 continue;
274 const sessions::SerializedNavigationEntry& current_navigation =
275 tab->navigations.at(tab->normalized_navigation_index());
276 if (search::IsNTPURL(current_navigation.virtual_url(), GetProfile())) {
277 continue;
279 tabs_in_window.push_back(tab);
281 if (tabs_in_window.empty())
282 return scoped_ptr<windows::Window>();
283 std::sort(tabs_in_window.begin(), tabs_in_window.end(), SortTabsByRecency);
285 scoped_ptr<std::vector<linked_ptr<tabs::Tab> > > tabs(
286 new std::vector<linked_ptr<tabs::Tab> >);
287 for (size_t i = 0; i < tabs_in_window.size(); ++i) {
288 tabs->push_back(make_linked_ptr(
289 CreateTabModel(session_tag, *tabs_in_window[i], i,
290 window.selected_tab_index).release()));
293 std::string session_id =
294 SessionId(session_tag, window.window_id.id()).ToString();
296 windows::WindowType type = windows::WINDOW_TYPE_NONE;
297 switch (window.type) {
298 case sessions::SessionWindow::TYPE_TABBED:
299 type = windows::WINDOW_TYPE_NORMAL;
300 break;
301 case sessions::SessionWindow::TYPE_POPUP:
302 type = windows::WINDOW_TYPE_POPUP;
303 break;
306 windows::WindowState state = windows::WINDOW_STATE_NONE;
307 switch (window.show_state) {
308 case ui::SHOW_STATE_NORMAL:
309 case ui::SHOW_STATE_DOCKED:
310 state = windows::WINDOW_STATE_NORMAL;
311 break;
312 case ui::SHOW_STATE_MINIMIZED:
313 state = windows::WINDOW_STATE_MINIMIZED;
314 break;
315 case ui::SHOW_STATE_MAXIMIZED:
316 state = windows::WINDOW_STATE_MAXIMIZED;
317 break;
318 case ui::SHOW_STATE_FULLSCREEN:
319 state = windows::WINDOW_STATE_FULLSCREEN;
320 break;
321 case ui::SHOW_STATE_DEFAULT:
322 case ui::SHOW_STATE_INACTIVE:
323 case ui::SHOW_STATE_END:
324 break;
327 scoped_ptr<windows::Window> window_struct(
328 CreateWindowModelHelper(tabs.Pass(), session_id, type, state));
329 // TODO(dwankri): Dig deeper to resolve bounds not being optional, so closed
330 // windows in GetRecentlyClosed can have set values in Window helper.
331 window_struct->left.reset(new int(window.bounds.x()));
332 window_struct->top.reset(new int(window.bounds.y()));
333 window_struct->width.reset(new int(window.bounds.width()));
334 window_struct->height.reset(new int(window.bounds.height()));
336 return window_struct.Pass();
339 scoped_ptr<api::sessions::Session>
340 SessionsGetDevicesFunction::CreateSessionModel(
341 const sessions::SessionWindow& window, const std::string& session_tag) {
342 scoped_ptr<windows::Window> window_model(
343 CreateWindowModel(window, session_tag));
344 // There is a chance that after pruning uninteresting tabs the window will be
345 // empty.
346 return !window_model ? scoped_ptr<api::sessions::Session>()
347 : CreateSessionModelHelper(window.timestamp.ToTimeT(),
348 scoped_ptr<tabs::Tab>(),
349 window_model.Pass());
352 scoped_ptr<api::sessions::Device> SessionsGetDevicesFunction::CreateDeviceModel(
353 const sync_driver::SyncedSession* session) {
354 int max_results = api::sessions::MAX_SESSION_RESULTS;
355 // Already validated in RunAsync().
356 scoped_ptr<GetDevices::Params> params(GetDevices::Params::Create(*args_));
357 if (params->filter && params->filter->max_results)
358 max_results = *params->filter->max_results;
360 scoped_ptr<api::sessions::Device> device_struct(new api::sessions::Device);
361 device_struct->info = session->session_name;
362 device_struct->device_name = session->session_name;
364 for (sync_driver::SyncedSession::SyncedWindowMap::const_iterator it =
365 session->windows.begin();
366 it != session->windows.end() &&
367 static_cast<int>(device_struct->sessions.size()) < max_results;
368 ++it) {
369 scoped_ptr<api::sessions::Session> session_model(CreateSessionModel(
370 *it->second, session->session_tag));
371 if (session_model)
372 device_struct->sessions.push_back(make_linked_ptr(
373 session_model.release()));
375 return device_struct.Pass();
378 bool SessionsGetDevicesFunction::RunSync() {
379 ProfileSyncService* service =
380 ProfileSyncServiceFactory::GetInstance()->GetForProfile(GetProfile());
381 if (!(service && service->GetPreferredDataTypes().Has(syncer::SESSIONS))) {
382 // Sync not enabled.
383 results_ = GetDevices::Results::Create(
384 std::vector<linked_ptr<api::sessions::Device> >());
385 return true;
388 sync_driver::OpenTabsUIDelegate* open_tabs = service->GetOpenTabsUIDelegate();
389 std::vector<const sync_driver::SyncedSession*> sessions;
390 if (!(open_tabs && open_tabs->GetAllForeignSessions(&sessions))) {
391 results_ = GetDevices::Results::Create(
392 std::vector<linked_ptr<api::sessions::Device> >());
393 return true;
396 scoped_ptr<GetDevices::Params> params(GetDevices::Params::Create(*args_));
397 EXTENSION_FUNCTION_VALIDATE(params);
398 if (params->filter && params->filter->max_results) {
399 EXTENSION_FUNCTION_VALIDATE(*params->filter->max_results >= 0 &&
400 *params->filter->max_results <= api::sessions::MAX_SESSION_RESULTS);
403 std::vector<linked_ptr<api::sessions::Device> > result;
404 // Sort sessions from most recent to least recent.
405 std::sort(sessions.begin(), sessions.end(), SortSessionsByRecency);
406 for (size_t i = 0; i < sessions.size(); ++i) {
407 result.push_back(make_linked_ptr(CreateDeviceModel(sessions[i]).release()));
410 results_ = GetDevices::Results::Create(result);
411 return true;
414 void SessionsRestoreFunction::SetInvalidIdError(const std::string& invalid_id) {
415 SetError(ErrorUtils::FormatErrorMessage(kInvalidSessionIdError, invalid_id));
419 void SessionsRestoreFunction::SetResultRestoredTab(
420 content::WebContents* contents) {
421 scoped_ptr<base::DictionaryValue> tab_value(
422 ExtensionTabUtil::CreateTabValue(contents, extension()));
423 scoped_ptr<tabs::Tab> tab(tabs::Tab::FromValue(*tab_value));
424 scoped_ptr<api::sessions::Session> restored_session(CreateSessionModelHelper(
425 base::Time::Now().ToTimeT(),
426 tab.Pass(),
427 scoped_ptr<windows::Window>()));
428 results_ = Restore::Results::Create(*restored_session);
431 bool SessionsRestoreFunction::SetResultRestoredWindow(int window_id) {
432 WindowController* controller = NULL;
433 if (!windows_util::GetWindowFromWindowID(this, window_id, 0, &controller)) {
434 // error_ is set by GetWindowFromWindowId function call.
435 return false;
437 scoped_ptr<base::DictionaryValue> window_value(
438 controller->CreateWindowValueWithTabs(extension()));
439 scoped_ptr<windows::Window> window(windows::Window::FromValue(
440 *window_value));
441 results_ = Restore::Results::Create(*CreateSessionModelHelper(
442 base::Time::Now().ToTimeT(),
443 scoped_ptr<tabs::Tab>(),
444 window.Pass()));
445 return true;
448 bool SessionsRestoreFunction::RestoreMostRecentlyClosed(Browser* browser) {
449 sessions::TabRestoreService* tab_restore_service =
450 TabRestoreServiceFactory::GetForProfile(GetProfile());
451 chrome::HostDesktopType host_desktop_type = browser->host_desktop_type();
452 sessions::TabRestoreService::Entries entries = tab_restore_service->entries();
454 if (entries.empty()) {
455 SetError(kNoRecentlyClosedSessionsError);
456 return false;
459 bool is_window = is_window_entry(entries.front());
460 sessions::TabRestoreServiceDelegate* delegate =
461 BrowserTabRestoreServiceDelegate::FindDelegateForWebContents(
462 browser->tab_strip_model()->GetActiveWebContents());
463 std::vector<sessions::LiveTab*> restored_tabs =
464 tab_restore_service->RestoreMostRecentEntry(delegate, host_desktop_type);
465 DCHECK(restored_tabs.size());
467 sessions::ContentLiveTab* first_tab =
468 static_cast<sessions::ContentLiveTab*>(restored_tabs[0]);
469 if (is_window) {
470 return SetResultRestoredWindow(
471 ExtensionTabUtil::GetWindowIdOfTab(first_tab->web_contents()));
474 SetResultRestoredTab(first_tab->web_contents());
475 return true;
478 bool SessionsRestoreFunction::RestoreLocalSession(const SessionId& session_id,
479 Browser* browser) {
480 sessions::TabRestoreService* tab_restore_service =
481 TabRestoreServiceFactory::GetForProfile(GetProfile());
482 chrome::HostDesktopType host_desktop_type = browser->host_desktop_type();
483 sessions::TabRestoreService::Entries entries = tab_restore_service->entries();
485 if (entries.empty()) {
486 SetInvalidIdError(session_id.ToString());
487 return false;
490 // Check if the recently closed list contains an entry with the provided id.
491 bool is_window = false;
492 for (sessions::TabRestoreService::Entries::iterator it = entries.begin();
493 it != entries.end(); ++it) {
494 if ((*it)->id == session_id.id()) {
495 // The only time a full window is being restored is if the entry ID
496 // matches the provided ID and the entry type is Window.
497 is_window = is_window_entry(*it);
498 break;
502 sessions::TabRestoreServiceDelegate* delegate =
503 BrowserTabRestoreServiceDelegate::FindDelegateForWebContents(
504 browser->tab_strip_model()->GetActiveWebContents());
505 std::vector<sessions::LiveTab*> restored_tabs =
506 tab_restore_service->RestoreEntryById(delegate, session_id.id(),
507 host_desktop_type, UNKNOWN);
508 // If the ID is invalid, restored_tabs will be empty.
509 if (!restored_tabs.size()) {
510 SetInvalidIdError(session_id.ToString());
511 return false;
514 sessions::ContentLiveTab* first_tab =
515 static_cast<sessions::ContentLiveTab*>(restored_tabs[0]);
517 // Retrieve the window through any of the tabs in restored_tabs.
518 if (is_window) {
519 return SetResultRestoredWindow(
520 ExtensionTabUtil::GetWindowIdOfTab(first_tab->web_contents()));
523 SetResultRestoredTab(first_tab->web_contents());
524 return true;
527 bool SessionsRestoreFunction::RestoreForeignSession(const SessionId& session_id,
528 Browser* browser) {
529 ProfileSyncService* service =
530 ProfileSyncServiceFactory::GetInstance()->GetForProfile(GetProfile());
531 if (!(service && service->GetPreferredDataTypes().Has(syncer::SESSIONS))) {
532 SetError(kSessionSyncError);
533 return false;
535 sync_driver::OpenTabsUIDelegate* open_tabs = service->GetOpenTabsUIDelegate();
536 if (!open_tabs) {
537 SetError(kSessionSyncError);
538 return false;
541 const sessions::SessionTab* tab = NULL;
542 if (open_tabs->GetForeignTab(session_id.session_tag(),
543 session_id.id(),
544 &tab)) {
545 TabStripModel* tab_strip = browser->tab_strip_model();
546 content::WebContents* contents = tab_strip->GetActiveWebContents();
548 content::WebContents* tab_contents =
549 SessionRestore::RestoreForeignSessionTab(contents, *tab,
550 NEW_FOREGROUND_TAB);
551 SetResultRestoredTab(tab_contents);
552 return true;
555 // Restoring a full window.
556 std::vector<const sessions::SessionWindow*> windows;
557 if (!open_tabs->GetForeignSession(session_id.session_tag(), &windows)) {
558 SetInvalidIdError(session_id.ToString());
559 return false;
562 std::vector<const sessions::SessionWindow*>::const_iterator window =
563 windows.begin();
564 while (window != windows.end()
565 && (*window)->window_id.id() != session_id.id()) {
566 ++window;
568 if (window == windows.end()) {
569 SetInvalidIdError(session_id.ToString());
570 return false;
573 chrome::HostDesktopType host_desktop_type = browser->host_desktop_type();
574 // Only restore one window at a time.
575 std::vector<Browser*> browsers = SessionRestore::RestoreForeignSessionWindows(
576 GetProfile(), host_desktop_type, window, window + 1);
577 // Will always create one browser because we only restore one window per call.
578 DCHECK_EQ(1u, browsers.size());
579 return SetResultRestoredWindow(ExtensionTabUtil::GetWindowId(browsers[0]));
582 bool SessionsRestoreFunction::RunSync() {
583 scoped_ptr<Restore::Params> params(Restore::Params::Create(*args_));
584 EXTENSION_FUNCTION_VALIDATE(params);
586 Browser* browser = chrome::FindBrowserWithProfile(
587 GetProfile(), chrome::HOST_DESKTOP_TYPE_NATIVE);
588 if (!browser) {
589 SetError(kNoBrowserToRestoreSession);
590 return false;
593 if (GetProfile() != GetProfile()->GetOriginalProfile()) {
594 SetError(kRestoreInIncognitoError);
595 return false;
598 if (!params->session_id)
599 return RestoreMostRecentlyClosed(browser);
601 scoped_ptr<SessionId> session_id(SessionId::Parse(*params->session_id));
602 if (!session_id) {
603 SetInvalidIdError(*params->session_id);
604 return false;
607 return session_id->IsForeign() ?
608 RestoreForeignSession(*session_id, browser)
609 : RestoreLocalSession(*session_id, browser);
612 SessionsEventRouter::SessionsEventRouter(Profile* profile)
613 : profile_(profile),
614 tab_restore_service_(TabRestoreServiceFactory::GetForProfile(profile)) {
615 // TabRestoreServiceFactory::GetForProfile() can return NULL (i.e., when in
616 // incognito mode)
617 if (tab_restore_service_) {
618 tab_restore_service_->LoadTabsFromLastSession();
619 tab_restore_service_->AddObserver(this);
623 SessionsEventRouter::~SessionsEventRouter() {
624 if (tab_restore_service_)
625 tab_restore_service_->RemoveObserver(this);
628 void SessionsEventRouter::TabRestoreServiceChanged(
629 sessions::TabRestoreService* service) {
630 scoped_ptr<base::ListValue> args(new base::ListValue());
631 EventRouter::Get(profile_)->BroadcastEvent(make_scoped_ptr(
632 new Event(events::SESSIONS_ON_CHANGED,
633 api::sessions::OnChanged::kEventName, args.Pass())));
636 void SessionsEventRouter::TabRestoreServiceDestroyed(
637 sessions::TabRestoreService* service) {
638 tab_restore_service_ = NULL;
641 SessionsAPI::SessionsAPI(content::BrowserContext* context)
642 : browser_context_(context) {
643 EventRouter::Get(browser_context_)->RegisterObserver(this,
644 api::sessions::OnChanged::kEventName);
647 SessionsAPI::~SessionsAPI() {
650 void SessionsAPI::Shutdown() {
651 EventRouter::Get(browser_context_)->UnregisterObserver(this);
654 static base::LazyInstance<BrowserContextKeyedAPIFactory<SessionsAPI> >
655 g_factory = LAZY_INSTANCE_INITIALIZER;
657 BrowserContextKeyedAPIFactory<SessionsAPI>*
658 SessionsAPI::GetFactoryInstance() {
659 return g_factory.Pointer();
662 void SessionsAPI::OnListenerAdded(const EventListenerInfo& details) {
663 sessions_event_router_.reset(
664 new SessionsEventRouter(Profile::FromBrowserContext(browser_context_)));
665 EventRouter::Get(browser_context_)->UnregisterObserver(this);
668 } // namespace extensions