Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(149)

Side by Side Diff: ios/chrome/browser/tabs/tab_model.mm

Issue 2703333006: Move the notion of current Tab from TabModel to WebStateList. (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import "ios/chrome/browser/tabs/tab_model.h" 5 #import "ios/chrome/browser/tabs/tab_model.h"
6 6
7 #include <cstdint> 7 #include <cstdint>
8 #include <utility> 8 #include <utility>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #import "base/mac/scoped_nsobject.h" 13 #import "base/mac/scoped_nsobject.h"
14 #include "base/metrics/histogram_macros.h" 14 #include "base/metrics/histogram_macros.h"
15 #include "base/metrics/user_metrics.h" 15 #include "base/metrics/user_metrics.h"
16 #include "base/metrics/user_metrics_action.h" 16 #include "base/metrics/user_metrics_action.h"
17 #include "base/strings/sys_string_conversions.h" 17 #include "base/strings/sys_string_conversions.h"
18 #include "base/task/cancelable_task_tracker.h" 18 #include "base/task/cancelable_task_tracker.h"
19 #include "components/sessions/core/serialized_navigation_entry.h" 19 #include "components/sessions/core/serialized_navigation_entry.h"
20 #include "components/sessions/core/session_id.h" 20 #include "components/sessions/core/session_id.h"
21 #include "components/sessions/core/tab_restore_service.h" 21 #include "components/sessions/core/tab_restore_service.h"
22 #include "components/sessions/ios/ios_live_tab.h" 22 #include "components/sessions/ios/ios_live_tab.h"
23 #include "ios/chrome/browser/browser_state/chrome_browser_state.h" 23 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
24 #include "ios/chrome/browser/chrome_url_constants.h" 24 #include "ios/chrome/browser/chrome_url_constants.h"
25 #import "ios/chrome/browser/chrome_url_util.h" 25 #import "ios/chrome/browser/chrome_url_util.h"
26 #import "ios/chrome/browser/metrics/tab_usage_recorder.h" 26 #import "ios/chrome/browser/metrics/tab_usage_recorder.h"
27 #import "ios/chrome/browser/metrics/tab_usage_recorder_web_state_list_observer.h "
27 #include "ios/chrome/browser/sessions/ios_chrome_tab_restore_service_factory.h" 28 #include "ios/chrome/browser/sessions/ios_chrome_tab_restore_service_factory.h"
28 #import "ios/chrome/browser/sessions/session_service.h" 29 #import "ios/chrome/browser/sessions/session_service.h"
29 #import "ios/chrome/browser/sessions/session_window.h" 30 #import "ios/chrome/browser/sessions/session_window.h"
30 #import "ios/chrome/browser/snapshots/snapshot_cache.h" 31 #import "ios/chrome/browser/snapshots/snapshot_cache.h"
32 #import "ios/chrome/browser/snapshots/snapshot_cache_web_state_list_observer.h"
31 #include "ios/chrome/browser/tab_parenting_global_observer.h" 33 #include "ios/chrome/browser/tab_parenting_global_observer.h"
32 #import "ios/chrome/browser/tabs/legacy_tab_helper.h" 34 #import "ios/chrome/browser/tabs/legacy_tab_helper.h"
33 #import "ios/chrome/browser/tabs/tab.h" 35 #import "ios/chrome/browser/tabs/tab.h"
34 #import "ios/chrome/browser/tabs/tab_model_list.h" 36 #import "ios/chrome/browser/tabs/tab_model_list.h"
35 #import "ios/chrome/browser/tabs/tab_model_observers.h" 37 #import "ios/chrome/browser/tabs/tab_model_observers.h"
36 #import "ios/chrome/browser/tabs/tab_model_observers_bridge.h" 38 #import "ios/chrome/browser/tabs/tab_model_observers_bridge.h"
37 #import "ios/chrome/browser/tabs/tab_model_order_controller.h" 39 #import "ios/chrome/browser/tabs/tab_model_selected_tab_observer.h"
38 #import "ios/chrome/browser/tabs/tab_model_synced_window_delegate.h" 40 #import "ios/chrome/browser/tabs/tab_model_synced_window_delegate.h"
39 #import "ios/chrome/browser/tabs/tab_parenting_observer.h" 41 #import "ios/chrome/browser/tabs/tab_parenting_observer.h"
40 #import "ios/chrome/browser/xcallback_parameters.h" 42 #import "ios/chrome/browser/xcallback_parameters.h"
41 #import "ios/shared/chrome/browser/tabs/web_state_list.h" 43 #import "ios/shared/chrome/browser/tabs/web_state_list.h"
42 #import "ios/shared/chrome/browser/tabs/web_state_list_fast_enumeration_helper.h " 44 #import "ios/shared/chrome/browser/tabs/web_state_list_fast_enumeration_helper.h "
43 #import "ios/shared/chrome/browser/tabs/web_state_list_metrics_observer.h" 45 #import "ios/shared/chrome/browser/tabs/web_state_list_metrics_observer.h"
44 #import "ios/shared/chrome/browser/tabs/web_state_list_observer.h" 46 #import "ios/shared/chrome/browser/tabs/web_state_list_observer.h"
45 #import "ios/web/navigation/crw_session_certificate_policy_manager.h" 47 #import "ios/web/navigation/crw_session_certificate_policy_manager.h"
46 #import "ios/web/navigation/crw_session_controller.h" 48 #import "ios/web/navigation/crw_session_controller.h"
47 #include "ios/web/public/browser_state.h" 49 #include "ios/web/public/browser_state.h"
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 159
158 // Used to keep the Tabs alive while the corresponding WebStates are stored 160 // Used to keep the Tabs alive while the corresponding WebStates are stored
159 // in the WebStateList (as Tabs currently own their WebState). Remove once 161 // in the WebStateList (as Tabs currently own their WebState). Remove once
160 // WebState owns the associated Tab. 162 // WebState owns the associated Tab.
161 base::scoped_nsobject<NSMutableSet<Tab*>> _tabRetainer; 163 base::scoped_nsobject<NSMutableSet<Tab*>> _tabRetainer;
162 164
163 // WebStateListObserver bridges to react to modifications of the model (may 165 // WebStateListObserver bridges to react to modifications of the model (may
164 // send notification, translate and forward events, update metrics, ...). 166 // send notification, translate and forward events, update metrics, ...).
165 std::vector<std::unique_ptr<WebStateListObserver>> _observerBridges; 167 std::vector<std::unique_ptr<WebStateListObserver>> _observerBridges;
166 168
167 // Maintains policy for where new tabs go and the selection when a tab
168 // is removed.
169 base::scoped_nsobject<TabModelOrderController> _orderController;
170 // The delegate for sync. 169 // The delegate for sync.
171 std::unique_ptr<TabModelSyncedWindowDelegate> _syncedWindowDelegate; 170 std::unique_ptr<TabModelSyncedWindowDelegate> _syncedWindowDelegate;
172 // Currently selected tab. May be nil.
173 base::WeakNSObject<Tab> _currentTab;
174 171
175 // Counters for metrics. 172 // Counters for metrics.
176 int _openedTabCount; 173 WebStateListMetricsObserver* _webStateListMetricsObserver;
177 int _closedTabCount;
178 int _newTabCount;
179 174
180 // Backs up property with the same name. 175 // Backs up property with the same name.
181 std::unique_ptr<TabUsageRecorder> _tabUsageRecorder; 176 std::unique_ptr<TabUsageRecorder> _tabUsageRecorder;
182 // Backs up property with the same name. 177 // Backs up property with the same name.
183 const SessionID _sessionID; 178 const SessionID _sessionID;
184 // Saves session's state. 179 // Saves session's state.
185 base::scoped_nsobject<SessionServiceIOS> _sessionService; 180 base::scoped_nsobject<SessionServiceIOS> _sessionService;
186 // List of TabModelObservers. 181 // List of TabModelObservers.
187 base::scoped_nsobject<TabModelObservers> _observers; 182 base::scoped_nsobject<TabModelObservers> _observers;
188 183
(...skipping 16 matching lines...) Expand all
205 // TabModelConstants::kTabPositionAutomatically if the caller doesn't have a 200 // TabModelConstants::kTabPositionAutomatically if the caller doesn't have a
206 // preference for the position of the tab. 201 // preference for the position of the tab.
207 - (Tab*)insertTabWithLoadParams: 202 - (Tab*)insertTabWithLoadParams:
208 (const web::NavigationManager::WebLoadParams&)params 203 (const web::NavigationManager::WebLoadParams&)params
209 windowName:(NSString*)windowName 204 windowName:(NSString*)windowName
210 opener:(Tab*)parentTab 205 opener:(Tab*)parentTab
211 openedByDOM:(BOOL)openedByDOM 206 openedByDOM:(BOOL)openedByDOM
212 atIndex:(NSUInteger)index 207 atIndex:(NSUInteger)index
213 inBackground:(BOOL)inBackground; 208 inBackground:(BOOL)inBackground;
214 209
215 // Call to switch the selected tab. Broadcasts about the change in selection.
216 // It's ok for |newTab| to be nil in case the last tab is going away. In that
217 // case, the "tab deselected" notification gets sent, but no corresponding
218 // "tab selected" notification is sent. |persist| indicates whether or not
219 // the tab's state should be persisted in history upon switching.
220 - (void)changeSelectedTabFrom:(Tab*)oldTab
221 to:(Tab*)newTab
222 persistState:(BOOL)persist;
223
224 // Tells the snapshot cache the adjacent tab session ids.
225 - (void)updateSnapshotCache:(Tab*)tab;
226
227 // Helper method that posts a notification with the given name with |tab| 210 // Helper method that posts a notification with the given name with |tab|
228 // in the userInfo dictionary under the kTabModelTabKey. 211 // in the userInfo dictionary under the kTabModelTabKey.
229 - (void)postNotificationName:(NSString*)notificationName withTab:(Tab*)tab; 212 - (void)postNotificationName:(NSString*)notificationName withTab:(Tab*)tab;
230 213
231 // Helper method to restore a saved session and control if the state should 214 // Helper method to restore a saved session and control if the state should
232 // be persisted or not. Used to implement the public -restoreSessionWindow: 215 // be persisted or not. Used to implement the public -restoreSessionWindow:
233 // method and restoring session in the initialiser. 216 // method and restoring session in the initialiser.
234 - (BOOL)restoreSessionWindow:(SessionWindowIOS*)window 217 - (BOOL)restoreSessionWindow:(SessionWindowIOS*)window
235 persistState:(BOOL)persistState; 218 persistState:(BOOL)persistState;
236 219
(...skipping 22 matching lines...) Expand all
259 242
260 #pragma mark - Overriden 243 #pragma mark - Overriden
261 244
262 - (void)dealloc { 245 - (void)dealloc {
263 DCHECK([_observers empty]); 246 DCHECK([_observers empty]);
264 // browserStateDestroyed should always have been called before destruction. 247 // browserStateDestroyed should always have been called before destruction.
265 DCHECK(!_browserState); 248 DCHECK(!_browserState);
266 249
267 [[NSNotificationCenter defaultCenter] removeObserver:self]; 250 [[NSNotificationCenter defaultCenter] removeObserver:self];
268 251
252 // Clear weak pointer to WebStateListMetricsObserver before destroying it.
253 _webStateListMetricsObserver = nullptr;
254
269 // Unregister all listeners before closing all the tabs. 255 // Unregister all listeners before closing all the tabs.
270 for (const auto& observerBridge : _observerBridges) 256 for (const auto& observerBridge : _observerBridges)
271 _webStateList.RemoveObserver(observerBridge.get()); 257 _webStateList.RemoveObserver(observerBridge.get());
272 _observerBridges.clear(); 258 _observerBridges.clear();
273 259
274 // Make sure the tabs do clean after themselves. It is important for 260 // Make sure the tabs do clean after themselves. It is important for
275 // removeObserver: to be called first otherwise a lot of unecessary work will 261 // removeObserver: to be called first otherwise a lot of unecessary work will
276 // happen on -closeAllTabs. 262 // happen on -closeAllTabs.
277 [self closeAllTabs]; 263 [self closeAllTabs];
278 264
279 _clearPoliciesTaskTracker.TryCancelAll(); 265 _clearPoliciesTaskTracker.TryCancelAll();
280 266
281 [super dealloc]; 267 [super dealloc];
282 } 268 }
283 269
284 #pragma mark - Public methods 270 #pragma mark - Public methods
285 271
286 - (Tab*)currentTab { 272 - (Tab*)currentTab {
287 return _currentTab.get(); 273 web::WebState* webState = _webStateList.GetActiveWebState();
274 return webState ? LegacyTabHelper::GetTabForWebState(webState) : nil;
288 } 275 }
289 276
290 - (void)setCurrentTab:(Tab*)newTab { 277 - (void)setCurrentTab:(Tab*)newTab {
291 DCHECK_NE([self indexOfTab:newTab], static_cast<NSUInteger>(NSNotFound)); 278 int indexOfTab = _webStateList.GetIndexOfWebState(newTab.webState);
292 if (_currentTab != newTab) { 279 DCHECK_NE(indexOfTab, WebStateList::kInvalidIndex);
293 base::RecordAction(base::UserMetricsAction("MobileTabSwitched")); 280 _webStateList.ActivateWebStateAt(indexOfTab);
294 [self updateSnapshotCache:newTab];
295 }
296 if (_tabUsageRecorder) {
297 _tabUsageRecorder->RecordTabSwitched(_currentTab, newTab);
298 }
299 [self changeSelectedTabFrom:_currentTab to:newTab persistState:YES];
300 } 281 }
301 282
302 - (TabModelSyncedWindowDelegate*)syncedWindowDelegate { 283 - (TabModelSyncedWindowDelegate*)syncedWindowDelegate {
303 return _syncedWindowDelegate.get(); 284 return _syncedWindowDelegate.get();
304 } 285 }
305 286
306 - (TabUsageRecorder*)tabUsageRecorder { 287 - (TabUsageRecorder*)tabUsageRecorder {
307 return _tabUsageRecorder.get(); 288 return _tabUsageRecorder.get();
308 } 289 }
309 290
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 // Set up the usage recorder before tabs are created. 322 // Set up the usage recorder before tabs are created.
342 _tabUsageRecorder = base::MakeUnique<TabUsageRecorder>(self); 323 _tabUsageRecorder = base::MakeUnique<TabUsageRecorder>(self);
343 } 324 }
344 _syncedWindowDelegate = 325 _syncedWindowDelegate =
345 base::MakeUnique<TabModelSyncedWindowDelegate>(self); 326 base::MakeUnique<TabModelSyncedWindowDelegate>(self);
346 327
347 // There must be a valid session service defined to consume session windows. 328 // There must be a valid session service defined to consume session windows.
348 DCHECK(service); 329 DCHECK(service);
349 _sessionService.reset([service retain]); 330 _sessionService.reset([service retain]);
350 331
332 _observerBridges.push_back(
333 base::MakeUnique<SnapshotCacheWebStateListObserver>(
334 [SnapshotCache sharedInstance]));
335 if (_tabUsageRecorder) {
336 _observerBridges.push_back(
337 base::MakeUnique<TabUsageRecorderWebStateListObserver>(
338 _tabUsageRecorder.get()));
339 }
351 _observerBridges.push_back(base::MakeUnique<TabParentingObserver>()); 340 _observerBridges.push_back(base::MakeUnique<TabParentingObserver>());
352 _observerBridges.push_back(base::MakeUnique<WebStateListObserverBridge>( 341 _observerBridges.push_back(base::MakeUnique<WebStateListObserverBridge>(
342 [[TabModelSelectedTabObserver alloc] initWithTabModel:self]));
343 _observerBridges.push_back(base::MakeUnique<WebStateListObserverBridge>(
353 [[TabModelObserversBridge alloc] initWithTabModel:self 344 [[TabModelObserversBridge alloc] initWithTabModel:self
354 tabModelObservers:_observers.get()])); 345 tabModelObservers:_observers.get()]));
355 _observerBridges.push_back(base::MakeUnique<WebStateListMetricsObserver>()); 346
347 auto webStateListMetricsObserver =
348 base::MakeUnique<WebStateListMetricsObserver>();
349 _webStateListMetricsObserver = webStateListMetricsObserver.get();
350 _observerBridges.push_back(std::move(webStateListMetricsObserver));
356 351
357 for (const auto& observerBridge : _observerBridges) 352 for (const auto& observerBridge : _observerBridges)
358 _webStateList.AddObserver(observerBridge.get()); 353 _webStateList.AddObserver(observerBridge.get());
359 354
360 if (window) { 355 if (window) {
361 DCHECK([_observers empty]); 356 DCHECK([_observers empty]);
362 // Restore the session and reset the session metrics (as the event have 357 // Restore the session and reset the session metrics (as the event have
363 // not been generated by the user but by a cold start cycle). 358 // not been generated by the user but by a cold start cycle).
364 [self restoreSessionWindow:window persistState:NO]; 359 [self restoreSessionWindow:window persistState:NO];
365 [self resetSessionMetrics]; 360 [self resetSessionMetrics];
366 } 361 }
367 362
368 _orderController.reset(
369 [[TabModelOrderController alloc] initWithTabModel:self]);
370
371 // Register for resign active notification. 363 // Register for resign active notification.
372 [[NSNotificationCenter defaultCenter] 364 [[NSNotificationCenter defaultCenter]
373 addObserver:self 365 addObserver:self
374 selector:@selector(willResignActive:) 366 selector:@selector(willResignActive:)
375 name:UIApplicationWillResignActiveNotification 367 name:UIApplicationWillResignActiveNotification
376 object:nil]; 368 object:nil];
377 // Register for background notification. 369 // Register for background notification.
378 [[NSNotificationCenter defaultCenter] 370 [[NSNotificationCenter defaultCenter]
379 addObserver:self 371 addObserver:self
380 selector:@selector(applicationDidEnterBackground:) 372 selector:@selector(applicationDidEnterBackground:)
(...skipping 17 matching lines...) Expand all
398 return nil; 390 return nil;
399 } 391 }
400 392
401 - (BOOL)restoreSessionWindow:(SessionWindowIOS*)window { 393 - (BOOL)restoreSessionWindow:(SessionWindowIOS*)window {
402 return [self restoreSessionWindow:window persistState:YES]; 394 return [self restoreSessionWindow:window persistState:YES];
403 } 395 }
404 396
405 - (void)saveSessionImmediately:(BOOL)immediately { 397 - (void)saveSessionImmediately:(BOOL)immediately {
406 // Do nothing if there are tabs in the model but no selected tab. This is 398 // Do nothing if there are tabs in the model but no selected tab. This is
407 // a transitional state. 399 // a transitional state.
408 if ((!_currentTab && _webStateList.count()) || !_browserState) 400 if ((!self.currentTab && _webStateList.count()) || !_browserState)
409 return; 401 return;
410 [_sessionService saveWindow:self.windowForSavingSession 402 [_sessionService saveWindow:self.windowForSavingSession
411 forBrowserState:_browserState 403 forBrowserState:_browserState
412 immediately:immediately]; 404 immediately:immediately];
413 } 405 }
414 406
415 - (Tab*)tabAtIndex:(NSUInteger)index { 407 - (Tab*)tabAtIndex:(NSUInteger)index {
416 DCHECK_LE(index, static_cast<NSUInteger>(INT_MAX)); 408 DCHECK_LE(index, static_cast<NSUInteger>(INT_MAX));
417 return LegacyTabHelper::GetTabForWebState( 409 return LegacyTabHelper::GetTabForWebState(
418 _webStateList.GetWebStateAt(static_cast<int>(index))); 410 _webStateList.GetWebStateAt(static_cast<int>(index)));
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
577 const int insertion_index = static_cast<int>(index); 569 const int insertion_index = static_cast<int>(index);
578 _webStateList.InsertWebState(insertion_index, tab.webState, 570 _webStateList.InsertWebState(insertion_index, tab.webState,
579 parentTab.webState); 571 parentTab.webState);
580 } 572 }
581 573
582 // Persist the session due to a new tab being inserted. If this is a 574 // Persist the session due to a new tab being inserted. If this is a
583 // background tab (will not become active), saving now will capture the 575 // background tab (will not become active), saving now will capture the
584 // state properly. If it does eventually become active, another save will 576 // state properly. If it does eventually become active, another save will
585 // be triggered to properly capture the end result. 577 // be triggered to properly capture the end result.
586 [self saveSessionImmediately:NO]; 578 [self saveSessionImmediately:NO];
587
588 ++_newTabCount;
589 } 579 }
590 580
591 - (void)insertTab:(Tab*)tab atIndex:(NSUInteger)index opener:(Tab*)parentTab { 581 - (void)insertTab:(Tab*)tab atIndex:(NSUInteger)index opener:(Tab*)parentTab {
592 DCHECK(tab); 582 DCHECK(tab);
593 DCHECK(![_tabRetainer containsObject:tab]); 583 DCHECK(![_tabRetainer containsObject:tab]);
594 DCHECK_LE(index, static_cast<NSUInteger>(INT_MAX)); 584 DCHECK_LE(index, static_cast<NSUInteger>(INT_MAX));
595 585
596 [self insertTab:tab 586 [self insertTab:tab
597 atIndex:index 587 atIndex:index
598 opener:parentTab 588 opener:parentTab
(...skipping 24 matching lines...) Expand all
623 DCHECK_GE(index, 0); 613 DCHECK_GE(index, 0);
624 614
625 base::scoped_nsobject<Tab> tabSaver([oldTab retain]); 615 base::scoped_nsobject<Tab> tabSaver([oldTab retain]);
626 [_tabRetainer removeObject:oldTab]; 616 [_tabRetainer removeObject:oldTab];
627 [_tabRetainer addObject:newTab]; 617 [_tabRetainer addObject:newTab];
628 [newTab setParentTabModel:self]; 618 [newTab setParentTabModel:self];
629 619
630 _webStateList.ReplaceWebStateAt(index, newTab.webState, 620 _webStateList.ReplaceWebStateAt(index, newTab.webState,
631 GetOpenerForTab(self, newTab).webState); 621 GetOpenerForTab(self, newTab).webState);
632 622
633 if (self.currentTab == oldTab)
634 [self changeSelectedTabFrom:nil to:newTab persistState:NO];
635
636 [oldTab setParentTabModel:nil]; 623 [oldTab setParentTabModel:nil];
637 [oldTab close]; 624 [oldTab close];
638 } 625 }
639 626
640 - (void)closeTabAtIndex:(NSUInteger)index { 627 - (void)closeTabAtIndex:(NSUInteger)index {
641 DCHECK(index < self.count); 628 DCHECK(index < self.count);
642 [self closeTab:[self tabAtIndex:index]]; 629 [self closeTab:[self tabAtIndex:index]];
643 } 630 }
644 631
645 - (void)closeTab:(Tab*)tab { 632 - (void)closeTab:(Tab*)tab {
646 // Ensure the tab stays alive long enough for us to send out the 633 // Ensure the tab stays alive long enough for us to send out the
647 // notice of its destruction to the delegate. 634 // notice of its destruction to the delegate.
648 [_observers tabModel:self willRemoveTab:tab]; 635 [_observers tabModel:self willRemoveTab:tab];
649 [tab close]; // Note it is not safe to access the tab after 'close'. 636 [tab close]; // Note it is not safe to access the tab after 'close'.
650 } 637 }
651 638
652 - (void)closeAllTabs { 639 - (void)closeAllTabs {
653 // If this changes, _closedTabCount metrics need to be adjusted.
654 for (NSInteger i = self.count - 1; i >= 0; --i) 640 for (NSInteger i = self.count - 1; i >= 0; --i)
655 [self closeTabAtIndex:i]; 641 [self closeTabAtIndex:i];
656 [[NSNotificationCenter defaultCenter] 642 [[NSNotificationCenter defaultCenter]
657 postNotificationName:kTabModelAllTabsDidCloseNotification 643 postNotificationName:kTabModelAllTabsDidCloseNotification
658 object:self]; 644 object:self];
659 } 645 }
660 646
661 - (void)haltAllTabs { 647 - (void)haltAllTabs {
662 for (Tab* tab in self) { 648 for (Tab* tab in self) {
663 [tab terminateNetworkActivity]; 649 [tab terminateNetworkActivity];
664 } 650 }
665 } 651 }
666 652
667 - (void)notifyTabChanged:(Tab*)tab { 653 - (void)notifyTabChanged:(Tab*)tab {
668 [_observers tabModel:self didChangeTab:tab]; 654 [_observers tabModel:self didChangeTab:tab];
669 } 655 }
670 656
671 - (void)addObserver:(id<TabModelObserver>)observer { 657 - (void)addObserver:(id<TabModelObserver>)observer {
672 [_observers addObserver:observer]; 658 [_observers addObserver:observer];
673 } 659 }
674 660
675 - (void)removeObserver:(id<TabModelObserver>)observer { 661 - (void)removeObserver:(id<TabModelObserver>)observer {
676 [_observers removeObserver:observer]; 662 [_observers removeObserver:observer];
677 } 663 }
678 664
679 - (void)resetSessionMetrics { 665 - (void)resetSessionMetrics {
680 _closedTabCount = 0; 666 if (_webStateListMetricsObserver)
681 _openedTabCount = 0; 667 _webStateListMetricsObserver->ResetSessionMetrics();
682 _newTabCount = 0;
683 } 668 }
684 669
685 - (void)recordSessionMetrics { 670 - (void)recordSessionMetrics {
686 UMA_HISTOGRAM_CUSTOM_COUNTS("Session.ClosedTabCounts", _closedTabCount, 1, 671 if (_webStateListMetricsObserver)
687 200, 50); 672 _webStateListMetricsObserver->RecordSessionMetrics();
688 UMA_HISTOGRAM_CUSTOM_COUNTS("Session.OpenedTabCounts", _openedTabCount, 1,
689 200, 50);
690 UMA_HISTOGRAM_CUSTOM_COUNTS("Session.NewTabCounts", _newTabCount, 1, 200, 50);
691 } 673 }
692 674
693 - (void)notifyTabSnapshotChanged:(Tab*)tab withImage:(UIImage*)image { 675 - (void)notifyTabSnapshotChanged:(Tab*)tab withImage:(UIImage*)image {
694 DCHECK([NSThread isMainThread]); 676 DCHECK([NSThread isMainThread]);
695 [_observers tabModel:self didChangeTabSnapshot:tab withImage:image]; 677 [_observers tabModel:self didChangeTabSnapshot:tab withImage:image];
696 } 678 }
697 679
698 - (void)resetAllWebViews { 680 - (void)resetAllWebViews {
699 for (Tab* tab in self) { 681 for (Tab* tab in self) {
700 [tab.webController reinitializeWebViewAndReload:(tab == _currentTab)]; 682 [tab.webController reinitializeWebViewAndReload:(tab == self.currentTab)];
701 } 683 }
702 } 684 }
703 685
704 - (void)setWebUsageEnabled:(BOOL)webUsageEnabled { 686 - (void)setWebUsageEnabled:(BOOL)webUsageEnabled {
705 if (webUsageEnabled_ == webUsageEnabled) 687 if (webUsageEnabled_ == webUsageEnabled)
706 return; 688 return;
707 webUsageEnabled_ = webUsageEnabled; 689 webUsageEnabled_ = webUsageEnabled;
708 for (Tab* tab in self) { 690 for (Tab* tab in self) {
709 tab.webUsageEnabled = webUsageEnabled; 691 tab.webUsageEnabled = webUsageEnabled;
710 } 692 }
711 } 693 }
712 694
713 - (void)setPrimary:(BOOL)primary { 695 - (void)setPrimary:(BOOL)primary {
714 if (_tabUsageRecorder) 696 if (_tabUsageRecorder)
715 _tabUsageRecorder->RecordPrimaryTabModelChange(primary, _currentTab); 697 _tabUsageRecorder->RecordPrimaryTabModelChange(primary, self.currentTab);
716 } 698 }
717 699
718 - (NSSet*)currentlyReferencedExternalFiles { 700 - (NSSet*)currentlyReferencedExternalFiles {
719 NSMutableSet* referencedFiles = [NSMutableSet set]; 701 NSMutableSet* referencedFiles = [NSMutableSet set];
720 if (!_browserState) 702 if (!_browserState)
721 return referencedFiles; 703 return referencedFiles;
722 // Check the currently open tabs for external files. 704 // Check the currently open tabs for external files.
723 for (Tab* tab in self) { 705 for (Tab* tab in self) {
724 if (UrlIsExternalFileReference(tab.url)) { 706 if (UrlIsExternalFileReference(tab.url)) {
725 NSString* fileName = base::SysUTF8ToNSString(tab.url.ExtractFileName()); 707 NSString* fileName = base::SysUTF8ToNSString(tab.url.ExtractFileName());
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
769 ? IOSChromeTabRestoreServiceFactory::GetForBrowserState(_browserState) 751 ? IOSChromeTabRestoreServiceFactory::GetForBrowserState(_browserState)
770 : nullptr; 752 : nullptr;
771 web::NavigationManagerImpl* navigationManager = [closedTab navigationManager]; 753 web::NavigationManagerImpl* navigationManager = [closedTab navigationManager];
772 DCHECK(navigationManager); 754 DCHECK(navigationManager);
773 int itemCount = navigationManager->GetItemCount(); 755 int itemCount = navigationManager->GetItemCount();
774 if (restoreService && (![self isNTPTab:closedTab] || itemCount > 1)) { 756 if (restoreService && (![self isNTPTab:closedTab] || itemCount > 1)) {
775 restoreService->CreateHistoricalTab( 757 restoreService->CreateHistoricalTab(
776 sessions::IOSLiveTab::GetForWebState(closedTab.webState), 758 sessions::IOSLiveTab::GetForWebState(closedTab.webState),
777 closedTabIndex); 759 closedTabIndex);
778 } 760 }
779 // This needs to be called before the tab is removed from the list.
780 Tab* newSelection =
781 [_orderController determineNewSelectedTabFromRemovedTab:closedTab];
782 761
783 base::scoped_nsobject<Tab> kungFuDeathGrip([closedTab retain]); 762 base::scoped_nsobject<Tab> kungFuDeathGrip([closedTab retain]);
784 763
785 // If closing the current tab, clear |_currentTab| before sending any 764 // If a non-current Tab is closed, save the session (it will be saved by
786 // notification. This avoids various parts of the code getting confused 765 // TabModelObserversBridge if the currentTab has been closed).
787 // when the current tab isn't in the tab model. 766 BOOL needToSaveSession = (closedTab != self.currentTab);
788 Tab* savedCurrentTab = _currentTab;
789 if (closedTab == _currentTab)
790 _currentTab.reset(nil);
791 767
792 DCHECK([_tabRetainer containsObject:closedTab]); 768 DCHECK([_tabRetainer containsObject:closedTab]);
793 [_tabRetainer removeObject:closedTab]; 769 [_tabRetainer removeObject:closedTab];
794 770
795 _webStateList.DetachWebStateAt(closedTabIndex); 771 _webStateList.DetachWebStateAt(closedTabIndex);
796 772
797 // Current tab has closed, update the selected tab and swap in its 773 if (needToSaveSession)
798 // contents. There is nothing to do if a non-selected tab is closed as
799 // the selection isn't index-based, therefore it hasn't changed.
800 // -changeSelectedTabFrom: will persist the state change, so only do it
801 // if the selection isn't changing.
802 if (closedTab == savedCurrentTab) {
803 [self changeSelectedTabFrom:closedTab to:newSelection persistState:NO];
804 } else {
805 [self saveSessionImmediately:NO]; 774 [self saveSessionImmediately:NO];
806 }
807 ++_closedTabCount;
808 } 775 }
809 776
810 - (void)navigationCommittedInTab:(Tab*)tab { 777 - (void)navigationCommittedInTab:(Tab*)tab {
811 if (self.offTheRecord) 778 if (self.offTheRecord)
812 return; 779 return;
813 if (![tab navigationManager]) 780 if (![tab navigationManager])
814 return; 781 return;
815 782
816 // See if the navigation was within a page; if so ignore it. 783 // See if the navigation was within a page; if so ignore it.
817 web::NavigationItem* previousItem = 784 web::NavigationItem* previousItem =
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
851 count++; 818 count++;
852 } 819 }
853 return count; 820 return count;
854 } 821 }
855 822
856 #pragma mark - Private methods 823 #pragma mark - Private methods
857 824
858 - (SessionWindowIOS*)windowForSavingSession { 825 - (SessionWindowIOS*)windowForSavingSession {
859 // Background tabs will already have their state preserved, but not the 826 // Background tabs will already have their state preserved, but not the
860 // fg tab. Do it now. 827 // fg tab. Do it now.
861 [_currentTab recordStateInHistory]; 828 [self.currentTab recordStateInHistory];
862 829
863 // Build the array of sessions. Copy the session objects as the saving will 830 // Build the array of sessions. Copy the session objects as the saving will
864 // be done on a separate thread. 831 // be done on a separate thread.
865 // TODO(crbug.com/661986): This could get expensive especially since this 832 // TODO(crbug.com/661986): This could get expensive especially since this
866 // window may never be saved (if another call comes in before the delay). 833 // window may never be saved (if another call comes in before the delay).
867 SessionWindowIOS* window = [[[SessionWindowIOS alloc] init] autorelease]; 834 SessionWindowIOS* window = [[[SessionWindowIOS alloc] init] autorelease];
868 for (Tab* tab in self) { 835 for (Tab* tab in self) {
869 web::WebState* webState = tab.webState; 836 web::WebState* webState = tab.webState;
870 DCHECK(webState); 837 DCHECK(webState);
871 [window addSerializedSessionStorage:webState->BuildSessionStorage()]; 838 [window addSerializedSessionStorage:webState->BuildSessionStorage()];
872 } 839 }
873 window.selectedIndex = [self indexOfTab:_currentTab]; 840 window.selectedIndex = [self indexOfTab:self.currentTab];
874 return window; 841 return window;
875 } 842 }
876 843
877 - (BOOL)isNTPTab:(Tab*)tab { 844 - (BOOL)isNTPTab:(Tab*)tab {
878 std::string host = tab.url.host(); 845 std::string host = tab.url.host();
879 return host == kChromeUINewTabHost || host == kChromeUIBookmarksHost; 846 return host == kChromeUINewTabHost || host == kChromeUIBookmarksHost;
880 } 847 }
881 848
882 - (Tab*)insertTabWithLoadParams: 849 - (Tab*)insertTabWithLoadParams:
883 (const web::NavigationManager::WebLoadParams&)params 850 (const web::NavigationManager::WebLoadParams&)params
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
915 postNotificationName:kTabModelNewTabWillOpenNotification 882 postNotificationName:kTabModelNewTabWillOpenNotification
916 object:self 883 object:self
917 userInfo:userInfo]; 884 userInfo:userInfo];
918 885
919 if (!inBackground) 886 if (!inBackground)
920 [self setCurrentTab:tab]; 887 [self setCurrentTab:tab];
921 888
922 return tab; 889 return tab;
923 } 890 }
924 891
925 - (void)changeSelectedTabFrom:(Tab*)oldTab
926 to:(Tab*)newTab
927 persistState:(BOOL)persist {
928 if (oldTab) {
929 // Save state, such as scroll position, before switching tabs.
930 if (oldTab != newTab && persist)
931 [oldTab recordStateInHistory];
932 [self postNotificationName:kTabModelTabDeselectedNotification
933 withTab:oldTab];
934 }
935
936 // No Tab to select (e.g. the last Tab has been closed).
937 if ([self indexOfTab:newTab] == NSNotFound)
938 return;
939
940 _currentTab.reset(newTab);
941 if (newTab) {
942 [_observers tabModel:self
943 didChangeActiveTab:newTab
944 previousTab:oldTab
945 atIndex:[self indexOfTab:newTab]];
946 [newTab updateLastVisitedTimestamp];
947 ++_openedTabCount;
948 }
949 BOOL loadingFinished = [newTab.webController loadPhase] == web::PAGE_LOADED;
950 if (loadingFinished) {
951 // Persist the session state.
952 [self saveSessionImmediately:NO];
953 }
954 }
955
956 - (void)updateSnapshotCache:(Tab*)tab {
957 NSMutableSet* set = [NSMutableSet set];
958 NSUInteger index = [self indexOfTab:tab];
959 if (index > 0) {
960 Tab* previousTab = [self tabAtIndex:(index - 1)];
961 [set addObject:previousTab.tabId];
962 }
963 if (index < self.count - 1) {
964 Tab* nextTab = [self tabAtIndex:(index + 1)];
965 [set addObject:nextTab.tabId];
966 }
967 [SnapshotCache sharedInstance].pinnedIDs = set;
968 }
969
970 - (void)postNotificationName:(NSString*)notificationName withTab:(Tab*)tab { 892 - (void)postNotificationName:(NSString*)notificationName withTab:(Tab*)tab {
971 // A scoped_nsobject is used rather than an NSDictionary with static 893 // A scoped_nsobject is used rather than an NSDictionary with static
972 // initializer dictionaryWithObject, because that approach adds the dictionary 894 // initializer dictionaryWithObject, because that approach adds the dictionary
973 // to the autorelease pool, which in turn holds Tab alive longer than 895 // to the autorelease pool, which in turn holds Tab alive longer than
974 // necessary. 896 // necessary.
975 base::scoped_nsobject<NSDictionary> userInfo( 897 base::scoped_nsobject<NSDictionary> userInfo(
976 [[NSDictionary alloc] initWithObjectsAndKeys:tab, kTabModelTabKey, nil]); 898 [[NSDictionary alloc] initWithObjectsAndKeys:tab, kTabModelTabKey, nil]);
977 [[NSNotificationCenter defaultCenter] postNotificationName:notificationName 899 [[NSNotificationCenter defaultCenter] postNotificationName:notificationName
978 object:self 900 object:self
979 userInfo:userInfo]; 901 userInfo:userInfo];
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
1028 DCHECK(opener.webState); 950 DCHECK(opener.webState);
1029 _webStateList.SetOpenerOfWebStateAt(index, opener.webState); 951 _webStateList.SetOpenerOfWebStateAt(index, opener.webState);
1030 } 952 }
1031 } 953 }
1032 954
1033 // Update the selected tab if there was a selected Tab in the saved session. 955 // Update the selected tab if there was a selected Tab in the saved session.
1034 if (window.selectedIndex != NSNotFound) { 956 if (window.selectedIndex != NSNotFound) {
1035 NSUInteger selectedIndex = window.selectedIndex + oldCount; 957 NSUInteger selectedIndex = window.selectedIndex + oldCount;
1036 DCHECK_LT(selectedIndex, self.count); 958 DCHECK_LT(selectedIndex, self.count);
1037 DCHECK([self tabAtIndex:selectedIndex]); 959 DCHECK([self tabAtIndex:selectedIndex]);
1038 [self changeSelectedTabFrom:_currentTab 960
1039 to:[self tabAtIndex:selectedIndex] 961 if (persistState && self.currentTab)
1040 persistState:persistState]; 962 [self.currentTab recordStateInHistory];
963 _webStateList.ActivateWebStateAt(static_cast<int>(selectedIndex));
1041 } 964 }
1042 965
1043 // If there was only one tab and it was the new tab page, clobber it. 966 // If there was only one tab and it was the new tab page, clobber it.
1044 BOOL closedNTPTab = NO; 967 BOOL closedNTPTab = NO;
1045 if (oldCount == 1) { 968 if (oldCount == 1) {
1046 Tab* tab = [self tabAtIndex:0]; 969 Tab* tab = [self tabAtIndex:0];
1047 if (tab.url == GURL(kChromeUINewTabURL)) { 970 if (tab.url == GURL(kChromeUINewTabURL)) {
1048 [self closeTab:tab]; 971 [self closeTab:tab];
1049 closedNTPTab = YES; 972 closedNTPTab = YES;
1050 oldCount = 0; 973 oldCount = 0;
1051 } 974 }
1052 } 975 }
1053 if (_tabUsageRecorder) { 976 if (_tabUsageRecorder) {
1054 NSMutableArray<Tab*>* restoredTabs = 977 NSMutableArray<Tab*>* restoredTabs =
1055 [NSMutableArray arrayWithCapacity:_webStateList.count() - oldCount]; 978 [NSMutableArray arrayWithCapacity:_webStateList.count() - oldCount];
1056 for (int index = oldCount; index < _webStateList.count(); ++index) { 979 for (int index = oldCount; index < _webStateList.count(); ++index) {
1057 web::WebState* webState = _webStateList.GetWebStateAt(index); 980 web::WebState* webState = _webStateList.GetWebStateAt(index);
1058 [restoredTabs addObject:LegacyTabHelper::GetTabForWebState(webState)]; 981 [restoredTabs addObject:LegacyTabHelper::GetTabForWebState(webState)];
1059 } 982 }
1060 _tabUsageRecorder->InitialRestoredTabs(_currentTab, restoredTabs); 983 _tabUsageRecorder->InitialRestoredTabs(self.currentTab, restoredTabs);
1061 } 984 }
1062 return closedNTPTab; 985 return closedNTPTab;
1063 } 986 }
1064 987
1065 #pragma mark - Notification Handlers 988 #pragma mark - Notification Handlers
1066 989
1067 // Called when UIApplicationWillResignActiveNotification is received. 990 // Called when UIApplicationWillResignActiveNotification is received.
1068 - (void)willResignActive:(NSNotification*)notify { 991 - (void)willResignActive:(NSNotification*)notify {
1069 if (webUsageEnabled_ && _currentTab) { 992 if (webUsageEnabled_ && self.currentTab) {
1070 [[SnapshotCache sharedInstance] 993 [[SnapshotCache sharedInstance]
1071 willBeSavedGreyWhenBackgrounding:_currentTab.get().tabId]; 994 willBeSavedGreyWhenBackgrounding:self.currentTab.tabId];
1072 } 995 }
1073 } 996 }
1074 997
1075 // Called when UIApplicationDidEnterBackgroundNotification is received. 998 // Called when UIApplicationDidEnterBackgroundNotification is received.
1076 - (void)applicationDidEnterBackground:(NSNotification*)notify { 999 - (void)applicationDidEnterBackground:(NSNotification*)notify {
1077 if (!_browserState) 1000 if (!_browserState)
1078 return; 1001 return;
1079 1002
1080 // Evict all the certificate policies except for the current entries of the 1003 // Evict all the certificate policies except for the current entries of the
1081 // active sessions. 1004 // active sessions.
1082 CleanCertificatePolicyCache( 1005 CleanCertificatePolicyCache(
1083 &_clearPoliciesTaskTracker, 1006 &_clearPoliciesTaskTracker,
1084 web::WebThread::GetTaskRunnerForThread(web::WebThread::IO), 1007 web::WebThread::GetTaskRunnerForThread(web::WebThread::IO),
1085 web::BrowserState::GetCertificatePolicyCache(_browserState), 1008 web::BrowserState::GetCertificatePolicyCache(_browserState),
1086 &_webStateList); 1009 &_webStateList);
1087 1010
1088 if (_tabUsageRecorder) 1011 if (_tabUsageRecorder)
1089 _tabUsageRecorder->AppDidEnterBackground(); 1012 _tabUsageRecorder->AppDidEnterBackground();
1090 1013
1091 // Normally, the session is saved after some timer expires but since the app 1014 // Normally, the session is saved after some timer expires but since the app
1092 // is about to enter the background send YES to save the session immediately. 1015 // is about to enter the background send YES to save the session immediately.
1093 [self saveSessionImmediately:YES]; 1016 [self saveSessionImmediately:YES];
1094 1017
1095 // Write out a grey version of the current website to disk. 1018 // Write out a grey version of the current website to disk.
1096 if (webUsageEnabled_ && _currentTab) { 1019 if (webUsageEnabled_ && self.currentTab) {
1097 [[SnapshotCache sharedInstance] 1020 [[SnapshotCache sharedInstance]
1098 saveGreyInBackgroundForSessionID:_currentTab.get().tabId]; 1021 saveGreyInBackgroundForSessionID:self.currentTab.tabId];
1099 } 1022 }
1100 } 1023 }
1101 1024
1102 // Called when UIApplicationWillEnterForegroundNotification is received. 1025 // Called when UIApplicationWillEnterForegroundNotification is received.
1103 - (void)applicationWillEnterForeground:(NSNotification*)notify { 1026 - (void)applicationWillEnterForeground:(NSNotification*)notify {
1104 if (_tabUsageRecorder) { 1027 if (_tabUsageRecorder) {
1105 _tabUsageRecorder->AppWillEnterForeground(); 1028 _tabUsageRecorder->AppWillEnterForeground();
1106 } 1029 }
1107 } 1030 }
1108 1031
(...skipping 26 matching lines...) Expand all
1135 web::NavigationManager::WebLoadParams params(URL); 1058 web::NavigationManager::WebLoadParams params(URL);
1136 params.referrer = referrer; 1059 params.referrer = referrer;
1137 params.transition_type = ui::PAGE_TRANSITION_TYPED; 1060 params.transition_type = ui::PAGE_TRANSITION_TYPED;
1138 [[tab webController] loadWithParams:params]; 1061 [[tab webController] loadWithParams:params];
1139 [tab webController].webUsageEnabled = webUsageEnabled_; 1062 [tab webController].webUsageEnabled = webUsageEnabled_;
1140 [self insertTab:tab atIndex:index opener:parentTab]; 1063 [self insertTab:tab atIndex:index opener:parentTab];
1141 return tab; 1064 return tab;
1142 } 1065 }
1143 1066
1144 @end 1067 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698