blob: 872c24eba7958f3e23de55769d2b154f815f1bff [file] [log] [blame]
[email protected]d791ad12013-08-23 02:12:591// 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
avia2f4804a2015-12-24 23:11:137#include <stddef.h>
dchengc963c7142016-04-08 03:55:228
Devlin Cronin7050f8e2018-02-07 19:52:049#include <algorithm>
Jinho Bangb5216cec2018-01-17 19:43:1110#include <memory>
dcheng1fc00f12015-12-26 22:18:0311#include <utility>
[email protected]d791ad12013-08-23 02:12:5912#include <vector>
13
14#include "base/i18n/rtl.h"
15#include "base/lazy_instance.h"
[email protected]d791ad12013-08-23 02:12:5916#include "base/strings/string_number_conversions.h"
[email protected]d791ad12013-08-23 02:12:5917#include "base/strings/utf_string_conversions.h"
18#include "base/time/time.h"
19#include "chrome/browser/extensions/api/sessions/session_id.h"
20#include "chrome/browser/extensions/api/tabs/windows_util.h"
[email protected]d791ad12013-08-23 02:12:5921#include "chrome/browser/extensions/extension_tab_util.h"
22#include "chrome/browser/extensions/window_controller.h"
23#include "chrome/browser/extensions/window_controller_list.h"
24#include "chrome/browser/profiles/profile.h"
25#include "chrome/browser/search/search.h"
26#include "chrome/browser/sessions/session_restore.h"
[email protected]d791ad12013-08-23 02:12:5927#include "chrome/browser/sessions/tab_restore_service_factory.h"
[email protected]d791ad12013-08-23 02:12:5928#include "chrome/browser/sync/profile_sync_service_factory.h"
29#include "chrome/browser/ui/browser.h"
30#include "chrome/browser/ui/browser_finder.h"
blundellbde024d2015-09-30 13:47:0731#include "chrome/browser/ui/browser_live_tab_context.h"
[email protected]d791ad12013-08-23 02:12:5932#include "chrome/browser/ui/tabs/tab_strip_model.h"
maxbogue26f40222016-09-16 20:22:1833#include "components/browser_sync/profile_sync_service.h"
blundell80c5b2a02015-09-17 18:22:1234#include "components/sessions/content/content_live_tab.h"
maxbogue8ef25082015-11-16 19:09:5835#include "components/sync_sessions/open_tabs_ui_delegate.h"
36#include "components/sync_sessions/synced_session.h"
rsleevi24f64dc22015-08-07 21:39:2137#include "components/url_formatter/url_formatter.h"
[email protected]d791ad12013-08-23 02:12:5938#include "content/public/browser/web_contents.h"
[email protected]0b9de032014-03-15 05:47:0139#include "extensions/browser/extension_function_dispatcher.h"
[email protected]21c6c432014-03-05 18:47:3140#include "extensions/browser/extension_function_registry.h"
[email protected]38f92582014-03-30 20:48:5541#include "extensions/browser/extension_system.h"
[email protected]d791ad12013-08-23 02:12:5942#include "extensions/common/error_utils.h"
[email protected]d791ad12013-08-23 02:12:5943#include "ui/base/layout.h"
44
45namespace extensions {
46
sdy7710d22c2016-08-09 14:04:3447namespace {
48
[email protected]d791ad12013-08-23 02:12:5949namespace GetRecentlyClosed = api::sessions::GetRecentlyClosed;
50namespace GetDevices = api::sessions::GetDevices;
51namespace Restore = api::sessions::Restore;
52namespace tabs = api::tabs;
53namespace windows = api::windows;
54
55const char kNoRecentlyClosedSessionsError[] =
56 "There are no recently closed sessions.";
57const char kInvalidSessionIdError[] = "Invalid session id: \"*\".";
58const char kNoBrowserToRestoreSession[] =
59 "There are no browser windows to restore the session.";
60const char kSessionSyncError[] = "Synced sessions are not available.";
[email protected]ecf519882014-03-21 15:49:5261const char kRestoreInIncognitoError[] =
62 "Can not restore sessions in incognito mode.";
[email protected]d791ad12013-08-23 02:12:5963
64// Comparator function for use with std::sort that will sort sessions by
65// descending modified_time (i.e., most recent first).
maxboguea79d99b72016-09-15 15:59:1666bool SortSessionsByRecency(const sync_sessions::SyncedSession* s1,
67 const sync_sessions::SyncedSession* s2) {
[email protected]d791ad12013-08-23 02:12:5968 return s1->modified_time > s2->modified_time;
69}
70
71// Comparator function for use with std::sort that will sort tabs in a window
72// by descending timestamp (i.e., most recent first).
skuhneb7409dcf2014-11-14 04:06:5573bool SortTabsByRecency(const sessions::SessionTab* t1,
74 const sessions::SessionTab* t2) {
[email protected]d791ad12013-08-23 02:12:5975 return t1->timestamp > t2->timestamp;
76}
77
rdevlin.cronin372cf1d52016-03-30 22:46:1778tabs::Tab CreateTabModelHelper(
[email protected]d791ad12013-08-23 02:12:5979 const sessions::SerializedNavigationEntry& current_navigation,
80 const std::string& session_id,
81 int index,
82 bool pinned,
sdy7710d22c2016-08-09 14:04:3483 bool active,
[email protected]d791ad12013-08-23 02:12:5984 const Extension* extension) {
rdevlin.cronin372cf1d52016-03-30 22:46:1785 tabs::Tab tab_struct;
[email protected]d791ad12013-08-23 02:12:5986
kalman4399163f2014-10-23 20:34:5887 const GURL& url = current_navigation.virtual_url();
[email protected]04338722013-12-24 23:18:0588 std::string title = base::UTF16ToUTF8(current_navigation.title());
[email protected]d791ad12013-08-23 02:12:5989
rdevlin.cronin372cf1d52016-03-30 22:46:1790 tab_struct.session_id.reset(new std::string(session_id));
91 tab_struct.url.reset(new std::string(url.spec()));
92 tab_struct.fav_icon_url.reset(
kalman4399163f2014-10-23 20:34:5893 new std::string(current_navigation.favicon_url().spec()));
[email protected]d791ad12013-08-23 02:12:5994 if (!title.empty()) {
rdevlin.cronin372cf1d52016-03-30 22:46:1795 tab_struct.title.reset(new std::string(title));
[email protected]d791ad12013-08-23 02:12:5996 } else {
rdevlin.cronin372cf1d52016-03-30 22:46:1797 tab_struct.title.reset(new std::string(
jshin1fb76462016-04-05 22:13:0398 base::UTF16ToUTF8(url_formatter::FormatUrl(url))));
[email protected]d791ad12013-08-23 02:12:5999 }
rdevlin.cronin372cf1d52016-03-30 22:46:17100 tab_struct.index = index;
101 tab_struct.pinned = pinned;
sdy7710d22c2016-08-09 14:04:34102 tab_struct.active = active;
rdevlin.cronin372cf1d52016-03-30 22:46:17103 ExtensionTabUtil::ScrubTabForExtension(extension, nullptr, &tab_struct);
dcheng1fc00f12015-12-26 22:18:03104 return tab_struct;
[email protected]d791ad12013-08-23 02:12:59105}
106
dchengc963c7142016-04-08 03:55:22107std::unique_ptr<windows::Window> CreateWindowModelHelper(
108 std::unique_ptr<std::vector<tabs::Tab>> tabs,
[email protected]d791ad12013-08-23 02:12:59109 const std::string& session_id,
rdevlin.cronin00f1fc22015-04-06 17:19:18110 const windows::WindowType& type,
111 const windows::WindowState& state) {
dchengc963c7142016-04-08 03:55:22112 std::unique_ptr<windows::Window> window_struct(new windows::Window);
dcheng1fc00f12015-12-26 22:18:03113 window_struct->tabs = std::move(tabs);
[email protected]d791ad12013-08-23 02:12:59114 window_struct->session_id.reset(new std::string(session_id));
115 window_struct->incognito = false;
116 window_struct->always_on_top = false;
117 window_struct->focused = false;
118 window_struct->type = type;
119 window_struct->state = state;
dcheng1fc00f12015-12-26 22:18:03120 return window_struct;
[email protected]d791ad12013-08-23 02:12:59121}
122
dchengc963c7142016-04-08 03:55:22123std::unique_ptr<api::sessions::Session> CreateSessionModelHelper(
[email protected]d791ad12013-08-23 02:12:59124 int last_modified,
dchengc963c7142016-04-08 03:55:22125 std::unique_ptr<tabs::Tab> tab,
126 std::unique_ptr<windows::Window> window) {
127 std::unique_ptr<api::sessions::Session> session_struct(
rdevlin.cronin2e624f82016-03-29 00:15:03128 new api::sessions::Session());
[email protected]d791ad12013-08-23 02:12:59129 session_struct->last_modified = last_modified;
130 if (tab)
dcheng1fc00f12015-12-26 22:18:03131 session_struct->tab = std::move(tab);
[email protected]d791ad12013-08-23 02:12:59132 else if (window)
dcheng1fc00f12015-12-26 22:18:03133 session_struct->window = std::move(window);
[email protected]d791ad12013-08-23 02:12:59134 else
135 NOTREACHED();
dcheng1fc00f12015-12-26 22:18:03136 return session_struct;
[email protected]d791ad12013-08-23 02:12:59137}
138
sdy7710d22c2016-08-09 14:04:34139bool is_window_entry(const sessions::TabRestoreService::Entry& entry) {
140 return entry.type == sessions::TabRestoreService::WINDOW;
[email protected]d791ad12013-08-23 02:12:59141}
142
sdy7710d22c2016-08-09 14:04:34143} // namespace
[email protected]d791ad12013-08-23 02:12:59144
rdevlin.cronin372cf1d52016-03-30 22:46:17145tabs::Tab SessionsGetRecentlyClosedFunction::CreateTabModel(
blundell74001adc2015-09-18 11:04:25146 const sessions::TabRestoreService::Tab& tab,
sdy7710d22c2016-08-09 14:04:34147 bool active) {
rdevlin.cronin456b2832016-10-10 20:20:21148 return CreateTabModelHelper(tab.navigations[tab.current_navigation_index],
sdy7710d22c2016-08-09 14:04:34149 base::IntToString(tab.id), tab.tabstrip_index,
150 tab.pinned, active, extension());
[email protected]d791ad12013-08-23 02:12:59151}
152
dchengc963c7142016-04-08 03:55:22153std::unique_ptr<windows::Window>
blundell74001adc2015-09-18 11:04:25154SessionsGetRecentlyClosedFunction::CreateWindowModel(
sdy7710d22c2016-08-09 14:04:34155 const sessions::TabRestoreService::Window& window) {
[email protected]d791ad12013-08-23 02:12:59156 DCHECK(!window.tabs.empty());
157
Jinho Bangb5216cec2018-01-17 19:43:11158 auto tabs = std::make_unique<std::vector<tabs::Tab>>();
sdy7710d22c2016-08-09 14:04:34159 for (const auto& tab : window.tabs)
160 tabs->push_back(
161 CreateTabModel(*tab, tab->tabstrip_index == window.selected_tab_index));
[email protected]d791ad12013-08-23 02:12:59162
sdy7710d22c2016-08-09 14:04:34163 return CreateWindowModelHelper(std::move(tabs), base::IntToString(window.id),
rdevlin.cronin00f1fc22015-04-06 17:19:18164 windows::WINDOW_TYPE_NORMAL,
165 windows::WINDOW_STATE_NORMAL);
[email protected]d791ad12013-08-23 02:12:59166}
167
dchengc963c7142016-04-08 03:55:22168std::unique_ptr<api::sessions::Session>
blundell74001adc2015-09-18 11:04:25169SessionsGetRecentlyClosedFunction::CreateSessionModel(
sdy7710d22c2016-08-09 14:04:34170 const sessions::TabRestoreService::Entry& entry) {
dchengc963c7142016-04-08 03:55:22171 std::unique_ptr<tabs::Tab> tab;
172 std::unique_ptr<windows::Window> window;
sdy7710d22c2016-08-09 14:04:34173 switch (entry.type) {
blundell74001adc2015-09-18 11:04:25174 case sessions::TabRestoreService::TAB:
rdevlin.cronin372cf1d52016-03-30 22:46:17175 tab.reset(new tabs::Tab(CreateTabModel(
sdy7710d22c2016-08-09 14:04:34176 static_cast<const sessions::TabRestoreService::Tab&>(entry), false)));
[email protected]d791ad12013-08-23 02:12:59177 break;
blundell74001adc2015-09-18 11:04:25178 case sessions::TabRestoreService::WINDOW:
[email protected]d791ad12013-08-23 02:12:59179 window = CreateWindowModel(
sdy7710d22c2016-08-09 14:04:34180 static_cast<const sessions::TabRestoreService::Window&>(entry));
[email protected]d791ad12013-08-23 02:12:59181 break;
182 default:
183 NOTREACHED();
184 }
sdy7710d22c2016-08-09 14:04:34185 return CreateSessionModelHelper(entry.timestamp.ToTimeT(), std::move(tab),
dcheng1fc00f12015-12-26 22:18:03186 std::move(window));
[email protected]d791ad12013-08-23 02:12:59187}
188
rdevlin.cronin456b2832016-10-10 20:20:21189ExtensionFunction::ResponseAction SessionsGetRecentlyClosedFunction::Run() {
dchengc963c7142016-04-08 03:55:22190 std::unique_ptr<GetRecentlyClosed::Params> params(
[email protected]d791ad12013-08-23 02:12:59191 GetRecentlyClosed::Params::Create(*args_));
192 EXTENSION_FUNCTION_VALIDATE(params);
193 int max_results = api::sessions::MAX_SESSION_RESULTS;
194 if (params->filter && params->filter->max_results)
195 max_results = *params->filter->max_results;
196 EXTENSION_FUNCTION_VALIDATE(max_results >= 0 &&
197 max_results <= api::sessions::MAX_SESSION_RESULTS);
198
rdevlin.cronin2e624f82016-03-29 00:15:03199 std::vector<api::sessions::Session> result;
blundell74001adc2015-09-18 11:04:25200 sessions::TabRestoreService* tab_restore_service =
rdevlin.cronin456b2832016-10-10 20:20:21201 TabRestoreServiceFactory::GetForProfile(
202 Profile::FromBrowserContext(browser_context()));
[email protected]b3e0f85c2014-03-22 04:58:00203
204 // TabRestoreServiceFactory::GetForProfile() can return NULL (i.e., when in
205 // incognito mode)
206 if (!tab_restore_service) {
rdevlin.cronin456b2832016-10-10 20:20:21207 DCHECK(browser_context()->IsOffTheRecord())
blundell74001adc2015-09-18 11:04:25208 << "sessions::TabRestoreService expected for normal profiles";
rdevlin.cronin456b2832016-10-10 20:20:21209 return RespondNow(ArgumentList(GetRecentlyClosed::Results::Create(result)));
[email protected]b3e0f85c2014-03-22 04:58:00210 }
[email protected]d791ad12013-08-23 02:12:59211
212 // List of entries. They are ordered from most to least recent.
213 // We prune the list to contain max 25 entries at any time and removes
214 // uninteresting entries.
sdy7710d22c2016-08-09 14:04:34215 for (const auto& entry : tab_restore_service->entries()) {
216 result.push_back(std::move(*CreateSessionModel(*entry)));
[email protected]d791ad12013-08-23 02:12:59217 }
218
rdevlin.cronin456b2832016-10-10 20:20:21219 return RespondNow(ArgumentList(GetRecentlyClosed::Results::Create(result)));
[email protected]d791ad12013-08-23 02:12:59220}
221
rdevlin.cronin372cf1d52016-03-30 22:46:17222tabs::Tab SessionsGetDevicesFunction::CreateTabModel(
[email protected]d791ad12013-08-23 02:12:59223 const std::string& session_tag,
skuhneb7409dcf2014-11-14 04:06:55224 const sessions::SessionTab& tab,
[email protected]d791ad12013-08-23 02:12:59225 int tab_index,
sdy7710d22c2016-08-09 14:04:34226 bool active) {
[email protected]d791ad12013-08-23 02:12:59227 std::string session_id = SessionId(session_tag, tab.tab_id.id()).ToString();
[email protected]eba8f7d2014-07-28 22:09:23228 return CreateTabModelHelper(
rdevlin.cronin456b2832016-10-10 20:20:21229 tab.navigations[tab.normalized_navigation_index()], session_id, tab_index,
230 tab.pinned, active, extension());
[email protected]d791ad12013-08-23 02:12:59231}
232
dchengc963c7142016-04-08 03:55:22233std::unique_ptr<windows::Window> SessionsGetDevicesFunction::CreateWindowModel(
234 const sessions::SessionWindow& window,
235 const std::string& session_tag) {
[email protected]d791ad12013-08-23 02:12:59236 DCHECK(!window.tabs.empty());
237
238 // Prune tabs that are not syncable or are NewTabPage. Then, sort the tabs
239 // from most recent to least recent.
skuhneb7409dcf2014-11-14 04:06:55240 std::vector<const sessions::SessionTab*> tabs_in_window;
[email protected]d791ad12013-08-23 02:12:59241 for (size_t i = 0; i < window.tabs.size(); ++i) {
avi498cabca2016-09-21 19:03:50242 const sessions::SessionTab* tab = window.tabs[i].get();
[email protected]d791ad12013-08-23 02:12:59243 if (tab->navigations.empty())
244 continue;
245 const sessions::SerializedNavigationEntry& current_navigation =
246 tab->navigations.at(tab->normalized_navigation_index());
rdevlin.cronin456b2832016-10-10 20:20:21247 if (search::IsNTPURL(current_navigation.virtual_url(),
248 Profile::FromBrowserContext(browser_context()))) {
[email protected]d791ad12013-08-23 02:12:59249 continue;
250 }
251 tabs_in_window.push_back(tab);
252 }
253 if (tabs_in_window.empty())
dchengc963c7142016-04-08 03:55:22254 return std::unique_ptr<windows::Window>();
[email protected]d791ad12013-08-23 02:12:59255 std::sort(tabs_in_window.begin(), tabs_in_window.end(), SortTabsByRecency);
256
dchengc963c7142016-04-08 03:55:22257 std::unique_ptr<std::vector<tabs::Tab>> tabs(new std::vector<tabs::Tab>());
[email protected]ddd54352014-04-05 07:43:30258 for (size_t i = 0; i < tabs_in_window.size(); ++i) {
rdevlin.cronin372cf1d52016-03-30 22:46:17259 tabs->push_back(CreateTabModel(session_tag, *tabs_in_window[i], i,
sdy7710d22c2016-08-09 14:04:34260 window.selected_tab_index == (int)i));
[email protected]d791ad12013-08-23 02:12:59261 }
262
263 std::string session_id =
264 SessionId(session_tag, window.window_id.id()).ToString();
265
rdevlin.cronin00f1fc22015-04-06 17:19:18266 windows::WindowType type = windows::WINDOW_TYPE_NONE;
[email protected]d791ad12013-08-23 02:12:59267 switch (window.type) {
skuhneb7409dcf2014-11-14 04:06:55268 case sessions::SessionWindow::TYPE_TABBED:
rdevlin.cronin00f1fc22015-04-06 17:19:18269 type = windows::WINDOW_TYPE_NORMAL;
[email protected]d791ad12013-08-23 02:12:59270 break;
skuhneb7409dcf2014-11-14 04:06:55271 case sessions::SessionWindow::TYPE_POPUP:
rdevlin.cronin00f1fc22015-04-06 17:19:18272 type = windows::WINDOW_TYPE_POPUP;
[email protected]d791ad12013-08-23 02:12:59273 break;
274 }
275
rdevlin.cronin00f1fc22015-04-06 17:19:18276 windows::WindowState state = windows::WINDOW_STATE_NONE;
[email protected]d791ad12013-08-23 02:12:59277 switch (window.show_state) {
278 case ui::SHOW_STATE_NORMAL:
rdevlin.cronin00f1fc22015-04-06 17:19:18279 state = windows::WINDOW_STATE_NORMAL;
[email protected]d791ad12013-08-23 02:12:59280 break;
281 case ui::SHOW_STATE_MINIMIZED:
rdevlin.cronin00f1fc22015-04-06 17:19:18282 state = windows::WINDOW_STATE_MINIMIZED;
[email protected]d791ad12013-08-23 02:12:59283 break;
284 case ui::SHOW_STATE_MAXIMIZED:
rdevlin.cronin00f1fc22015-04-06 17:19:18285 state = windows::WINDOW_STATE_MAXIMIZED;
[email protected]d791ad12013-08-23 02:12:59286 break;
287 case ui::SHOW_STATE_FULLSCREEN:
rdevlin.cronin00f1fc22015-04-06 17:19:18288 state = windows::WINDOW_STATE_FULLSCREEN;
[email protected]d791ad12013-08-23 02:12:59289 break;
290 case ui::SHOW_STATE_DEFAULT:
291 case ui::SHOW_STATE_INACTIVE:
[email protected]d791ad12013-08-23 02:12:59292 case ui::SHOW_STATE_END:
293 break;
294 }
295
dchengc963c7142016-04-08 03:55:22296 std::unique_ptr<windows::Window> window_struct(
dcheng1fc00f12015-12-26 22:18:03297 CreateWindowModelHelper(std::move(tabs), session_id, type, state));
[email protected]d791ad12013-08-23 02:12:59298 // TODO(dwankri): Dig deeper to resolve bounds not being optional, so closed
299 // windows in GetRecentlyClosed can have set values in Window helper.
300 window_struct->left.reset(new int(window.bounds.x()));
301 window_struct->top.reset(new int(window.bounds.y()));
302 window_struct->width.reset(new int(window.bounds.width()));
303 window_struct->height.reset(new int(window.bounds.height()));
304
dcheng1fc00f12015-12-26 22:18:03305 return window_struct;
[email protected]d791ad12013-08-23 02:12:59306}
307
dchengc963c7142016-04-08 03:55:22308std::unique_ptr<api::sessions::Session>
[email protected]d791ad12013-08-23 02:12:59309SessionsGetDevicesFunction::CreateSessionModel(
dchengc963c7142016-04-08 03:55:22310 const sessions::SessionWindow& window,
311 const std::string& session_tag) {
312 std::unique_ptr<windows::Window> window_model(
[email protected]d791ad12013-08-23 02:12:59313 CreateWindowModel(window, session_tag));
314 // There is a chance that after pruning uninteresting tabs the window will be
315 // empty.
dchengc963c7142016-04-08 03:55:22316 return !window_model ? std::unique_ptr<api::sessions::Session>()
dcheng1fc00f12015-12-26 22:18:03317 : CreateSessionModelHelper(window.timestamp.ToTimeT(),
dchengc963c7142016-04-08 03:55:22318 std::unique_ptr<tabs::Tab>(),
dcheng1fc00f12015-12-26 22:18:03319 std::move(window_model));
[email protected]d791ad12013-08-23 02:12:59320}
321
rdevlin.cronin2e624f82016-03-29 00:15:03322api::sessions::Device SessionsGetDevicesFunction::CreateDeviceModel(
maxboguea79d99b72016-09-15 15:59:16323 const sync_sessions::SyncedSession* session) {
[email protected]d791ad12013-08-23 02:12:59324 int max_results = api::sessions::MAX_SESSION_RESULTS;
[email protected]a0c91a9f2014-05-03 03:41:43325 // Already validated in RunAsync().
dchengc963c7142016-04-08 03:55:22326 std::unique_ptr<GetDevices::Params> params(
327 GetDevices::Params::Create(*args_));
[email protected]d791ad12013-08-23 02:12:59328 if (params->filter && params->filter->max_results)
329 max_results = *params->filter->max_results;
330
rdevlin.cronin2e624f82016-03-29 00:15:03331 api::sessions::Device device_struct;
332 device_struct.info = session->session_name;
333 device_struct.device_name = session->session_name;
[email protected]d791ad12013-08-23 02:12:59334
avi498cabca2016-09-21 19:03:50335 for (auto it = session->windows.begin();
droger6a118632015-06-23 17:59:45336 it != session->windows.end() &&
rdevlin.cronin2e624f82016-03-29 00:15:03337 static_cast<int>(device_struct.sessions.size()) < max_results;
droger6a118632015-06-23 17:59:45338 ++it) {
dchengc963c7142016-04-08 03:55:22339 std::unique_ptr<api::sessions::Session> session_model(
zea325508e2017-03-29 20:11:22340 CreateSessionModel(it->second->wrapped_window, session->session_tag));
[email protected]d791ad12013-08-23 02:12:59341 if (session_model)
rdevlin.cronin2e624f82016-03-29 00:15:03342 device_struct.sessions.push_back(std::move(*session_model));
[email protected]d791ad12013-08-23 02:12:59343 }
dcheng1fc00f12015-12-26 22:18:03344 return device_struct;
[email protected]d791ad12013-08-23 02:12:59345}
346
rdevlin.cronin456b2832016-10-10 20:20:21347ExtensionFunction::ResponseAction SessionsGetDevicesFunction::Run() {
maxbogue0a379452016-09-22 21:35:05348 browser_sync::ProfileSyncService* service =
rdevlin.cronin456b2832016-10-10 20:20:21349 ProfileSyncServiceFactory::GetInstance()->GetForProfile(
350 Profile::FromBrowserContext(browser_context()));
[email protected]d791ad12013-08-23 02:12:59351 if (!(service && service->GetPreferredDataTypes().Has(syncer::SESSIONS))) {
352 // Sync not enabled.
rdevlin.cronin456b2832016-10-10 20:20:21353 return RespondNow(ArgumentList(
354 GetDevices::Results::Create(std::vector<api::sessions::Device>())));
[email protected]d791ad12013-08-23 02:12:59355 }
356
maxboguea79d99b72016-09-15 15:59:16357 sync_sessions::OpenTabsUIDelegate* open_tabs =
358 service->GetOpenTabsUIDelegate();
359 std::vector<const sync_sessions::SyncedSession*> sessions;
[email protected]a9f56622013-11-21 19:37:06360 if (!(open_tabs && open_tabs->GetAllForeignSessions(&sessions))) {
rdevlin.cronin456b2832016-10-10 20:20:21361 return RespondNow(ArgumentList(
362 GetDevices::Results::Create(std::vector<api::sessions::Device>())));
[email protected]d791ad12013-08-23 02:12:59363 }
364
dchengc963c7142016-04-08 03:55:22365 std::unique_ptr<GetDevices::Params> params(
366 GetDevices::Params::Create(*args_));
[email protected]d791ad12013-08-23 02:12:59367 EXTENSION_FUNCTION_VALIDATE(params);
368 if (params->filter && params->filter->max_results) {
369 EXTENSION_FUNCTION_VALIDATE(*params->filter->max_results >= 0 &&
370 *params->filter->max_results <= api::sessions::MAX_SESSION_RESULTS);
371 }
372
rdevlin.cronin2e624f82016-03-29 00:15:03373 std::vector<api::sessions::Device> result;
[email protected]d791ad12013-08-23 02:12:59374 // Sort sessions from most recent to least recent.
375 std::sort(sessions.begin(), sessions.end(), SortSessionsByRecency);
rdevlin.cronin2e624f82016-03-29 00:15:03376 for (size_t i = 0; i < sessions.size(); ++i)
377 result.push_back(CreateDeviceModel(sessions[i]));
[email protected]d791ad12013-08-23 02:12:59378
rdevlin.cronin456b2832016-10-10 20:20:21379 return RespondNow(ArgumentList(GetDevices::Results::Create(result)));
[email protected]d791ad12013-08-23 02:12:59380}
381
rdevlin.cronin456b2832016-10-10 20:20:21382ExtensionFunction::ResponseValue SessionsRestoreFunction::GetRestoredTabResult(
[email protected]fc2b46b2014-05-03 16:33:45383 content::WebContents* contents) {
Devlin Cronin1980f44d2018-02-08 23:14:01384 std::unique_ptr<tabs::Tab> tab(ExtensionTabUtil::CreateTabObject(
385 contents, ExtensionTabUtil::kScrubTab, extension()));
dchengc963c7142016-04-08 03:55:22386 std::unique_ptr<api::sessions::Session> restored_session(
dcheng1fc00f12015-12-26 22:18:03387 CreateSessionModelHelper(base::Time::Now().ToTimeT(), std::move(tab),
dchengc963c7142016-04-08 03:55:22388 std::unique_ptr<windows::Window>()));
rdevlin.cronin456b2832016-10-10 20:20:21389 return ArgumentList(Restore::Results::Create(*restored_session));
[email protected]d791ad12013-08-23 02:12:59390}
391
rdevlin.cronin456b2832016-10-10 20:20:21392ExtensionFunction::ResponseValue
393SessionsRestoreFunction::GetRestoredWindowResult(int window_id) {
Devlin Cronin7050f8e2018-02-07 19:52:04394 Browser* browser = nullptr;
rdevlin.cronin456b2832016-10-10 20:20:21395 std::string error;
Devlin Cronin7050f8e2018-02-07 19:52:04396 if (!windows_util::GetBrowserFromWindowID(this, window_id, 0, &browser,
397 &error)) {
rdevlin.cronin456b2832016-10-10 20:20:21398 return Error(error);
[email protected]d791ad12013-08-23 02:12:59399 }
dchengc963c7142016-04-08 03:55:22400 std::unique_ptr<base::DictionaryValue> window_value(
Devlin Cronin7050f8e2018-02-07 19:52:04401 ExtensionTabUtil::CreateWindowValueForExtension(
402 *browser, extension(), ExtensionTabUtil::kPopulateTabs));
dchengc963c7142016-04-08 03:55:22403 std::unique_ptr<windows::Window> window(
404 windows::Window::FromValue(*window_value));
rdevlin.cronin456b2832016-10-10 20:20:21405 return ArgumentList(Restore::Results::Create(*CreateSessionModelHelper(
dchengc963c7142016-04-08 03:55:22406 base::Time::Now().ToTimeT(), std::unique_ptr<tabs::Tab>(),
rdevlin.cronin456b2832016-10-10 20:20:21407 std::move(window))));
[email protected]d791ad12013-08-23 02:12:59408}
409
rdevlin.cronin456b2832016-10-10 20:20:21410ExtensionFunction::ResponseValue
411SessionsRestoreFunction::RestoreMostRecentlyClosed(Browser* browser) {
blundell74001adc2015-09-18 11:04:25412 sessions::TabRestoreService* tab_restore_service =
rdevlin.cronin456b2832016-10-10 20:20:21413 TabRestoreServiceFactory::GetForProfile(
414 Profile::FromBrowserContext(browser_context()));
sdy7710d22c2016-08-09 14:04:34415 const sessions::TabRestoreService::Entries& entries =
416 tab_restore_service->entries();
[email protected]d791ad12013-08-23 02:12:59417
rdevlin.cronin456b2832016-10-10 20:20:21418 if (entries.empty())
419 return Error(kNoRecentlyClosedSessionsError);
[email protected]d791ad12013-08-23 02:12:59420
sdy7710d22c2016-08-09 14:04:34421 bool is_window = is_window_entry(*entries.front());
blundellbde024d2015-09-30 13:47:07422 sessions::LiveTabContext* context =
423 BrowserLiveTabContext::FindContextForWebContents(
[email protected]d791ad12013-08-23 02:12:59424 browser->tab_strip_model()->GetActiveWebContents());
blundell80c5b2a02015-09-17 18:22:12425 std::vector<sessions::LiveTab*> restored_tabs =
scottmgd161e6c2016-02-17 02:08:01426 tab_restore_service->RestoreMostRecentEntry(context);
blundell80c5b2a02015-09-17 18:22:12427 DCHECK(restored_tabs.size());
[email protected]d791ad12013-08-23 02:12:59428
blundell80c5b2a02015-09-17 18:22:12429 sessions::ContentLiveTab* first_tab =
430 static_cast<sessions::ContentLiveTab*>(restored_tabs[0]);
[email protected]d791ad12013-08-23 02:12:59431 if (is_window) {
rdevlin.cronin456b2832016-10-10 20:20:21432 return GetRestoredWindowResult(
blundell80c5b2a02015-09-17 18:22:12433 ExtensionTabUtil::GetWindowIdOfTab(first_tab->web_contents()));
[email protected]d791ad12013-08-23 02:12:59434 }
435
rdevlin.cronin456b2832016-10-10 20:20:21436 return GetRestoredTabResult(first_tab->web_contents());
[email protected]d791ad12013-08-23 02:12:59437}
438
rdevlin.cronin456b2832016-10-10 20:20:21439ExtensionFunction::ResponseValue SessionsRestoreFunction::RestoreLocalSession(
440 const SessionId& session_id,
441 Browser* browser) {
blundell74001adc2015-09-18 11:04:25442 sessions::TabRestoreService* tab_restore_service =
rdevlin.cronin456b2832016-10-10 20:20:21443 TabRestoreServiceFactory::GetForProfile(
444 Profile::FromBrowserContext(browser_context()));
sdy7710d22c2016-08-09 14:04:34445 const sessions::TabRestoreService::Entries& entries =
446 tab_restore_service->entries();
[email protected]d791ad12013-08-23 02:12:59447
rdevlin.cronin456b2832016-10-10 20:20:21448 if (entries.empty())
449 return Error(kInvalidSessionIdError, session_id.ToString());
[email protected]d791ad12013-08-23 02:12:59450
451 // Check if the recently closed list contains an entry with the provided id.
452 bool is_window = false;
sdy7710d22c2016-08-09 14:04:34453 for (const auto& entry : entries) {
454 if (entry->id == session_id.id()) {
455 // A full window is being restored only if the entry ID
[email protected]d791ad12013-08-23 02:12:59456 // matches the provided ID and the entry type is Window.
sdy7710d22c2016-08-09 14:04:34457 is_window = is_window_entry(*entry);
[email protected]d791ad12013-08-23 02:12:59458 break;
459 }
460 }
461
blundellbde024d2015-09-30 13:47:07462 sessions::LiveTabContext* context =
463 BrowserLiveTabContext::FindContextForWebContents(
[email protected]d791ad12013-08-23 02:12:59464 browser->tab_strip_model()->GetActiveWebContents());
blundell80c5b2a02015-09-17 18:22:12465 std::vector<sessions::LiveTab*> restored_tabs =
nick3b04f322016-08-31 19:29:19466 tab_restore_service->RestoreEntryById(context, session_id.id(),
467 WindowOpenDisposition::UNKNOWN);
blundell80c5b2a02015-09-17 18:22:12468 // If the ID is invalid, restored_tabs will be empty.
rdevlin.cronin456b2832016-10-10 20:20:21469 if (restored_tabs.empty())
470 return Error(kInvalidSessionIdError, session_id.ToString());
[email protected]d791ad12013-08-23 02:12:59471
blundell80c5b2a02015-09-17 18:22:12472 sessions::ContentLiveTab* first_tab =
473 static_cast<sessions::ContentLiveTab*>(restored_tabs[0]);
474
475 // Retrieve the window through any of the tabs in restored_tabs.
[email protected]d791ad12013-08-23 02:12:59476 if (is_window) {
rdevlin.cronin456b2832016-10-10 20:20:21477 return GetRestoredWindowResult(
blundell80c5b2a02015-09-17 18:22:12478 ExtensionTabUtil::GetWindowIdOfTab(first_tab->web_contents()));
[email protected]d791ad12013-08-23 02:12:59479 }
480
rdevlin.cronin456b2832016-10-10 20:20:21481 return GetRestoredTabResult(first_tab->web_contents());
[email protected]d791ad12013-08-23 02:12:59482}
483
rdevlin.cronin456b2832016-10-10 20:20:21484ExtensionFunction::ResponseValue SessionsRestoreFunction::RestoreForeignSession(
485 const SessionId& session_id,
486 Browser* browser) {
487 Profile* profile = Profile::FromBrowserContext(browser_context());
maxbogue0a379452016-09-22 21:35:05488 browser_sync::ProfileSyncService* service =
rdevlin.cronin456b2832016-10-10 20:20:21489 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile);
490 if (!(service && service->GetPreferredDataTypes().Has(syncer::SESSIONS)))
491 return Error(kSessionSyncError);
maxboguea79d99b72016-09-15 15:59:16492 sync_sessions::OpenTabsUIDelegate* open_tabs =
493 service->GetOpenTabsUIDelegate();
rdevlin.cronin456b2832016-10-10 20:20:21494 if (!open_tabs)
495 return Error(kSessionSyncError);
[email protected]d791ad12013-08-23 02:12:59496
skuhneb7409dcf2014-11-14 04:06:55497 const sessions::SessionTab* tab = NULL;
[email protected]a9f56622013-11-21 19:37:06498 if (open_tabs->GetForeignTab(session_id.session_tag(),
499 session_id.id(),
500 &tab)) {
[email protected]d791ad12013-08-23 02:12:59501 TabStripModel* tab_strip = browser->tab_strip_model();
502 content::WebContents* contents = tab_strip->GetActiveWebContents();
503
504 content::WebContents* tab_contents =
nick3b04f322016-08-31 19:29:19505 SessionRestore::RestoreForeignSessionTab(
506 contents, *tab, WindowOpenDisposition::NEW_FOREGROUND_TAB);
rdevlin.cronin456b2832016-10-10 20:20:21507 return GetRestoredTabResult(tab_contents);
[email protected]d791ad12013-08-23 02:12:59508 }
509
510 // Restoring a full window.
skuhneb7409dcf2014-11-14 04:06:55511 std::vector<const sessions::SessionWindow*> windows;
rdevlin.cronin456b2832016-10-10 20:20:21512 if (!open_tabs->GetForeignSession(session_id.session_tag(), &windows))
513 return Error(kInvalidSessionIdError, session_id.ToString());
[email protected]d791ad12013-08-23 02:12:59514
skuhneb7409dcf2014-11-14 04:06:55515 std::vector<const sessions::SessionWindow*>::const_iterator window =
516 windows.begin();
[email protected]d791ad12013-08-23 02:12:59517 while (window != windows.end()
518 && (*window)->window_id.id() != session_id.id()) {
519 ++window;
520 }
rdevlin.cronin456b2832016-10-10 20:20:21521 if (window == windows.end())
522 return Error(kInvalidSessionIdError, session_id.ToString());
[email protected]d791ad12013-08-23 02:12:59523
[email protected]d791ad12013-08-23 02:12:59524 // Only restore one window at a time.
rdevlin.cronin456b2832016-10-10 20:20:21525 std::vector<Browser*> browsers =
526 SessionRestore::RestoreForeignSessionWindows(profile, window, window + 1);
[email protected]d791ad12013-08-23 02:12:59527 // Will always create one browser because we only restore one window per call.
528 DCHECK_EQ(1u, browsers.size());
rdevlin.cronin456b2832016-10-10 20:20:21529 return GetRestoredWindowResult(ExtensionTabUtil::GetWindowId(browsers[0]));
[email protected]d791ad12013-08-23 02:12:59530}
531
rdevlin.cronin456b2832016-10-10 20:20:21532ExtensionFunction::ResponseAction SessionsRestoreFunction::Run() {
dchengc963c7142016-04-08 03:55:22533 std::unique_ptr<Restore::Params> params(Restore::Params::Create(*args_));
[email protected]d791ad12013-08-23 02:12:59534 EXTENSION_FUNCTION_VALIDATE(params);
535
rdevlin.cronin456b2832016-10-10 20:20:21536 Profile* profile = Profile::FromBrowserContext(browser_context());
537 Browser* browser = chrome::FindBrowserWithProfile(profile);
538 if (!browser)
539 return RespondNow(Error(kNoBrowserToRestoreSession));
[email protected]d791ad12013-08-23 02:12:59540
rdevlin.cronin456b2832016-10-10 20:20:21541 if (profile != profile->GetOriginalProfile())
542 return RespondNow(Error(kRestoreInIncognitoError));
[email protected]ecf519882014-03-21 15:49:52543
[email protected]d791ad12013-08-23 02:12:59544 if (!params->session_id)
rdevlin.cronin456b2832016-10-10 20:20:21545 return RespondNow(RestoreMostRecentlyClosed(browser));
[email protected]d791ad12013-08-23 02:12:59546
dchengc963c7142016-04-08 03:55:22547 std::unique_ptr<SessionId> session_id(SessionId::Parse(*params->session_id));
rdevlin.cronin456b2832016-10-10 20:20:21548 if (!session_id)
549 return RespondNow(Error(kInvalidSessionIdError, *params->session_id));
[email protected]d791ad12013-08-23 02:12:59550
rdevlin.cronin456b2832016-10-10 20:20:21551 return RespondNow(session_id->IsForeign()
552 ? RestoreForeignSession(*session_id, browser)
553 : RestoreLocalSession(*session_id, browser));
[email protected]d791ad12013-08-23 02:12:59554}
555
[email protected]38f92582014-03-30 20:48:55556SessionsEventRouter::SessionsEventRouter(Profile* profile)
557 : profile_(profile),
558 tab_restore_service_(TabRestoreServiceFactory::GetForProfile(profile)) {
559 // TabRestoreServiceFactory::GetForProfile() can return NULL (i.e., when in
560 // incognito mode)
561 if (tab_restore_service_) {
562 tab_restore_service_->LoadTabsFromLastSession();
563 tab_restore_service_->AddObserver(this);
564 }
565}
566
567SessionsEventRouter::~SessionsEventRouter() {
568 if (tab_restore_service_)
569 tab_restore_service_->RemoveObserver(this);
570}
571
572void SessionsEventRouter::TabRestoreServiceChanged(
blundell74001adc2015-09-18 11:04:25573 sessions::TabRestoreService* service) {
dchengc963c7142016-04-08 03:55:22574 std::unique_ptr<base::ListValue> args(new base::ListValue());
Jinho Bangb5216cec2018-01-17 19:43:11575 EventRouter::Get(profile_)->BroadcastEvent(std::make_unique<Event>(
ricea91d6fc122016-08-30 08:47:14576 events::SESSIONS_ON_CHANGED, api::sessions::OnChanged::kEventName,
577 std::move(args)));
[email protected]38f92582014-03-30 20:48:55578}
579
580void SessionsEventRouter::TabRestoreServiceDestroyed(
blundell74001adc2015-09-18 11:04:25581 sessions::TabRestoreService* service) {
[email protected]38f92582014-03-30 20:48:55582 tab_restore_service_ = NULL;
583}
584
585SessionsAPI::SessionsAPI(content::BrowserContext* context)
586 : browser_context_(context) {
587 EventRouter::Get(browser_context_)->RegisterObserver(this,
588 api::sessions::OnChanged::kEventName);
589}
590
591SessionsAPI::~SessionsAPI() {
592}
593
594void SessionsAPI::Shutdown() {
595 EventRouter::Get(browser_context_)->UnregisterObserver(this);
596}
597
Daniel Bratella413dfd2017-10-10 20:08:26598static base::LazyInstance<BrowserContextKeyedAPIFactory<SessionsAPI>>::
599 DestructorAtExit g_sessions_api_factory = LAZY_INSTANCE_INITIALIZER;
[email protected]38f92582014-03-30 20:48:55600
601BrowserContextKeyedAPIFactory<SessionsAPI>*
602SessionsAPI::GetFactoryInstance() {
Daniel Bratella413dfd2017-10-10 20:08:26603 return g_sessions_api_factory.Pointer();
[email protected]38f92582014-03-30 20:48:55604}
605
606void SessionsAPI::OnListenerAdded(const EventListenerInfo& details) {
607 sessions_event_router_.reset(
608 new SessionsEventRouter(Profile::FromBrowserContext(browser_context_)));
609 EventRouter::Get(browser_context_)->UnregisterObserver(this);
610}
611
[email protected]d791ad12013-08-23 02:12:59612} // namespace extensions