• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/extensions/api/sessions/sessions_api.h"
6 
7 #include <vector>
8 
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_function_dispatcher.h"
19 #include "chrome/browser/extensions/extension_function_registry.h"
20 #include "chrome/browser/extensions/extension_tab_util.h"
21 #include "chrome/browser/extensions/window_controller.h"
22 #include "chrome/browser/extensions/window_controller_list.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/search/search.h"
25 #include "chrome/browser/sessions/session_restore.h"
26 #include "chrome/browser/sessions/tab_restore_service_delegate.h"
27 #include "chrome/browser/sessions/tab_restore_service_factory.h"
28 #include "chrome/browser/sync/glue/synced_session.h"
29 #include "chrome/browser/sync/open_tabs_ui_delegate.h"
30 #include "chrome/browser/sync/profile_sync_service.h"
31 #include "chrome/browser/sync/profile_sync_service_factory.h"
32 #include "chrome/browser/ui/browser.h"
33 #include "chrome/browser/ui/browser_finder.h"
34 #include "chrome/browser/ui/host_desktop.h"
35 #include "chrome/browser/ui/tabs/tab_strip_model.h"
36 #include "chrome/common/pref_names.h"
37 #include "content/public/browser/web_contents.h"
38 #include "extensions/common/error_utils.h"
39 #include "net/base/net_util.h"
40 #include "ui/base/layout.h"
41 
42 namespace extensions {
43 
44 namespace GetRecentlyClosed = api::sessions::GetRecentlyClosed;
45 namespace GetDevices = api::sessions::GetDevices;
46 namespace Restore = api::sessions::Restore;
47 namespace tabs = api::tabs;
48 namespace windows = api::windows;
49 
50 const char kNoRecentlyClosedSessionsError[] =
51     "There are no recently closed sessions.";
52 const char kInvalidSessionIdError[] = "Invalid session id: \"*\".";
53 const char kNoBrowserToRestoreSession[] =
54     "There are no browser windows to restore the session.";
55 const char kSessionSyncError[] = "Synced sessions are not available.";
56 
57 // Comparator function for use with std::sort that will sort sessions by
58 // descending modified_time (i.e., most recent first).
SortSessionsByRecency(const browser_sync::SyncedSession * s1,const browser_sync::SyncedSession * s2)59 bool SortSessionsByRecency(const browser_sync::SyncedSession* s1,
60                            const browser_sync::SyncedSession* s2) {
61   return s1->modified_time > s2->modified_time;
62 }
63 
64 // Comparator function for use with std::sort that will sort tabs in a window
65 // by descending timestamp (i.e., most recent first).
SortTabsByRecency(const SessionTab * t1,const SessionTab * t2)66 bool SortTabsByRecency(const SessionTab* t1, const SessionTab* t2) {
67   return t1->timestamp > t2->timestamp;
68 }
69 
CreateTabModelHelper(Profile * profile,const sessions::SerializedNavigationEntry & current_navigation,const std::string & session_id,int index,bool pinned,int selected_index,const Extension * extension)70 scoped_ptr<tabs::Tab> CreateTabModelHelper(
71     Profile* profile,
72     const sessions::SerializedNavigationEntry& current_navigation,
73     const std::string& session_id,
74     int index,
75     bool pinned,
76     int selected_index,
77     const Extension* extension) {
78   scoped_ptr<tabs::Tab> tab_struct(new tabs::Tab);
79 
80   GURL gurl = current_navigation.virtual_url();
81   std::string title = UTF16ToUTF8(current_navigation.title());
82 
83   tab_struct->session_id.reset(new std::string(session_id));
84   tab_struct->url.reset(new std::string(gurl.spec()));
85   if (!title.empty()) {
86     tab_struct->title.reset(new std::string(title));
87   } else {
88     const std::string languages =
89         profile->GetPrefs()->GetString(prefs::kAcceptLanguages);
90     tab_struct->title.reset(new std::string(UTF16ToUTF8(
91         net::FormatUrl(gurl, languages))));
92   }
93   tab_struct->index = index;
94   tab_struct->pinned = pinned;
95   tab_struct->selected = index == selected_index;
96   tab_struct->active = false;
97   tab_struct->highlighted = false;
98   tab_struct->incognito = false;
99   ExtensionTabUtil::ScrubTabForExtension(extension, tab_struct.get());
100   return tab_struct.Pass();
101 }
102 
CreateWindowModelHelper(scoped_ptr<std::vector<linked_ptr<tabs::Tab>>> tabs,const std::string & session_id,const windows::Window::Type & type,const windows::Window::State & state)103 scoped_ptr<windows::Window> CreateWindowModelHelper(
104     scoped_ptr<std::vector<linked_ptr<tabs::Tab> > > tabs,
105     const std::string& session_id,
106     const windows::Window::Type& type,
107     const windows::Window::State& state) {
108   scoped_ptr<windows::Window> window_struct(new windows::Window);
109   window_struct->tabs = tabs.Pass();
110   window_struct->session_id.reset(new std::string(session_id));
111   window_struct->incognito = false;
112   window_struct->always_on_top = false;
113   window_struct->focused = false;
114   window_struct->type = type;
115   window_struct->state = state;
116   return window_struct.Pass();
117 }
118 
CreateSessionModelHelper(int last_modified,scoped_ptr<tabs::Tab> tab,scoped_ptr<windows::Window> window)119 scoped_ptr<api::sessions::Session> CreateSessionModelHelper(
120     int last_modified,
121     scoped_ptr<tabs::Tab> tab,
122     scoped_ptr<windows::Window> window) {
123   scoped_ptr<api::sessions::Session> session_struct(new api::sessions::Session);
124   session_struct->last_modified = last_modified;
125   if (tab)
126     session_struct->tab = tab.Pass();
127   else if (window)
128     session_struct->window = window.Pass();
129   else
130     NOTREACHED();
131   return session_struct.Pass();
132 }
133 
is_tab_entry(const TabRestoreService::Entry * entry)134 bool is_tab_entry(const TabRestoreService::Entry* entry) {
135   return entry->type == TabRestoreService::TAB;
136 }
137 
is_window_entry(const TabRestoreService::Entry * entry)138 bool is_window_entry(const TabRestoreService::Entry* entry) {
139   return entry->type == TabRestoreService::WINDOW;
140 }
141 
CreateTabModel(const TabRestoreService::Tab & tab,int session_id,int selected_index)142 scoped_ptr<tabs::Tab> SessionsGetRecentlyClosedFunction::CreateTabModel(
143     const TabRestoreService::Tab& tab, int session_id, int selected_index) {
144   return CreateTabModelHelper(GetProfile(),
145                               tab.navigations[tab.current_navigation_index],
146                               base::IntToString(session_id),
147                               tab.tabstrip_index,
148                               tab.pinned,
149                               selected_index,
150                               GetExtension());
151 }
152 
153 scoped_ptr<windows::Window>
CreateWindowModel(const TabRestoreService::Window & window,int session_id)154     SessionsGetRecentlyClosedFunction::CreateWindowModel(
155         const TabRestoreService::Window& window,
156         int session_id) {
157   DCHECK(!window.tabs.empty());
158 
159   scoped_ptr<std::vector<linked_ptr<tabs::Tab> > > tabs(
160       new std::vector<linked_ptr<tabs::Tab> >);
161   for (size_t i = 0; i < window.tabs.size(); ++i) {
162     tabs->push_back(make_linked_ptr(
163         CreateTabModel(window.tabs[i], window.tabs[i].id,
164                        window.selected_tab_index).release()));
165   }
166 
167   return CreateWindowModelHelper(tabs.Pass(),
168                                  base::IntToString(session_id),
169                                  windows::Window::TYPE_NORMAL,
170                                  windows::Window::STATE_NORMAL);
171 }
172 
173 scoped_ptr<api::sessions::Session>
CreateSessionModel(const TabRestoreService::Entry * entry)174     SessionsGetRecentlyClosedFunction::CreateSessionModel(
175         const TabRestoreService::Entry* entry) {
176   scoped_ptr<tabs::Tab> tab;
177   scoped_ptr<windows::Window> window;
178   switch (entry->type) {
179     case TabRestoreService::TAB:
180       tab = CreateTabModel(
181           *static_cast<const TabRestoreService::Tab*>(entry), entry->id, -1);
182       break;
183     case TabRestoreService::WINDOW:
184       window = CreateWindowModel(
185         *static_cast<const TabRestoreService::Window*>(entry), entry->id);
186       break;
187     default:
188       NOTREACHED();
189   }
190   return CreateSessionModelHelper(entry->timestamp.ToTimeT(),
191                                   tab.Pass(),
192                                   window.Pass());
193 }
194 
RunImpl()195 bool SessionsGetRecentlyClosedFunction::RunImpl() {
196   scoped_ptr<GetRecentlyClosed::Params> params(
197       GetRecentlyClosed::Params::Create(*args_));
198   EXTENSION_FUNCTION_VALIDATE(params);
199   int max_results = api::sessions::MAX_SESSION_RESULTS;
200   if (params->filter && params->filter->max_results)
201     max_results = *params->filter->max_results;
202   EXTENSION_FUNCTION_VALIDATE(max_results >= 0 &&
203       max_results <= api::sessions::MAX_SESSION_RESULTS);
204 
205   std::vector<linked_ptr<api::sessions::Session> > result;
206   TabRestoreService* tab_restore_service =
207       TabRestoreServiceFactory::GetForProfile(GetProfile());
208   DCHECK(tab_restore_service);
209 
210   // List of entries. They are ordered from most to least recent.
211   // We prune the list to contain max 25 entries at any time and removes
212   // uninteresting entries.
213   TabRestoreService::Entries entries = tab_restore_service->entries();
214   for (TabRestoreService::Entries::const_iterator it = entries.begin();
215        it != entries.end() && static_cast<int>(result.size()) < max_results;
216        ++it) {
217     TabRestoreService::Entry* entry = *it;
218     result.push_back(make_linked_ptr(CreateSessionModel(entry).release()));
219   }
220 
221   results_ = GetRecentlyClosed::Results::Create(result);
222   return true;
223 }
224 
CreateTabModel(const std::string & session_tag,const SessionTab & tab,int tab_index,int selected_index)225 scoped_ptr<tabs::Tab> SessionsGetDevicesFunction::CreateTabModel(
226     const std::string& session_tag,
227     const SessionTab& tab,
228     int tab_index,
229     int selected_index) {
230   std::string session_id = SessionId(session_tag, tab.tab_id.id()).ToString();
231   return CreateTabModelHelper(GetProfile(),
232                               tab.navigations[tab.current_navigation_index],
233                               session_id,
234                               tab_index,
235                               tab.pinned,
236                               selected_index,
237                               GetExtension());
238 }
239 
CreateWindowModel(const SessionWindow & window,const std::string & session_tag)240 scoped_ptr<windows::Window> SessionsGetDevicesFunction::CreateWindowModel(
241         const SessionWindow& window, const std::string& session_tag) {
242   DCHECK(!window.tabs.empty());
243 
244   // Prune tabs that are not syncable or are NewTabPage. Then, sort the tabs
245   // from most recent to least recent.
246   std::vector<const SessionTab*> tabs_in_window;
247   for (size_t i = 0; i < window.tabs.size(); ++i) {
248     const SessionTab* tab = window.tabs[i];
249     if (tab->navigations.empty())
250       continue;
251     const sessions::SerializedNavigationEntry& current_navigation =
252         tab->navigations.at(tab->normalized_navigation_index());
253     if (chrome::IsNTPURL(current_navigation.virtual_url(), GetProfile())) {
254       continue;
255     }
256     tabs_in_window.push_back(tab);
257   }
258   if (tabs_in_window.empty())
259     return scoped_ptr<windows::Window>();
260   std::sort(tabs_in_window.begin(), tabs_in_window.end(), SortTabsByRecency);
261 
262   scoped_ptr<std::vector<linked_ptr<tabs::Tab> > > tabs(
263       new std::vector<linked_ptr<tabs::Tab> >);
264   for (size_t i = 0; i < window.tabs.size(); ++i) {
265     tabs->push_back(make_linked_ptr(
266         CreateTabModel(session_tag, *window.tabs[i], i,
267                        window.selected_tab_index).release()));
268   }
269 
270   std::string session_id =
271       SessionId(session_tag, window.window_id.id()).ToString();
272 
273   windows::Window::Type type = windows::Window::TYPE_NONE;
274   switch (window.type) {
275     case Browser::TYPE_TABBED:
276       type = windows::Window::TYPE_NORMAL;
277       break;
278     case Browser::TYPE_POPUP:
279       type = windows::Window::TYPE_POPUP;
280       break;
281   }
282 
283   windows::Window::State state = windows::Window::STATE_NONE;
284   switch (window.show_state) {
285     case ui::SHOW_STATE_NORMAL:
286       state = windows::Window::STATE_NORMAL;
287       break;
288     case ui::SHOW_STATE_MINIMIZED:
289       state = windows::Window::STATE_MINIMIZED;
290       break;
291     case ui::SHOW_STATE_MAXIMIZED:
292       state = windows::Window::STATE_MAXIMIZED;
293       break;
294     case ui::SHOW_STATE_FULLSCREEN:
295       state = windows::Window::STATE_FULLSCREEN;
296       break;
297     case ui::SHOW_STATE_DEFAULT:
298     case ui::SHOW_STATE_INACTIVE:
299     case ui::SHOW_STATE_DETACHED:
300     case ui::SHOW_STATE_END:
301       break;
302   }
303 
304   scoped_ptr<windows::Window> window_struct(
305       CreateWindowModelHelper(tabs.Pass(), session_id, type, state));
306   // TODO(dwankri): Dig deeper to resolve bounds not being optional, so closed
307   // windows in GetRecentlyClosed can have set values in Window helper.
308   window_struct->left.reset(new int(window.bounds.x()));
309   window_struct->top.reset(new int(window.bounds.y()));
310   window_struct->width.reset(new int(window.bounds.width()));
311   window_struct->height.reset(new int(window.bounds.height()));
312 
313   return window_struct.Pass();
314 }
315 
316 scoped_ptr<api::sessions::Session>
CreateSessionModel(const SessionWindow & window,const std::string & session_tag)317 SessionsGetDevicesFunction::CreateSessionModel(
318     const SessionWindow& window, const std::string& session_tag) {
319   scoped_ptr<windows::Window> window_model(
320       CreateWindowModel(window, session_tag));
321   // There is a chance that after pruning uninteresting tabs the window will be
322   // empty.
323   return !window_model ? scoped_ptr<api::sessions::Session>()
324       : CreateSessionModelHelper(window.timestamp.ToTimeT(),
325                                  scoped_ptr<tabs::Tab>(),
326                                  window_model.Pass());
327 }
328 
CreateDeviceModel(const browser_sync::SyncedSession * session)329 scoped_ptr<api::sessions::Device> SessionsGetDevicesFunction::CreateDeviceModel(
330     const browser_sync::SyncedSession* session) {
331   int max_results = api::sessions::MAX_SESSION_RESULTS;
332   // Already validated in RunImpl().
333   scoped_ptr<GetDevices::Params> params(GetDevices::Params::Create(*args_));
334   if (params->filter && params->filter->max_results)
335     max_results = *params->filter->max_results;
336 
337   scoped_ptr<api::sessions::Device> device_struct(new api::sessions::Device);
338   device_struct->info = session->session_name;
339 
340   for (browser_sync::SyncedSession::SyncedWindowMap::const_iterator it =
341        session->windows.begin(); it != session->windows.end() &&
342        static_cast<int>(device_struct->sessions.size()) < max_results; ++it) {
343     scoped_ptr<api::sessions::Session> session_model(CreateSessionModel(
344         *it->second, session->session_tag));
345     if (session_model)
346       device_struct->sessions.push_back(make_linked_ptr(
347           session_model.release()));
348   }
349   return device_struct.Pass();
350 }
351 
RunImpl()352 bool SessionsGetDevicesFunction::RunImpl() {
353   ProfileSyncService* service =
354       ProfileSyncServiceFactory::GetInstance()->GetForProfile(GetProfile());
355   if (!(service && service->GetPreferredDataTypes().Has(syncer::SESSIONS))) {
356     // Sync not enabled.
357     results_ = GetDevices::Results::Create(
358         std::vector<linked_ptr<api::sessions::Device> >());
359     return true;
360   }
361 
362   browser_sync::OpenTabsUIDelegate* open_tabs =
363       service->GetOpenTabsUIDelegate();
364   std::vector<const browser_sync::SyncedSession*> sessions;
365   if (!(open_tabs && open_tabs->GetAllForeignSessions(&sessions))) {
366     results_ = GetDevices::Results::Create(
367         std::vector<linked_ptr<api::sessions::Device> >());
368     return true;
369   }
370 
371   scoped_ptr<GetDevices::Params> params(GetDevices::Params::Create(*args_));
372   EXTENSION_FUNCTION_VALIDATE(params);
373   if (params->filter && params->filter->max_results) {
374     EXTENSION_FUNCTION_VALIDATE(*params->filter->max_results >= 0 &&
375         *params->filter->max_results <= api::sessions::MAX_SESSION_RESULTS);
376   }
377 
378   std::vector<linked_ptr<api::sessions::Device> > result;
379   // Sort sessions from most recent to least recent.
380   std::sort(sessions.begin(), sessions.end(), SortSessionsByRecency);
381   for (size_t i = 0; i < sessions.size(); ++i) {
382     result.push_back(make_linked_ptr(CreateDeviceModel(sessions[i]).release()));
383   }
384 
385   results_ = GetDevices::Results::Create(result);
386   return true;
387 }
388 
SetInvalidIdError(const std::string & invalid_id)389 void SessionsRestoreFunction::SetInvalidIdError(const std::string& invalid_id) {
390   SetError(ErrorUtils::FormatErrorMessage(kInvalidSessionIdError, invalid_id));
391 }
392 
393 
SetResultRestoredTab(const content::WebContents * contents)394 void SessionsRestoreFunction::SetResultRestoredTab(
395     const content::WebContents* contents) {
396   scoped_ptr<DictionaryValue> tab_value(
397       ExtensionTabUtil::CreateTabValue(contents, GetExtension()));
398   scoped_ptr<tabs::Tab> tab(tabs::Tab::FromValue(*tab_value));
399   scoped_ptr<api::sessions::Session> restored_session(CreateSessionModelHelper(
400       base::Time::Now().ToTimeT(),
401       tab.Pass(),
402       scoped_ptr<windows::Window>()));
403   results_ = Restore::Results::Create(*restored_session);
404 }
405 
SetResultRestoredWindow(int window_id)406 bool SessionsRestoreFunction::SetResultRestoredWindow(int window_id) {
407   WindowController* controller = NULL;
408   if (!windows_util::GetWindowFromWindowID(this, window_id, &controller)) {
409     // error_ is set by GetWindowFromWindowId function call.
410     return false;
411   }
412   scoped_ptr<DictionaryValue> window_value(
413       controller->CreateWindowValueWithTabs(GetExtension()));
414   scoped_ptr<windows::Window> window(windows::Window::FromValue(
415       *window_value));
416   results_ = Restore::Results::Create(*CreateSessionModelHelper(
417       base::Time::Now().ToTimeT(),
418       scoped_ptr<tabs::Tab>(),
419       window.Pass()));
420   return true;
421 }
422 
RestoreMostRecentlyClosed(Browser * browser)423 bool SessionsRestoreFunction::RestoreMostRecentlyClosed(Browser* browser) {
424   TabRestoreService* tab_restore_service =
425       TabRestoreServiceFactory::GetForProfile(GetProfile());
426   chrome::HostDesktopType host_desktop_type = browser->host_desktop_type();
427   TabRestoreService::Entries entries = tab_restore_service->entries();
428 
429   if (entries.empty()) {
430     SetError(kNoRecentlyClosedSessionsError);
431     return false;
432   }
433 
434   bool is_window = is_window_entry(entries.front());
435   TabRestoreServiceDelegate* delegate =
436       TabRestoreServiceDelegate::FindDelegateForWebContents(
437           browser->tab_strip_model()->GetActiveWebContents());
438   std::vector<content::WebContents*> contents =
439       tab_restore_service->RestoreMostRecentEntry(delegate, host_desktop_type);
440   DCHECK(contents.size());
441 
442   if (is_window) {
443     return SetResultRestoredWindow(
444         ExtensionTabUtil::GetWindowIdOfTab(contents[0]));
445   }
446 
447   SetResultRestoredTab(contents[0]);
448   return true;
449 }
450 
RestoreLocalSession(const SessionId & session_id,Browser * browser)451 bool SessionsRestoreFunction::RestoreLocalSession(const SessionId& session_id,
452                                                   Browser* browser) {
453   TabRestoreService* tab_restore_service =
454       TabRestoreServiceFactory::GetForProfile(GetProfile());
455   chrome::HostDesktopType host_desktop_type = browser->host_desktop_type();
456   TabRestoreService::Entries entries = tab_restore_service->entries();
457 
458   if (entries.empty()) {
459     SetInvalidIdError(session_id.ToString());
460     return false;
461   }
462 
463   // Check if the recently closed list contains an entry with the provided id.
464   bool is_window = false;
465   for (TabRestoreService::Entries::iterator it = entries.begin();
466        it != entries.end(); ++it) {
467     if ((*it)->id == session_id.id()) {
468       // The only time a full window is being restored is if the entry ID
469       // matches the provided ID and the entry type is Window.
470       is_window = is_window_entry(*it);
471       break;
472     }
473   }
474 
475   TabRestoreServiceDelegate* delegate =
476       TabRestoreServiceDelegate::FindDelegateForWebContents(
477           browser->tab_strip_model()->GetActiveWebContents());
478   std::vector<content::WebContents*> contents =
479       tab_restore_service->RestoreEntryById(delegate,
480                                             session_id.id(),
481                                             host_desktop_type,
482                                             UNKNOWN);
483   // If the ID is invalid, contents will be empty.
484   if (!contents.size()) {
485     SetInvalidIdError(session_id.ToString());
486     return false;
487   }
488 
489   // Retrieve the window through any of the tabs in contents.
490   if (is_window) {
491     return SetResultRestoredWindow(
492         ExtensionTabUtil::GetWindowIdOfTab(contents[0]));
493   }
494 
495   SetResultRestoredTab(contents[0]);
496   return true;
497 }
498 
RestoreForeignSession(const SessionId & session_id,Browser * browser)499 bool SessionsRestoreFunction::RestoreForeignSession(const SessionId& session_id,
500                                                     Browser* browser) {
501   ProfileSyncService* service =
502       ProfileSyncServiceFactory::GetInstance()->GetForProfile(GetProfile());
503   if (!(service && service->GetPreferredDataTypes().Has(syncer::SESSIONS))) {
504     SetError(kSessionSyncError);
505     return false;
506   }
507   browser_sync::OpenTabsUIDelegate* open_tabs =
508       service->GetOpenTabsUIDelegate();
509   if (!open_tabs) {
510     SetError(kSessionSyncError);
511     return false;
512   }
513 
514   const SessionTab* tab = NULL;
515   if (open_tabs->GetForeignTab(session_id.session_tag(),
516                                session_id.id(),
517                                &tab)) {
518     TabStripModel* tab_strip = browser->tab_strip_model();
519     content::WebContents* contents = tab_strip->GetActiveWebContents();
520 
521     content::WebContents* tab_contents =
522         SessionRestore::RestoreForeignSessionTab(contents, *tab,
523                                                  NEW_FOREGROUND_TAB);
524     SetResultRestoredTab(tab_contents);
525     return true;
526   }
527 
528   // Restoring a full window.
529   std::vector<const SessionWindow*> windows;
530   if (!open_tabs->GetForeignSession(session_id.session_tag(), &windows)) {
531     SetInvalidIdError(session_id.ToString());
532     return false;
533   }
534 
535   std::vector<const SessionWindow*>::const_iterator window = windows.begin();
536   while (window != windows.end()
537          && (*window)->window_id.id() != session_id.id()) {
538     ++window;
539   }
540   if (window == windows.end()) {
541     SetInvalidIdError(session_id.ToString());
542     return false;
543   }
544 
545   chrome::HostDesktopType host_desktop_type = browser->host_desktop_type();
546   // Only restore one window at a time.
547   std::vector<Browser*> browsers = SessionRestore::RestoreForeignSessionWindows(
548       GetProfile(), host_desktop_type, window, window + 1);
549   // Will always create one browser because we only restore one window per call.
550   DCHECK_EQ(1u, browsers.size());
551   return SetResultRestoredWindow(ExtensionTabUtil::GetWindowId(browsers[0]));
552 }
553 
RunImpl()554 bool SessionsRestoreFunction::RunImpl() {
555   scoped_ptr<Restore::Params> params(Restore::Params::Create(*args_));
556   EXTENSION_FUNCTION_VALIDATE(params);
557 
558   Browser* browser = chrome::FindBrowserWithProfile(
559       GetProfile(), chrome::HOST_DESKTOP_TYPE_NATIVE);
560   if (!browser) {
561     SetError(kNoBrowserToRestoreSession);
562     return false;
563   }
564 
565   if (!params->session_id)
566     return RestoreMostRecentlyClosed(browser);
567 
568   scoped_ptr<SessionId> session_id(SessionId::Parse(*params->session_id));
569   if (!session_id) {
570     SetInvalidIdError(*params->session_id);
571     return false;
572   }
573 
574   return session_id->IsForeign() ?
575       RestoreForeignSession(*session_id, browser)
576       : RestoreLocalSession(*session_id, browser);
577 }
578 
SessionsAPI(Profile * profile)579 SessionsAPI::SessionsAPI(Profile* profile) {
580 }
581 
~SessionsAPI()582 SessionsAPI::~SessionsAPI() {
583 }
584 
585 static base::LazyInstance<ProfileKeyedAPIFactory<SessionsAPI> >
586     g_factory = LAZY_INSTANCE_INITIALIZER;
587 
588 // static
589 ProfileKeyedAPIFactory<SessionsAPI>*
GetFactoryInstance()590     SessionsAPI::GetFactoryInstance() {
591   return &g_factory.Get();
592 }
593 
594 }  // namespace extensions
595