• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/ui/webui/foreign_session_handler.h"
6 
7 #include <algorithm>
8 #include <string>
9 #include <vector>
10 #include "base/memory/scoped_vector.h"
11 #include "base/string_number_conversions.h"
12 #include "base/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/sessions/session_restore.h"
16 #include "chrome/browser/sync/engine/syncapi.h"
17 #include "chrome/browser/sync/profile_sync_service.h"
18 #include "chrome/browser/ui/webui/new_tab_ui.h"
19 #include "content/common/notification_details.h"
20 #include "content/common/notification_service.h"
21 #include "chrome/common/url_constants.h"
22 
23 namespace browser_sync {
24 
25 // Maximum number of session we're going to display on the NTP
26 static const int kMaxSessionsToShow = 10;
27 
28 // Invalid value, used to note that we don't have a tab or window number.
29 static const int kInvalidId = -1;
30 
ForeignSessionHandler()31 ForeignSessionHandler::ForeignSessionHandler() {
32   Init();
33 }
34 
RegisterMessages()35 void ForeignSessionHandler::RegisterMessages() {
36   web_ui_->RegisterMessageCallback("getForeignSessions",
37       NewCallback(this,
38       &ForeignSessionHandler::HandleGetForeignSessions));
39   web_ui_->RegisterMessageCallback("openForeignSession",
40       NewCallback(this,
41       &ForeignSessionHandler::HandleOpenForeignSession));
42 }
43 
Init()44 void ForeignSessionHandler::Init() {
45   registrar_.Add(this, NotificationType::SYNC_CONFIGURE_DONE,
46                  NotificationService::AllSources());
47   registrar_.Add(this, NotificationType::FOREIGN_SESSION_UPDATED,
48                  NotificationService::AllSources());
49   registrar_.Add(this, NotificationType::FOREIGN_SESSION_DISABLED,
50                  NotificationService::AllSources());
51 }
52 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)53 void ForeignSessionHandler::Observe(NotificationType type,
54                                     const NotificationSource& source,
55                                     const NotificationDetails& details) {
56   ListValue list_value;
57   switch (type.value) {
58     case NotificationType::SYNC_CONFIGURE_DONE:
59     case NotificationType::FOREIGN_SESSION_UPDATED:
60       HandleGetForeignSessions(&list_value);
61       break;
62     case NotificationType::FOREIGN_SESSION_DISABLED:
63       // Calling foreignSessions with empty list will automatically hide
64       // foreign session section.
65       web_ui_->CallJavascriptFunction("foreignSessions", list_value);
66       break;
67     default:
68       NOTREACHED();
69   }
70 }
71 
GetModelAssociator()72 SessionModelAssociator* ForeignSessionHandler::GetModelAssociator() {
73   ProfileSyncService* service = web_ui_->GetProfile()->GetProfileSyncService();
74   if (service == NULL)
75     return NULL;
76   // We only want to set the model associator if there is one, and it is done
77   // syncing sessions.
78   SessionModelAssociator* model_associator = service->
79       GetSessionModelAssociator();
80   if (model_associator == NULL ||
81       !service->ShouldPushChanges()) {
82     return NULL;
83   }
84   return web_ui_->GetProfile()->GetProfileSyncService()->
85       GetSessionModelAssociator();
86 }
87 
HandleGetForeignSessions(const ListValue * args)88 void ForeignSessionHandler::HandleGetForeignSessions(const ListValue* args) {
89   SessionModelAssociator* associator = GetModelAssociator();
90   std::vector<const ForeignSession*> sessions;
91 
92   if (associator == NULL) {
93     // Called before associator created, exit.
94     return;
95   }
96 
97   // Note: we don't own the ForeignSessions themselves.
98   if (!associator->GetAllForeignSessions(&sessions)) {
99     LOG(ERROR) << "ForeignSessionHandler failed to get session data from"
100         "SessionModelAssociator.";
101     return;
102   }
103   int added_count = 0;
104   ListValue session_list;
105   for (std::vector<const ForeignSession*>::const_iterator i =
106       sessions.begin(); i != sessions.end() &&
107       added_count < kMaxSessionsToShow; ++i) {
108     const ForeignSession* foreign_session = *i;
109     scoped_ptr<ListValue> window_list(new ListValue());
110     for (std::vector<SessionWindow*>::const_iterator it =
111         foreign_session->windows.begin(); it != foreign_session->windows.end();
112         ++it) {
113       SessionWindow* window = *it;
114       scoped_ptr<DictionaryValue> window_data(new DictionaryValue());
115       if (SessionWindowToValue(*window, window_data.get())) {
116         window_data->SetString("sessionTag",
117             foreign_session->foreign_session_tag);
118 
119         // Give ownership to |list_value|.
120         window_list->Append(window_data.release());
121       }
122     }
123     added_count++;
124 
125     // Give ownership to |session_list|.
126     session_list.Append(window_list.release());
127   }
128   web_ui_->CallJavascriptFunction("foreignSessions", session_list);
129 }
130 
HandleOpenForeignSession(const ListValue * args)131 void ForeignSessionHandler::HandleOpenForeignSession(
132     const ListValue* args) {
133   size_t num_args = args->GetSize();
134   if (num_args > 3U || num_args == 0) {
135     LOG(ERROR) << "openForeignWindow called with only " << args->GetSize()
136                << " arguments.";
137     return;
138   }
139 
140   // Extract the machine tag (always provided).
141   std::string session_string_value;
142   if (!args->GetString(0, &session_string_value)) {
143     LOG(ERROR) << "Failed to extract session tag.";
144     return;
145   }
146 
147   // Extract window number.
148   std::string window_num_str;
149   int window_num = kInvalidId;
150   if (num_args >= 2 && (!args->GetString(1, &window_num_str) ||
151       !base::StringToInt(window_num_str, &window_num))) {
152     LOG(ERROR) << "Failed to extract window number.";
153     return;
154   }
155 
156   // Extract tab id.
157   std::string tab_id_str;
158   SessionID::id_type tab_id = kInvalidId;
159   if (num_args == 3 && (!args->GetString(2, &tab_id_str) ||
160       !base::StringToInt(tab_id_str, &tab_id))) {
161     LOG(ERROR) << "Failed to extract tab SessionID.";
162     return;
163   }
164 
165   SessionModelAssociator* associator = GetModelAssociator();
166 
167   if (tab_id != kInvalidId) {
168     // We don't actually care about |window_num|, this is just a sanity check.
169     DCHECK_LT(kInvalidId, window_num);
170     const SessionTab* tab;
171     if (!associator->GetForeignTab(session_string_value, tab_id, &tab)) {
172       LOG(ERROR) << "Failed to load foreign tab.";
173       return;
174     }
175     SessionRestore::RestoreForeignSessionTab(web_ui_->GetProfile(), *tab);
176   } else {
177     std::vector<SessionWindow*> windows;
178     // Note: we don't own the ForeignSessions themselves.
179     if (!associator->GetForeignSession(session_string_value, &windows)) {
180       LOG(ERROR) << "ForeignSessionHandler failed to get session data from"
181           "SessionModelAssociator.";
182       return;
183     }
184     std::vector<SessionWindow*>::const_iterator iter_begin = windows.begin() +
185         ((window_num == kInvalidId) ? 0 : window_num);
186     std::vector<SessionWindow*>::const_iterator iter_end =
187         ((window_num == kInvalidId) ?
188         std::vector<SessionWindow*>::const_iterator(windows.end()) :
189         iter_begin+1);
190     SessionRestore::RestoreForeignSessionWindows(web_ui_->GetProfile(),
191                                                  iter_begin,
192                                                  iter_end);
193   }
194 }
195 
SessionTabToValue(const SessionTab & tab,DictionaryValue * dictionary)196 bool ForeignSessionHandler::SessionTabToValue(
197     const SessionTab& tab,
198     DictionaryValue* dictionary) {
199   if (tab.navigations.empty())
200     return false;
201   int selected_index = tab.current_navigation_index;
202   selected_index = std::max(
203       0,
204       std::min(selected_index,
205                static_cast<int>(tab.navigations.size() - 1)));
206   const TabNavigation& current_navigation =
207       tab.navigations.at(selected_index);
208   if (current_navigation.virtual_url() == GURL(chrome::kChromeUINewTabURL))
209     return false;
210   NewTabUI::SetURLTitleAndDirection(dictionary, current_navigation.title(),
211                                     current_navigation.virtual_url());
212   dictionary->SetString("type", "tab");
213   dictionary->SetDouble("timestamp",
214                         static_cast<double>(tab.timestamp.ToInternalValue()));
215   dictionary->SetInteger("sessionId", tab.tab_id.id());
216   return true;
217 }
218 
SessionWindowToValue(const SessionWindow & window,DictionaryValue * dictionary)219 bool ForeignSessionHandler::SessionWindowToValue(
220     const SessionWindow& window,
221     DictionaryValue* dictionary) {
222   if (window.tabs.empty()) {
223     NOTREACHED();
224     return false;
225   }
226   scoped_ptr<ListValue> tab_values(new ListValue());
227   for (size_t i = 0; i < window.tabs.size(); ++i) {
228     scoped_ptr<DictionaryValue> tab_value(new DictionaryValue());
229     if (SessionTabToValue(*window.tabs[i], tab_value.get()))
230       tab_values->Append(tab_value.release());
231   }
232   if (tab_values->GetSize() == 0)
233     return false;
234   dictionary->SetString("type", "window");
235   dictionary->SetDouble("timestamp",
236       static_cast<double>(window.timestamp.ToInternalValue()));
237   dictionary->SetInteger("sessionId", window.window_id.id());
238   dictionary->Set("tabs", tab_values.release());
239   return true;
240 }
241 
242 }  // namespace browser_sync
243