Home | History | Annotate | Download | only in webui
      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 
     31 ForeignSessionHandler::ForeignSessionHandler() {
     32   Init();
     33 }
     34 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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