| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2012 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/sessions/in_memory_tab_restore_service.h" |
| 6 |
| 7 #include <algorithm> |
| 8 #include <iterator> |
| 9 #include <map> |
| 10 |
| 11 #include "base/metrics/histogram.h" |
| 12 #include "base/stl_util.h" |
| 13 #include "chrome/browser/extensions/extension_service.h" |
| 14 #include "chrome/browser/extensions/tab_helper.h" |
| 15 #include "chrome/browser/profiles/profile.h" |
| 16 #include "chrome/browser/sessions/session_command.h" |
| 17 #include "chrome/browser/sessions/session_service.h" |
| 18 #include "chrome/browser/sessions/session_service_factory.h" |
| 19 #include "chrome/browser/sessions/session_types.h" |
| 20 #include "chrome/browser/sessions/tab_restore_service_delegate.h" |
| 21 #include "chrome/browser/sessions/tab_restore_service_observer.h" |
| 22 #include "chrome/browser/ui/tab_contents/tab_contents.h" |
| 23 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h" |
| 24 #include "chrome/common/extensions/extension.h" |
| 25 #include "chrome/common/extensions/extension_constants.h" |
| 26 #include "chrome/common/url_constants.h" |
| 27 #include "content/public/browser/navigation_controller.h" |
| 28 #include "content/public/browser/navigation_entry.h" |
| 29 #include "content/public/browser/web_contents.h" |
| 30 #include "content/public/browser/session_storage_namespace.h" |
| 31 |
| 32 using content::NavigationController; |
| 33 using content::NavigationEntry; |
| 34 using content::WebContents; |
| 35 |
| 36 namespace { |
| 37 |
| 38 void RecordAppLaunch(Profile* profile, const TabRestoreService::Tab& tab) { |
| 39 #if !defined(OS_ANDROID) |
| 40 GURL url = tab.navigations.at(tab.current_navigation_index).virtual_url(); |
| 41 DCHECK(profile->GetExtensionService()); |
| 42 if (!profile->GetExtensionService()->IsInstalledApp(url)) |
| 43 return; |
| 44 |
| 45 AppLauncherHandler::RecordAppLaunchType( |
| 46 extension_misc::APP_LAUNCH_NTP_RECENTLY_CLOSED); |
| 47 #endif // !defined(OS_ANDROID) |
| 48 } |
| 49 |
| 50 } // namespace |
| 51 |
| 52 InMemoryTabRestoreService::InMemoryTabRestoreService( |
| 53 Profile* profile, |
| 54 TabRestoreService::TimeFactory* time_factory) |
| 55 : profile_(profile), |
| 56 restoring_(false), |
| 57 time_factory_(time_factory) { |
| 58 } |
| 59 |
| 60 InMemoryTabRestoreService::~InMemoryTabRestoreService() { |
| 61 FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_, |
| 62 TabRestoreServiceDestroyed(this)); |
| 63 STLDeleteElements(&entries_); |
| 64 time_factory_ = NULL; |
| 65 } |
| 66 |
| 67 void InMemoryTabRestoreService::AddObserver( |
| 68 TabRestoreServiceObserver* observer) { |
| 69 observer_list_.AddObserver(observer); |
| 70 } |
| 71 |
| 72 void InMemoryTabRestoreService::RemoveObserver( |
| 73 TabRestoreServiceObserver* observer) { |
| 74 observer_list_.RemoveObserver(observer); |
| 75 } |
| 76 |
| 77 void InMemoryTabRestoreService::CreateHistoricalTab( |
| 78 content::WebContents* contents, |
| 79 int index) { |
| 80 if (restoring_) |
| 81 return; |
| 82 |
| 83 TabRestoreServiceDelegate* delegate = |
| 84 TabRestoreServiceDelegate::FindDelegateForWebContents(contents); |
| 85 if (closing_delegates_.find(delegate) != closing_delegates_.end()) |
| 86 return; |
| 87 |
| 88 scoped_ptr<Tab> local_tab(new Tab()); |
| 89 PopulateTab(local_tab.get(), index, delegate, &contents->GetController()); |
| 90 if (local_tab->navigations.empty()) |
| 91 return; |
| 92 |
| 93 AddEntry(local_tab.release(), true, true); |
| 94 } |
| 95 |
| 96 void InMemoryTabRestoreService::BrowserClosing( |
| 97 TabRestoreServiceDelegate* delegate) { |
| 98 closing_delegates_.insert(delegate); |
| 99 |
| 100 scoped_ptr<Window> window(new Window()); |
| 101 window->selected_tab_index = delegate->GetSelectedIndex(); |
| 102 window->timestamp = TimeNow(); |
| 103 window->app_name = delegate->GetAppName(); |
| 104 |
| 105 // Don't use std::vector::resize() because it will push copies of an empty tab |
| 106 // into the vector, which will give all tabs in a window the same ID. |
| 107 for (int i = 0; i < delegate->GetTabCount(); ++i) { |
| 108 window->tabs.push_back(Tab()); |
| 109 } |
| 110 size_t entry_index = 0; |
| 111 for (int tab_index = 0; tab_index < delegate->GetTabCount(); ++tab_index) { |
| 112 PopulateTab(&(window->tabs[entry_index]), |
| 113 tab_index, |
| 114 delegate, |
| 115 &delegate->GetWebContentsAt(tab_index)->GetController()); |
| 116 if (window->tabs[entry_index].navigations.empty()) { |
| 117 window->tabs.erase(window->tabs.begin() + entry_index); |
| 118 } else { |
| 119 window->tabs[entry_index].browser_id = delegate->GetSessionID().id(); |
| 120 entry_index++; |
| 121 } |
| 122 } |
| 123 if (window->tabs.size() == 1 && window->app_name.empty()) { |
| 124 // Short-circuit creating a Window if only 1 tab was present. This fixes |
| 125 // http://crbug.com/56744. Copy the Tab because it's owned by an object on |
| 126 // the stack. |
| 127 AddEntry(new Tab(window->tabs[0]), true, true); |
| 128 } else if (!window->tabs.empty()) { |
| 129 window->selected_tab_index = |
| 130 std::min(static_cast<int>(window->tabs.size() - 1), |
| 131 window->selected_tab_index); |
| 132 AddEntry(window.release(), true, true); |
| 133 } |
| 134 } |
| 135 |
| 136 void InMemoryTabRestoreService::BrowserClosed( |
| 137 TabRestoreServiceDelegate* delegate) { |
| 138 closing_delegates_.erase(delegate); |
| 139 } |
| 140 |
| 141 void InMemoryTabRestoreService::ClearEntries() { |
| 142 OnClearEntries(); |
| 143 STLDeleteElements(&entries_); |
| 144 NotifyTabsChanged(); |
| 145 } |
| 146 |
| 147 const TabRestoreService::Entries& InMemoryTabRestoreService::entries() const { |
| 148 return entries_; |
| 149 } |
| 150 |
| 151 void InMemoryTabRestoreService::RestoreMostRecentEntry( |
| 152 TabRestoreServiceDelegate* delegate) { |
| 153 if (entries_.empty()) |
| 154 return; |
| 155 |
| 156 RestoreEntryById(delegate, entries_.front()->id, UNKNOWN); |
| 157 } |
| 158 |
| 159 TabRestoreService::Tab* InMemoryTabRestoreService::RemoveTabEntryById( |
| 160 SessionID::id_type id) { |
| 161 Entries::iterator i = GetEntryIteratorById(id); |
| 162 if (i == entries_.end()) |
| 163 return NULL; |
| 164 |
| 165 Entry* entry = *i; |
| 166 if (entry->type != TAB) |
| 167 return NULL; |
| 168 |
| 169 Tab* tab = static_cast<Tab*>(entry); |
| 170 entries_.erase(i); |
| 171 return tab; |
| 172 } |
| 173 |
| 174 void InMemoryTabRestoreService::RestoreEntryById( |
| 175 TabRestoreServiceDelegate* delegate, |
| 176 SessionID::id_type id, |
| 177 WindowOpenDisposition disposition) { |
| 178 Entries::iterator entry_iterator = GetEntryIteratorById(id); |
| 179 if (entry_iterator == entries_.end()) |
| 180 // Don't hoark here, we allow an invalid id. |
| 181 return; |
| 182 |
| 183 OnRestoreEntryById(id, entry_iterator); |
| 184 restoring_ = true; |
| 185 Entry* entry = *entry_iterator; |
| 186 |
| 187 // If the entry's ID does not match the ID that is being restored, then the |
| 188 // entry is a window from which a single tab will be restored. |
| 189 bool restoring_tab_in_window = entry->id != id; |
| 190 |
| 191 if (!restoring_tab_in_window) { |
| 192 entries_.erase(entry_iterator); |
| 193 entry_iterator = entries_.end(); |
| 194 } |
| 195 |
| 196 // |delegate| will be NULL in cases where one isn't already available (eg, |
| 197 // when invoked on Mac OS X with no windows open). In this case, create a |
| 198 // new browser into which we restore the tabs. |
| 199 if (entry->type == TAB) { |
| 200 Tab* tab = static_cast<Tab*>(entry); |
| 201 delegate = RestoreTab(*tab, delegate, disposition); |
| 202 delegate->ShowBrowserWindow(); |
| 203 } else if (entry->type == WINDOW) { |
| 204 TabRestoreServiceDelegate* current_delegate = delegate; |
| 205 Window* window = static_cast<Window*>(entry); |
| 206 |
| 207 // When restoring a window, either the entire window can be restored, or a |
| 208 // single tab within it. If the entry's ID matches the one to restore, then |
| 209 // the entire window will be restored. |
| 210 if (!restoring_tab_in_window) { |
| 211 delegate = TabRestoreServiceDelegate::Create(profile_, window->app_name); |
| 212 for (size_t tab_i = 0; tab_i < window->tabs.size(); ++tab_i) { |
| 213 const Tab& tab = window->tabs[tab_i]; |
| 214 WebContents* restored_tab = |
| 215 delegate->AddRestoredTab(tab.navigations, delegate->GetTabCount(), |
| 216 tab.current_navigation_index, |
| 217 tab.extension_app_id, |
| 218 static_cast<int>(tab_i) == |
| 219 window->selected_tab_index, |
| 220 tab.pinned, tab.from_last_session, |
| 221 tab.session_storage_namespace, |
| 222 tab.user_agent_override); |
| 223 if (restored_tab) { |
| 224 restored_tab->GetController().LoadIfNecessary(); |
| 225 RecordAppLaunch(profile_, tab); |
| 226 } |
| 227 } |
| 228 // All the window's tabs had the same former browser_id. |
| 229 if (window->tabs[0].has_browser()) { |
| 230 UpdateTabBrowserIDs(window->tabs[0].browser_id, |
| 231 delegate->GetSessionID().id()); |
| 232 } |
| 233 } else { |
| 234 // Restore a single tab from the window. Find the tab that matches the ID |
| 235 // in the window and restore it. |
| 236 for (std::vector<Tab>::iterator tab_i = window->tabs.begin(); |
| 237 tab_i != window->tabs.end(); ++tab_i) { |
| 238 const Tab& tab = *tab_i; |
| 239 if (tab.id == id) { |
| 240 delegate = RestoreTab(tab, delegate, disposition); |
| 241 window->tabs.erase(tab_i); |
| 242 // If restoring the tab leaves the window with nothing else, delete it |
| 243 // as well. |
| 244 if (!window->tabs.size()) { |
| 245 entries_.erase(entry_iterator); |
| 246 delete entry; |
| 247 } else { |
| 248 // Update the browser ID of the rest of the tabs in the window so if |
| 249 // any one is restored, it goes into the same window as the tab |
| 250 // being restored now. |
| 251 UpdateTabBrowserIDs(tab.browser_id, |
| 252 delegate->GetSessionID().id()); |
| 253 for (std::vector<Tab>::iterator tab_j = window->tabs.begin(); |
| 254 tab_j != window->tabs.end(); ++tab_j) { |
| 255 (*tab_j).browser_id = delegate->GetSessionID().id(); |
| 256 } |
| 257 } |
| 258 break; |
| 259 } |
| 260 } |
| 261 } |
| 262 delegate->ShowBrowserWindow(); |
| 263 |
| 264 if (disposition == CURRENT_TAB && current_delegate && |
| 265 current_delegate->GetActiveWebContents()) { |
| 266 current_delegate->CloseTab(); |
| 267 } |
| 268 } else { |
| 269 NOTREACHED(); |
| 270 } |
| 271 |
| 272 if (!restoring_tab_in_window) { |
| 273 delete entry; |
| 274 } |
| 275 |
| 276 restoring_ = false; |
| 277 NotifyTabsChanged(); |
| 278 } |
| 279 |
| 280 void InMemoryTabRestoreService::LoadTabsFromLastSession() { |
| 281 NOTIMPLEMENTED(); |
| 282 } |
| 283 |
| 284 bool InMemoryTabRestoreService::IsLoaded() const { |
| 285 NOTIMPLEMENTED(); |
| 286 return false; |
| 287 } |
| 288 |
| 289 void InMemoryTabRestoreService::Shutdown() { |
| 290 NOTIMPLEMENTED(); |
| 291 } |
| 292 |
| 293 void InMemoryTabRestoreService::PopulateTab( |
| 294 Tab* tab, |
| 295 int index, |
| 296 TabRestoreServiceDelegate* delegate, |
| 297 NavigationController* controller) { |
| 298 const int pending_index = controller->GetPendingEntryIndex(); |
| 299 int entry_count = controller->GetEntryCount(); |
| 300 if (entry_count == 0 && pending_index == 0) |
| 301 entry_count++; |
| 302 tab->navigations.resize(static_cast<int>(entry_count)); |
| 303 for (int i = 0; i < entry_count; ++i) { |
| 304 NavigationEntry* entry = (i == pending_index) ? |
| 305 controller->GetPendingEntry() : controller->GetEntryAtIndex(i); |
| 306 tab->navigations[i] = |
| 307 TabNavigation::FromNavigationEntry(i, *entry); |
| 308 } |
| 309 tab->timestamp = TimeNow(); |
| 310 tab->current_navigation_index = controller->GetCurrentEntryIndex(); |
| 311 if (tab->current_navigation_index == -1 && entry_count > 0) |
| 312 tab->current_navigation_index = 0; |
| 313 tab->tabstrip_index = index; |
| 314 |
| 315 TabContents* tab_contents = |
| 316 TabContents::FromWebContents(controller->GetWebContents()); |
| 317 // tab_contents is NULL in some browser tests. |
| 318 if (tab_contents) { |
| 319 const extensions::Extension* extension = |
| 320 extensions::TabHelper::FromWebContents(controller->GetWebContents())-> |
| 321 extension_app(); |
| 322 if (extension) |
| 323 tab->extension_app_id = extension->id(); |
| 324 } |
| 325 |
| 326 tab->user_agent_override = |
| 327 controller->GetWebContents()->GetUserAgentOverride(); |
| 328 |
| 329 // TODO(ajwong): This does not correctly handle storage for isolated apps. |
| 330 tab->session_storage_namespace = |
| 331 controller->GetDefaultSessionStorageNamespace(); |
| 332 |
| 333 // Delegate may be NULL during unit tests. |
| 334 if (delegate) { |
| 335 tab->browser_id = delegate->GetSessionID().id(); |
| 336 tab->pinned = delegate->IsTabPinned(tab->tabstrip_index); |
| 337 } |
| 338 } |
| 339 |
| 340 void InMemoryTabRestoreService::AddEntry(Entry* entry, |
| 341 bool notify, |
| 342 bool to_front) { |
| 343 if (!FilterEntry(entry) || (entries_.size() >= kMaxEntries && !to_front)) { |
| 344 delete entry; |
| 345 return; |
| 346 } |
| 347 |
| 348 if (to_front) |
| 349 entries_.push_front(entry); |
| 350 else |
| 351 entries_.push_back(entry); |
| 352 |
| 353 PruneEntries(); |
| 354 |
| 355 if (notify) |
| 356 NotifyTabsChanged(); |
| 357 |
| 358 OnAddEntry(); |
| 359 } |
| 360 |
| 361 void InMemoryTabRestoreService::PruneEntries() { |
| 362 Entries new_entries; |
| 363 |
| 364 for (TabRestoreService::Entries::const_iterator iter = entries_.begin(); |
| 365 iter != entries_.end(); ++iter) { |
| 366 TabRestoreService::Entry* entry = *iter; |
| 367 |
| 368 if (FilterEntry(entry) && |
| 369 new_entries.size() < kMaxEntries) { |
| 370 new_entries.push_back(entry); |
| 371 } else { |
| 372 delete entry; |
| 373 } |
| 374 } |
| 375 |
| 376 entries_ = new_entries; |
| 377 } |
| 378 |
| 379 void InMemoryTabRestoreService::NotifyTabsChanged() { |
| 380 FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_, |
| 381 TabRestoreServiceChanged(this)); |
| 382 } |
| 383 |
| 384 TabRestoreService::Entries::iterator |
| 385 InMemoryTabRestoreService::GetEntryIteratorById(SessionID::id_type id) { |
| 386 for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) { |
| 387 if ((*i)->id == id) |
| 388 return i; |
| 389 |
| 390 // For Window entries, see if the ID matches a tab. If so, report the window |
| 391 // as the Entry. |
| 392 if ((*i)->type == WINDOW) { |
| 393 std::vector<Tab>& tabs = static_cast<Window*>(*i)->tabs; |
| 394 for (std::vector<Tab>::iterator j = tabs.begin(); |
| 395 j != tabs.end(); ++j) { |
| 396 if ((*j).id == id) { |
| 397 return i; |
| 398 } |
| 399 } |
| 400 } |
| 401 } |
| 402 return entries_.end(); |
| 403 } |
| 404 |
| 405 bool InMemoryTabRestoreService::ConvertSessionWindowToWindow( |
| 406 SessionWindow* session_window, |
| 407 Window* window) { |
| 408 for (size_t i = 0; i < session_window->tabs.size(); ++i) { |
| 409 if (!session_window->tabs[i]->navigations.empty()) { |
| 410 window->tabs.resize(window->tabs.size() + 1); |
| 411 Tab& tab = window->tabs.back(); |
| 412 tab.pinned = session_window->tabs[i]->pinned; |
| 413 tab.navigations.swap(session_window->tabs[i]->navigations); |
| 414 tab.current_navigation_index = |
| 415 session_window->tabs[i]->current_navigation_index; |
| 416 tab.extension_app_id = session_window->tabs[i]->extension_app_id; |
| 417 tab.timestamp = base::Time(); |
| 418 } |
| 419 } |
| 420 if (window->tabs.empty()) |
| 421 return false; |
| 422 |
| 423 window->selected_tab_index = |
| 424 std::min(session_window->selected_tab_index, |
| 425 static_cast<int>(window->tabs.size() - 1)); |
| 426 window->timestamp = base::Time(); |
| 427 return true; |
| 428 } |
| 429 |
| 430 // static |
| 431 bool InMemoryTabRestoreService::ValidateEntry(Entry* entry) { |
| 432 if (entry->type == TAB) |
| 433 return ValidateTab(static_cast<Tab*>(entry)); |
| 434 |
| 435 if (entry->type == WINDOW) |
| 436 return ValidateWindow(static_cast<Window*>(entry)); |
| 437 |
| 438 NOTREACHED(); |
| 439 return false; |
| 440 } |
| 441 |
| 442 TabRestoreServiceDelegate* InMemoryTabRestoreService::RestoreTab( |
| 443 const Tab& tab, |
| 444 TabRestoreServiceDelegate* delegate, |
| 445 WindowOpenDisposition disposition) { |
| 446 if (disposition == CURRENT_TAB && delegate) { |
| 447 delegate->ReplaceRestoredTab(tab.navigations, |
| 448 tab.current_navigation_index, |
| 449 tab.from_last_session, |
| 450 tab.extension_app_id, |
| 451 tab.session_storage_namespace, |
| 452 tab.user_agent_override); |
| 453 } else { |
| 454 // We only respsect the tab's original browser if there's no disposition. |
| 455 if (disposition == UNKNOWN && tab.has_browser()) |
| 456 delegate = TabRestoreServiceDelegate::FindDelegateWithID(tab.browser_id); |
| 457 |
| 458 int tab_index = -1; |
| 459 |
| 460 // |delegate| will be NULL in cases where one isn't already available (eg, |
| 461 // when invoked on Mac OS X with no windows open). In this case, create a |
| 462 // new browser into which we restore the tabs. |
| 463 if (delegate && disposition != NEW_WINDOW) { |
| 464 tab_index = tab.tabstrip_index; |
| 465 } else { |
| 466 delegate = TabRestoreServiceDelegate::Create(profile_, std::string()); |
| 467 if (tab.has_browser()) |
| 468 UpdateTabBrowserIDs(tab.browser_id, delegate->GetSessionID().id()); |
| 469 } |
| 470 |
| 471 // Place the tab at the end if the tab index is no longer valid or |
| 472 // we were passed a specific disposition. |
| 473 if (tab_index < 0 || tab_index > delegate->GetTabCount() || |
| 474 disposition != UNKNOWN) { |
| 475 tab_index = delegate->GetTabCount(); |
| 476 } |
| 477 |
| 478 WebContents* web_contents = delegate->AddRestoredTab( |
| 479 tab.navigations, |
| 480 tab_index, |
| 481 tab.current_navigation_index, |
| 482 tab.extension_app_id, |
| 483 disposition != NEW_BACKGROUND_TAB, |
| 484 tab.pinned, |
| 485 tab.from_last_session, |
| 486 tab.session_storage_namespace, |
| 487 tab.user_agent_override); |
| 488 web_contents->GetController().LoadIfNecessary(); |
| 489 } |
| 490 RecordAppLaunch(profile_, tab); |
| 491 return delegate; |
| 492 } |
| 493 |
| 494 |
| 495 bool InMemoryTabRestoreService::ValidateTab(Tab* tab) { |
| 496 if (tab->navigations.empty()) |
| 497 return false; |
| 498 |
| 499 tab->current_navigation_index = |
| 500 std::max(0, std::min(tab->current_navigation_index, |
| 501 static_cast<int>(tab->navigations.size()) - 1)); |
| 502 |
| 503 return true; |
| 504 } |
| 505 |
| 506 bool InMemoryTabRestoreService::ValidateWindow(Window* window) { |
| 507 window->selected_tab_index = |
| 508 std::max(0, std::min(window->selected_tab_index, |
| 509 static_cast<int>(window->tabs.size() - 1))); |
| 510 |
| 511 int i = 0; |
| 512 for (std::vector<Tab>::iterator tab_i = window->tabs.begin(); |
| 513 tab_i != window->tabs.end();) { |
| 514 if (!ValidateTab(&(*tab_i))) { |
| 515 tab_i = window->tabs.erase(tab_i); |
| 516 if (i < window->selected_tab_index) |
| 517 window->selected_tab_index--; |
| 518 else if (i == window->selected_tab_index) |
| 519 window->selected_tab_index = 0; |
| 520 } else { |
| 521 ++tab_i; |
| 522 ++i; |
| 523 } |
| 524 } |
| 525 |
| 526 if (window->tabs.empty()) |
| 527 return false; |
| 528 |
| 529 return true; |
| 530 } |
| 531 |
| 532 bool InMemoryTabRestoreService::IsTabInteresting(const Tab* tab) { |
| 533 if (tab->navigations.empty()) |
| 534 return false; |
| 535 |
| 536 if (tab->navigations.size() > 1) |
| 537 return true; |
| 538 |
| 539 return tab->pinned || |
| 540 tab->navigations.at(0).virtual_url() != |
| 541 GURL(chrome::kChromeUINewTabURL); |
| 542 } |
| 543 |
| 544 bool InMemoryTabRestoreService::IsWindowInteresting(const Window* window) { |
| 545 if (window->tabs.empty()) |
| 546 return false; |
| 547 |
| 548 if (window->tabs.size() > 1) |
| 549 return true; |
| 550 |
| 551 return IsTabInteresting(&window->tabs[0]); |
| 552 } |
| 553 |
| 554 bool InMemoryTabRestoreService::FilterEntry(Entry* entry) { |
| 555 if (!ValidateEntry(entry)) |
| 556 return false; |
| 557 |
| 558 if (entry->type == TAB) |
| 559 return IsTabInteresting(static_cast<Tab*>(entry)); |
| 560 else if (entry->type == WINDOW) |
| 561 return IsWindowInteresting(static_cast<Window*>(entry)); |
| 562 |
| 563 NOTREACHED(); |
| 564 return false; |
| 565 } |
| 566 |
| 567 void InMemoryTabRestoreService::UpdateTabBrowserIDs(SessionID::id_type old_id, |
| 568 SessionID::id_type new_id) { |
| 569 for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) { |
| 570 Entry* entry = *i; |
| 571 if (entry->type == TAB) { |
| 572 Tab* tab = static_cast<Tab*>(entry); |
| 573 if (tab->browser_id == old_id) |
| 574 tab->browser_id = new_id; |
| 575 } |
| 576 } |
| 577 } |
| 578 |
| 579 void InMemoryTabRestoreService::DeleteLastSession() { |
| 580 NOTIMPLEMENTED(); |
| 581 } |
| 582 |
| 583 base::Time InMemoryTabRestoreService::TimeNow() const { |
| 584 return time_factory_ ? time_factory_->TimeNow() : base::Time::Now(); |
| 585 } |
| OLD | NEW |