foreign_session_handler.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/foreign_session_handler.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/time_formatting.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_vector.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_number_conversions.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/utf_string_conversions.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/prefs/pref_service.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/prefs/scoped_user_pref_update.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/session_restore.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sync/profile_sync_service.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sync/profile_sync_service_factory.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_ANDROID) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/search/other_device_menu_controller.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/new_tab_ui.h" 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/session_favicon_source.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/web_ui_util.h" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_notification_types.h" 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h" 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/time_format.h" 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h" 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h" 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_source.h" 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h" 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace browser_sync { 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maximum number of sessions we're going to display on the NTP 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const size_t kMaxSessionsToShow = 10; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Comparator function for use with std::sort that will sort sessions by 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// descending modified_time (i.e., most recent first). 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SortSessionsByRecency(const SyncedSession* s1, const SyncedSession* s2) { 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return s1->modified_time > s2->modified_time; 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namepace 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ForeignSessionHandler::ForeignSessionHandler() { 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ForeignSessionHandler::RegisterUserPrefs(PrefService* prefs) { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefs->RegisterDictionaryPref(prefs::kNtpCollapsedForeignSessions, 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrefService::UNSYNCABLE_PREF); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ForeignSessionHandler::OpenForeignSessionTab( 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::WebUI* web_ui, 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& session_string_value, 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SessionID::id_type window_num, 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SessionID::id_type tab_id, 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const WindowOpenDisposition& disposition) { 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SessionModelAssociator* associator = GetModelAssociator(web_ui); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!associator) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We don't actually care about |window_num|, this is just a sanity check. 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LT(kInvalidId, window_num); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SessionTab* tab; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!associator->GetForeignTab(session_string_value, tab_id, &tab)) { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to load foreign tab."; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab->navigations.empty()) { 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Foreign tab no longer has valid navigations."; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SessionRestore::RestoreForeignSessionTab( 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui->GetWebContents(), *tab, disposition); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ForeignSessionHandler::OpenForeignSessionWindows( 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::WebUI* web_ui, 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& session_string_value, 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SessionID::id_type window_num) { 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SessionModelAssociator* associator = GetModelAssociator(web_ui); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!associator) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<const SessionWindow*> windows; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: we don't own the ForeignSessions themselves. 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!associator->GetForeignSession(session_string_value, &windows)) { 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "ForeignSessionHandler failed to get session data from" 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "SessionModelAssociator."; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<const SessionWindow*>::const_iterator iter_begin = 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) windows.begin() + (window_num == kInvalidId ? 0 : window_num); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<const SessionWindow*>::const_iterator iter_end = 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_num == kInvalidId ? 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<const SessionWindow*>::const_iterator(windows.end()) : 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter_begin + 1; 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SessionRestore::RestoreForeignSessionWindows( 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile::FromWebUI(web_ui), iter_begin, iter_end); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ForeignSessionHandler::SessionTabToValue( 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SessionTab& tab, 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DictionaryValue* dictionary) { 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab.navigations.empty()) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int selected_index = std::min(tab.current_navigation_index, 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<int>(tab.navigations.size() - 1)); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const TabNavigation& current_navigation = 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab.navigations.at(selected_index); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GURL tab_url = current_navigation.virtual_url(); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_url == GURL(chrome::kChromeUINewTabURL)) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NewTabUI::SetUrlTitleAndDirection(dictionary, current_navigation.title(), 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_url); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dictionary->SetString("type", "tab"); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dictionary->SetDouble("timestamp", 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<double>(tab.timestamp.ToInternalValue())); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(jeremycho): This should probably be renamed to tabId to avoid 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // confusion with the ID corresponding to a session. Investigate all the 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // places (C++ and JS) where this is being used. (http://crbug.com/154865). 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dictionary->SetInteger("sessionId", tab.tab_id.id()); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SessionModelAssociator* ForeignSessionHandler::GetModelAssociator( 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::WebUI* web_ui) { 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile* profile = Profile::FromWebUI(web_ui); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileSyncService* service = 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only return the associator if it exists and it is done syncing sessions. 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (service && service->ShouldPushChanges()) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return service->GetSessionModelAssociator(); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ForeignSessionHandler::RegisterMessages() { 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui()->RegisterMessageCallback("deleteForeignSession", 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&ForeignSessionHandler::HandleDeleteForeignSession, 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this))); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui()->RegisterMessageCallback("getForeignSessions", 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&ForeignSessionHandler::HandleGetForeignSessions, 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this))); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui()->RegisterMessageCallback("openForeignSession", 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&ForeignSessionHandler::HandleOpenForeignSession, 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this))); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui()->RegisterMessageCallback("setForeignSessionCollapsed", 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&ForeignSessionHandler::HandleSetForeignSessionCollapsed, 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this))); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui()->RegisterMessageCallback("showOtherDeviceSessionPopup", 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&ForeignSessionHandler::HandleShowOtherDeviceSessionPopup, 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this))); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ForeignSessionHandler::Init() { 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile* profile = Profile::FromWebUI(web_ui()); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileSyncService* service = 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) registrar_.Add(this, chrome::NOTIFICATION_SYNC_CONFIGURE_DONE, 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Source<ProfileSyncService>(service)); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) registrar_.Add(this, chrome::NOTIFICATION_FOREIGN_SESSION_UPDATED, 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Source<Profile>(profile)); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) registrar_.Add(this, chrome::NOTIFICATION_FOREIGN_SESSION_DISABLED, 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Source<Profile>(profile)); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add the data source for synced favicons. 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ChromeURLDataManager::AddDataSource(profile, 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new SessionFaviconSource(profile)); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ForeignSessionHandler::Observe( 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int type, 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::NotificationSource& source, 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::NotificationDetails& details) { 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ListValue list_value; 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (type) { 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case chrome::NOTIFICATION_FOREIGN_SESSION_DISABLED: 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Tab sync is disabled, so clean up data about collapsed sessions. 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile::FromWebUI(web_ui())->GetPrefs()->ClearPref( 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefs::kNtpCollapsedForeignSessions); 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Fall through. 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case chrome::NOTIFICATION_SYNC_CONFIGURE_DONE: 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case chrome::NOTIFICATION_FOREIGN_SESSION_UPDATED: 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleGetForeignSessions(&list_value); 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ForeignSessionHandler::IsTabSyncEnabled() { 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile* profile = Profile::FromWebUI(web_ui()); 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileSyncService* service = 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return service && service->GetPreferredDataTypes().Has(syncer::SESSIONS); 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)string16 ForeignSessionHandler::FormatSessionTime(const base::Time& time) { 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return a time like "1 hour ago", "2 days ago", etc. 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TimeFormat::TimeElapsed(base::Time::Now() - time); 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ForeignSessionHandler::HandleGetForeignSessions(const ListValue* args) { 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SessionModelAssociator* associator = GetModelAssociator(web_ui()); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<const SyncedSession*> sessions; 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ListValue session_list; 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (associator && associator->GetAllForeignSessions(&sessions)) { 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sort sessions from most recent to least recent. 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::sort(sessions.begin(), sessions.end(), SortSessionsByRecency); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use a pref to keep track of sessions that were collapsed by the user. 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // To prevent the pref from accumulating stale sessions, clear it each time 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and only add back sessions that are still current. 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DictionaryPrefUpdate pref_update(Profile::FromWebUI(web_ui())->GetPrefs(), 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefs::kNtpCollapsedForeignSessions); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DictionaryValue* current_collapsed_sessions = pref_update.Get(); 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<DictionaryValue> collapsed_sessions( 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_collapsed_sessions->DeepCopy()); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_collapsed_sessions->Clear(); 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: we don't own the SyncedSessions themselves. 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < sessions.size() && i < kMaxSessionsToShow; ++i) { 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SyncedSession* session = sessions[i]; 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& session_tag = session->session_tag; 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<DictionaryValue> session_data(new DictionaryValue()); 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) session_data->SetString("tag", session_tag); 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) session_data->SetString("name", session->session_name); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) session_data->SetString("deviceType", session->DeviceTypeAsString()); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) session_data->SetString("modifiedTime", 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FormatSessionTime(session->modified_time)); 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_collapsed = collapsed_sessions->HasKey(session_tag); 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) session_data->SetBoolean("collapsed", is_collapsed); 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_collapsed) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_collapsed_sessions->SetBoolean(session_tag, true); 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<ListValue> window_list(new ListValue()); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (SyncedSession::SyncedWindowMap::const_iterator it = 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) session->windows.begin(); it != session->windows.end(); ++it) { 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SessionWindow* window = it->second; 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<DictionaryValue> window_data(new DictionaryValue()); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (SessionWindowToValue(*window, window_data.get())) 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_list->Append(window_data.release()); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) session_data->Set("windows", window_list.release()); 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) session_list.Append(session_data.release()); 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::FundamentalValue tab_sync_enabled(IsTabSyncEnabled()); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui()->CallJavascriptFunction("ntp.setForeignSessions", 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) session_list, 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_sync_enabled); 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ForeignSessionHandler::HandleOpenForeignSession(const ListValue* args) { 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t num_args = args->GetSize(); 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Expect either 1 or 8 args. For restoring an entire session, only 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // one argument is required -- the session tag. To restore a tab, 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the additional args required are the window id, the tab id, 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and 4 properties of the event object (button, altKey, ctrlKey, 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // metaKey, shiftKey) for determining how to open the tab. 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (num_args != 8U && num_args != 1U) { 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "openForeignSession called with " << args->GetSize() 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " arguments."; 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Extract the session tag (always provided). 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string session_string_value; 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!args->GetString(0, &session_string_value)) { 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to extract session tag."; 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Extract window number. 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string window_num_str; 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int window_num = kInvalidId; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (num_args >= 2 && (!args->GetString(1, &window_num_str) || 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !base::StringToInt(window_num_str, &window_num))) { 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to extract window number."; 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Extract tab id. 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string tab_id_str; 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SessionID::id_type tab_id = kInvalidId; 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (num_args >= 3 && (!args->GetString(2, &tab_id_str) || 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !base::StringToInt(tab_id_str, &tab_id))) { 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to extract tab SessionID."; 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_id != kInvalidId) { 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WindowOpenDisposition disposition = 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui_util::GetDispositionFromClick(args, 3); 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OpenForeignSessionTab( 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui(), session_string_value, window_num, tab_id, disposition); 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OpenForeignSessionWindows(web_ui(), session_string_value, window_num); 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ForeignSessionHandler::HandleDeleteForeignSession(const ListValue* args) { 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (args->GetSize() != 1U) { 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Wrong number of args to deleteForeignSession"; 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the session tag argument (required). 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string session_tag; 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!args->GetString(0, &session_tag)) { 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Unable to extract session tag"; 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SessionModelAssociator* associator = GetModelAssociator(web_ui()); 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (associator) 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) associator->DeleteForeignSession(session_tag); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ForeignSessionHandler::HandleSetForeignSessionCollapsed( 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ListValue* args) { 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (args->GetSize() != 2U) { 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Wrong number of args to setForeignSessionCollapsed"; 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the session tag argument (required). 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string session_tag; 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!args->GetString(0, &session_tag)) { 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Unable to extract session tag"; 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_collapsed; 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!args->GetBoolean(1, &is_collapsed)) { 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Unable to extract boolean argument"; 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Store session tags for collapsed sessions in a preference so that the 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // collapsed state persists. 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs(); 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DictionaryPrefUpdate update(prefs, prefs::kNtpCollapsedForeignSessions); 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_collapsed) 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) update.Get()->SetBoolean(session_tag, true); 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) update.Get()->Remove(session_tag, NULL); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ForeignSessionHandler::HandleShowOtherDeviceSessionPopup( 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ListValue* args) { 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Exclude Android until an OtherDeviceMenu view is implemented for it. 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) #if !defined(OS_ANDROID) 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(args->GetSize() == 3U); 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Extract the session tag. 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string session_string_value; 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(args->GetString(0, &session_string_value)); 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Extract horizontal coordinate of the click relative to the origin of the 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // screen coordinate system. 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double screen_x; 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(args->GetDouble(1, &screen_x)); 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Extract vertical coordinate of the click relative to the origin of the 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // screen coordinate system. 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double screen_y; 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(args->GetDouble(2, &screen_y)); 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OtherDeviceMenuController* menu = new OtherDeviceMenuController( 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui(), 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) session_string_value, gfx::Point(screen_x, screen_y)); 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu->ShowMenu(); 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) #endif 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ForeignSessionHandler::SessionWindowToValue( 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SessionWindow& window, 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DictionaryValue* dictionary) { 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (window.tabs.empty()) { 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<ListValue> tab_values(new ListValue()); 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Calculate the last |modification_time| for all entries within a window. 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Time modification_time = window.timestamp; 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < window.tabs.size(); ++i) { 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<DictionaryValue> tab_value(new DictionaryValue()); 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (SessionTabToValue(*window.tabs[i], tab_value.get())) { 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modification_time = std::max(modification_time, 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window.tabs[i]->timestamp); 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_values->Append(tab_value.release()); 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_values->GetSize() == 0) 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dictionary->SetString("type", "window"); 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dictionary->SetDouble("timestamp", modification_time.ToInternalValue()); 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const base::TimeDelta last_synced = base::Time::Now() - modification_time; 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If clock skew leads to a future time, or we last synced less than a minute 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ago, output "Just now". 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dictionary->SetString("userVisibleTimestamp", 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_synced < base::TimeDelta::FromMinutes(1) ? 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetStringUTF16(IDS_SYNC_TIME_JUST_NOW) : 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeFormat::TimeElapsed(last_synced)); 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dictionary->SetInteger("sessionId", window.window_id.id()); 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dictionary->Set("tabs", tab_values.release()); 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace browser_sync 437