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"
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(
77 const sessions::SerializedNavigationEntry
& current_navigation
,
78 const std::string
& session_id
,
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()));
93 tab_struct
->title
.reset(new std::string(title
));
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
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(
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
;
135 session_struct
->tab
= tab
.Pass();
137 session_struct
->window
= window
.Pass();
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
,
154 int selected_index
) {
155 return CreateTabModelHelper(GetProfile(),
156 tab
.navigations
[tab
.current_navigation_index
],
157 base::IntToString(session_id
),
164 scoped_ptr
<windows::Window
>
165 SessionsGetRecentlyClosedFunction::CreateWindowModel(
166 const sessions::TabRestoreService::Window
& window
,
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
),
194 case sessions::TabRestoreService::WINDOW
:
195 window
= CreateWindowModel(
196 *static_cast<const sessions::TabRestoreService::Window
*>(entry
),
202 return CreateSessionModelHelper(entry
->timestamp
.ToTimeT(),
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
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
> >());
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
=
237 it
!= entries
.end() && static_cast<int>(result
.size()) < max_results
;
239 sessions::TabRestoreService::Entry
* entry
= *it
;
240 result
.push_back(make_linked_ptr(CreateSessionModel(entry
).release()));
243 results_
= GetRecentlyClosed::Results::Create(result
);
247 scoped_ptr
<tabs::Tab
> SessionsGetDevicesFunction::CreateTabModel(
248 const std::string
& session_tag
,
249 const sessions::SessionTab
& tab
,
251 int selected_index
) {
252 std::string session_id
= SessionId(session_tag
, tab
.tab_id
.id()).ToString();
253 return CreateTabModelHelper(
255 tab
.navigations
[tab
.normalized_navigation_index()],
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())
274 const sessions::SerializedNavigationEntry
& current_navigation
=
275 tab
->navigations
.at(tab
->normalized_navigation_index());
276 if (search::IsNTPURL(current_navigation
.virtual_url(), GetProfile())) {
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
;
301 case sessions::SessionWindow::TYPE_POPUP
:
302 type
= windows::WINDOW_TYPE_POPUP
;
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
;
312 case ui::SHOW_STATE_MINIMIZED
:
313 state
= windows::WINDOW_STATE_MINIMIZED
;
315 case ui::SHOW_STATE_MAXIMIZED
:
316 state
= windows::WINDOW_STATE_MAXIMIZED
;
318 case ui::SHOW_STATE_FULLSCREEN
:
319 state
= windows::WINDOW_STATE_FULLSCREEN
;
321 case ui::SHOW_STATE_DEFAULT
:
322 case ui::SHOW_STATE_INACTIVE
:
323 case ui::SHOW_STATE_END
:
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
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
;
369 scoped_ptr
<api::sessions::Session
> session_model(CreateSessionModel(
370 *it
->second
, session
->session_tag
));
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
))) {
383 results_
= GetDevices::Results::Create(
384 std::vector
<linked_ptr
<api::sessions::Device
> >());
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
> >());
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
);
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(),
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.
437 scoped_ptr
<base::DictionaryValue
> window_value(
438 controller
->CreateWindowValueWithTabs(extension()));
439 scoped_ptr
<windows::Window
> window(windows::Window::FromValue(
441 results_
= Restore::Results::Create(*CreateSessionModelHelper(
442 base::Time::Now().ToTimeT(),
443 scoped_ptr
<tabs::Tab
>(),
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
);
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]);
470 return SetResultRestoredWindow(
471 ExtensionTabUtil::GetWindowIdOfTab(first_tab
->web_contents()));
474 SetResultRestoredTab(first_tab
->web_contents());
478 bool SessionsRestoreFunction::RestoreLocalSession(const SessionId
& session_id
,
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());
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
);
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());
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.
519 return SetResultRestoredWindow(
520 ExtensionTabUtil::GetWindowIdOfTab(first_tab
->web_contents()));
523 SetResultRestoredTab(first_tab
->web_contents());
527 bool SessionsRestoreFunction::RestoreForeignSession(const SessionId
& session_id
,
529 ProfileSyncService
* service
=
530 ProfileSyncServiceFactory::GetInstance()->GetForProfile(GetProfile());
531 if (!(service
&& service
->GetPreferredDataTypes().Has(syncer::SESSIONS
))) {
532 SetError(kSessionSyncError
);
535 sync_driver::OpenTabsUIDelegate
* open_tabs
= service
->GetOpenTabsUIDelegate();
537 SetError(kSessionSyncError
);
541 const sessions::SessionTab
* tab
= NULL
;
542 if (open_tabs
->GetForeignTab(session_id
.session_tag(),
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
,
551 SetResultRestoredTab(tab_contents
);
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());
562 std::vector
<const sessions::SessionWindow
*>::const_iterator window
=
564 while (window
!= windows
.end()
565 && (*window
)->window_id
.id() != session_id
.id()) {
568 if (window
== windows
.end()) {
569 SetInvalidIdError(session_id
.ToString());
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
);
589 SetError(kNoBrowserToRestoreSession
);
593 if (GetProfile() != GetProfile()->GetOriginalProfile()) {
594 SetError(kRestoreInIncognitoError
);
598 if (!params
->session_id
)
599 return RestoreMostRecentlyClosed(browser
);
601 scoped_ptr
<SessionId
> session_id(SessionId::Parse(*params
->session_id
));
603 SetInvalidIdError(*params
->session_id
);
607 return session_id
->IsForeign() ?
608 RestoreForeignSession(*session_id
, browser
)
609 : RestoreLocalSession(*session_id
, browser
);
612 SessionsEventRouter::SessionsEventRouter(Profile
* profile
)
614 tab_restore_service_(TabRestoreServiceFactory::GetForProfile(profile
)) {
615 // TabRestoreServiceFactory::GetForProfile() can return NULL (i.e., when in
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