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

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: Rebase. Created 3 years, 9 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
« no previous file with comments | « ios/chrome/browser/tabs/tab.mm ('k') | ios/chrome/browser/tabs/tab_model_observers_bridge.mm » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
155 157
156 // Used to keep the Tabs alive while the corresponding WebStates are stored 158 // Used to keep the Tabs alive while the corresponding WebStates are stored
157 // in the WebStateList (as Tabs currently own their WebState). Remove once 159 // in the WebStateList (as Tabs currently own their WebState). Remove once
158 // WebState owns the associated Tab. 160 // WebState owns the associated Tab.
159 base::scoped_nsobject<NSMutableSet<Tab*>> _tabRetainer; 161 base::scoped_nsobject<NSMutableSet<Tab*>> _tabRetainer;
160 162
161 // WebStateListObserver bridges to react to modifications of the model (may 163 // WebStateListObserver bridges to react to modifications of the model (may
162 // send notification, translate and forward events, update metrics, ...). 164 // send notification, translate and forward events, update metrics, ...).
163 std::vector<std::unique_ptr<WebStateListObserver>> _observerBridges; 165 std::vector<std::unique_ptr<WebStateListObserver>> _observerBridges;
164 166
165 // Maintains policy for where new tabs go and the selection when a tab
166 // is removed.
167 base::scoped_nsobject<TabModelOrderController> _orderController;
168 // The delegate for sync. 167 // The delegate for sync.
169 std::unique_ptr<TabModelSyncedWindowDelegate> _syncedWindowDelegate; 168 std::unique_ptr<TabModelSyncedWindowDelegate> _syncedWindowDelegate;
170 // Currently selected tab. May be nil.
171 base::WeakNSObject<Tab> _currentTab;
172 169
173 // Counters for metrics. 170 // Counters for metrics.
174 int _openedTabCount; 171 WebStateListMetricsObserver* _webStateListMetricsObserver;
175 int _closedTabCount;
176 int _newTabCount;
177 172
178 // Backs up property with the same name. 173 // Backs up property with the same name.
179 std::unique_ptr<TabUsageRecorder> _tabUsageRecorder; 174 std::unique_ptr<TabUsageRecorder> _tabUsageRecorder;
180 // Backs up property with the same name. 175 // Backs up property with the same name.
181 const SessionID _sessionID; 176 const SessionID _sessionID;
182 // Saves session's state. 177 // Saves session's state.
183 base::scoped_nsobject<SessionServiceIOS> _sessionService; 178 base::scoped_nsobject<SessionServiceIOS> _sessionService;
184 // List of TabModelObservers. 179 // List of TabModelObservers.
185 base::scoped_nsobject<TabModelObservers> _observers; 180 base::scoped_nsobject<TabModelObservers> _observers;
186 181
187 // Used to ensure thread-safety of the certificate policy management code. 182 // Used to ensure thread-safety of the certificate policy management code.
188 base::CancelableTaskTracker _clearPoliciesTaskTracker; 183 base::CancelableTaskTracker _clearPoliciesTaskTracker;
189 } 184 }
190 185
191 // Session window for the contents of the tab model. 186 // Session window for the contents of the tab model.
192 @property(nonatomic, readonly) SessionWindowIOS* windowForSavingSession; 187 @property(nonatomic, readonly) SessionWindowIOS* windowForSavingSession;
193 188
194 // Returns YES if tab URL host indicates that tab is an NTP tab. 189 // Returns YES if tab URL host indicates that tab is an NTP tab.
195 - (BOOL)isNTPTab:(Tab*)tab; 190 - (BOOL)isNTPTab:(Tab*)tab;
196 191
197 // Call to switch the selected tab. Broadcasts about the change in selection.
198 // It's ok for |newTab| to be nil in case the last tab is going away. In that
199 // case, the "tab deselected" notification gets sent, but no corresponding
200 // "tab selected" notification is sent. |persist| indicates whether or not
201 // the tab's state should be persisted in history upon switching.
202 - (void)changeSelectedTabFrom:(Tab*)oldTab
203 to:(Tab*)newTab
204 persistState:(BOOL)persist;
205
206 // Tells the snapshot cache the adjacent tab session ids.
207 - (void)updateSnapshotCache:(Tab*)tab;
208
209 // Helper method that posts a notification with the given name with |tab| 192 // Helper method that posts a notification with the given name with |tab|
210 // in the userInfo dictionary under the kTabModelTabKey. 193 // in the userInfo dictionary under the kTabModelTabKey.
211 - (void)postNotificationName:(NSString*)notificationName withTab:(Tab*)tab; 194 - (void)postNotificationName:(NSString*)notificationName withTab:(Tab*)tab;
212 195
213 // Helper method to restore a saved session and control if the state should 196 // Helper method to restore a saved session and control if the state should
214 // be persisted or not. Used to implement the public -restoreSessionWindow: 197 // be persisted or not. Used to implement the public -restoreSessionWindow:
215 // method and restoring session in the initialiser. 198 // method and restoring session in the initialiser.
216 - (BOOL)restoreSessionWindow:(SessionWindowIOS*)window 199 - (BOOL)restoreSessionWindow:(SessionWindowIOS*)window
217 persistState:(BOOL)persistState; 200 persistState:(BOOL)persistState;
218 201
(...skipping 22 matching lines...) Expand all
241 224
242 #pragma mark - Overriden 225 #pragma mark - Overriden
243 226
244 - (void)dealloc { 227 - (void)dealloc {
245 DCHECK([_observers empty]); 228 DCHECK([_observers empty]);
246 // browserStateDestroyed should always have been called before destruction. 229 // browserStateDestroyed should always have been called before destruction.
247 DCHECK(!_browserState); 230 DCHECK(!_browserState);
248 231
249 [[NSNotificationCenter defaultCenter] removeObserver:self]; 232 [[NSNotificationCenter defaultCenter] removeObserver:self];
250 233
234 // Clear weak pointer to WebStateListMetricsObserver before destroying it.
235 _webStateListMetricsObserver = nullptr;
236
251 // Unregister all listeners before closing all the tabs. 237 // Unregister all listeners before closing all the tabs.
252 for (const auto& observerBridge : _observerBridges) 238 for (const auto& observerBridge : _observerBridges)
253 _webStateList.RemoveObserver(observerBridge.get()); 239 _webStateList.RemoveObserver(observerBridge.get());
254 _observerBridges.clear(); 240 _observerBridges.clear();
255 241
256 // Make sure the tabs do clean after themselves. It is important for 242 // Make sure the tabs do clean after themselves. It is important for
257 // removeObserver: to be called first otherwise a lot of unecessary work will 243 // removeObserver: to be called first otherwise a lot of unecessary work will
258 // happen on -closeAllTabs. 244 // happen on -closeAllTabs.
259 [self closeAllTabs]; 245 [self closeAllTabs];
260 246
261 _clearPoliciesTaskTracker.TryCancelAll(); 247 _clearPoliciesTaskTracker.TryCancelAll();
262 248
263 [super dealloc]; 249 [super dealloc];
264 } 250 }
265 251
266 #pragma mark - Public methods 252 #pragma mark - Public methods
267 253
268 - (Tab*)currentTab { 254 - (Tab*)currentTab {
269 return _currentTab.get(); 255 web::WebState* webState = _webStateList.GetActiveWebState();
256 return webState ? LegacyTabHelper::GetTabForWebState(webState) : nil;
270 } 257 }
271 258
272 - (void)setCurrentTab:(Tab*)newTab { 259 - (void)setCurrentTab:(Tab*)newTab {
273 DCHECK_NE([self indexOfTab:newTab], static_cast<NSUInteger>(NSNotFound)); 260 int indexOfTab = _webStateList.GetIndexOfWebState(newTab.webState);
274 if (_currentTab != newTab) { 261 DCHECK_NE(indexOfTab, WebStateList::kInvalidIndex);
275 base::RecordAction(base::UserMetricsAction("MobileTabSwitched")); 262 _webStateList.ActivateWebStateAt(indexOfTab);
276 [self updateSnapshotCache:newTab];
277 }
278 if (_tabUsageRecorder) {
279 _tabUsageRecorder->RecordTabSwitched(_currentTab, newTab);
280 }
281 [self changeSelectedTabFrom:_currentTab to:newTab persistState:YES];
282 } 263 }
283 264
284 - (TabModelSyncedWindowDelegate*)syncedWindowDelegate { 265 - (TabModelSyncedWindowDelegate*)syncedWindowDelegate {
285 return _syncedWindowDelegate.get(); 266 return _syncedWindowDelegate.get();
286 } 267 }
287 268
288 - (TabUsageRecorder*)tabUsageRecorder { 269 - (TabUsageRecorder*)tabUsageRecorder {
289 return _tabUsageRecorder.get(); 270 return _tabUsageRecorder.get();
290 } 271 }
291 272
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
323 // Set up the usage recorder before tabs are created. 304 // Set up the usage recorder before tabs are created.
324 _tabUsageRecorder = base::MakeUnique<TabUsageRecorder>(self); 305 _tabUsageRecorder = base::MakeUnique<TabUsageRecorder>(self);
325 } 306 }
326 _syncedWindowDelegate = 307 _syncedWindowDelegate =
327 base::MakeUnique<TabModelSyncedWindowDelegate>(self); 308 base::MakeUnique<TabModelSyncedWindowDelegate>(self);
328 309
329 // There must be a valid session service defined to consume session windows. 310 // There must be a valid session service defined to consume session windows.
330 DCHECK(service); 311 DCHECK(service);
331 _sessionService.reset([service retain]); 312 _sessionService.reset([service retain]);
332 313
314 _observerBridges.push_back(
315 base::MakeUnique<SnapshotCacheWebStateListObserver>(
316 [SnapshotCache sharedInstance]));
317 if (_tabUsageRecorder) {
318 _observerBridges.push_back(
319 base::MakeUnique<TabUsageRecorderWebStateListObserver>(
320 _tabUsageRecorder.get()));
321 }
333 _observerBridges.push_back(base::MakeUnique<TabParentingObserver>()); 322 _observerBridges.push_back(base::MakeUnique<TabParentingObserver>());
334 _observerBridges.push_back(base::MakeUnique<WebStateListObserverBridge>( 323 _observerBridges.push_back(base::MakeUnique<WebStateListObserverBridge>(
324 [[TabModelSelectedTabObserver alloc] initWithTabModel:self]));
325 _observerBridges.push_back(base::MakeUnique<WebStateListObserverBridge>(
335 [[TabModelObserversBridge alloc] initWithTabModel:self 326 [[TabModelObserversBridge alloc] initWithTabModel:self
336 tabModelObservers:_observers.get()])); 327 tabModelObservers:_observers.get()]));
337 _observerBridges.push_back(base::MakeUnique<WebStateListMetricsObserver>()); 328
329 auto webStateListMetricsObserver =
330 base::MakeUnique<WebStateListMetricsObserver>();
331 _webStateListMetricsObserver = webStateListMetricsObserver.get();
332 _observerBridges.push_back(std::move(webStateListMetricsObserver));
338 333
339 for (const auto& observerBridge : _observerBridges) 334 for (const auto& observerBridge : _observerBridges)
340 _webStateList.AddObserver(observerBridge.get()); 335 _webStateList.AddObserver(observerBridge.get());
341 336
342 if (window) { 337 if (window) {
343 DCHECK([_observers empty]); 338 DCHECK([_observers empty]);
344 // Restore the session and reset the session metrics (as the event have 339 // Restore the session and reset the session metrics (as the event have
345 // not been generated by the user but by a cold start cycle). 340 // not been generated by the user but by a cold start cycle).
346 [self restoreSessionWindow:window persistState:NO]; 341 [self restoreSessionWindow:window persistState:NO];
347 [self resetSessionMetrics]; 342 [self resetSessionMetrics];
348 } 343 }
349 344
350 _orderController.reset(
351 [[TabModelOrderController alloc] initWithTabModel:self]);
352
353 // Register for resign active notification. 345 // Register for resign active notification.
354 [[NSNotificationCenter defaultCenter] 346 [[NSNotificationCenter defaultCenter]
355 addObserver:self 347 addObserver:self
356 selector:@selector(willResignActive:) 348 selector:@selector(willResignActive:)
357 name:UIApplicationWillResignActiveNotification 349 name:UIApplicationWillResignActiveNotification
358 object:nil]; 350 object:nil];
359 // Register for background notification. 351 // Register for background notification.
360 [[NSNotificationCenter defaultCenter] 352 [[NSNotificationCenter defaultCenter]
361 addObserver:self 353 addObserver:self
362 selector:@selector(applicationDidEnterBackground:) 354 selector:@selector(applicationDidEnterBackground:)
(...skipping 17 matching lines...) Expand all
380 return nil; 372 return nil;
381 } 373 }
382 374
383 - (BOOL)restoreSessionWindow:(SessionWindowIOS*)window { 375 - (BOOL)restoreSessionWindow:(SessionWindowIOS*)window {
384 return [self restoreSessionWindow:window persistState:YES]; 376 return [self restoreSessionWindow:window persistState:YES];
385 } 377 }
386 378
387 - (void)saveSessionImmediately:(BOOL)immediately { 379 - (void)saveSessionImmediately:(BOOL)immediately {
388 // Do nothing if there are tabs in the model but no selected tab. This is 380 // Do nothing if there are tabs in the model but no selected tab. This is
389 // a transitional state. 381 // a transitional state.
390 if ((!_currentTab && _webStateList.count()) || !_browserState) 382 if ((!self.currentTab && _webStateList.count()) || !_browserState)
391 return; 383 return;
392 [_sessionService saveWindow:self.windowForSavingSession 384 [_sessionService saveWindow:self.windowForSavingSession
393 forBrowserState:_browserState 385 forBrowserState:_browserState
394 immediately:immediately]; 386 immediately:immediately];
395 } 387 }
396 388
397 - (Tab*)tabAtIndex:(NSUInteger)index { 389 - (Tab*)tabAtIndex:(NSUInteger)index {
398 DCHECK_LE(index, static_cast<NSUInteger>(INT_MAX)); 390 DCHECK_LE(index, static_cast<NSUInteger>(INT_MAX));
399 return LegacyTabHelper::GetTabForWebState( 391 return LegacyTabHelper::GetTabForWebState(
400 _webStateList.GetWebStateAt(static_cast<int>(index))); 392 _webStateList.GetWebStateAt(static_cast<int>(index)));
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
549 const int insertion_index = static_cast<int>(index); 541 const int insertion_index = static_cast<int>(index);
550 _webStateList.InsertWebState(insertion_index, tab.webState, 542 _webStateList.InsertWebState(insertion_index, tab.webState,
551 parentTab.webState); 543 parentTab.webState);
552 } 544 }
553 545
554 // Persist the session due to a new tab being inserted. If this is a 546 // Persist the session due to a new tab being inserted. If this is a
555 // background tab (will not become active), saving now will capture the 547 // background tab (will not become active), saving now will capture the
556 // state properly. If it does eventually become active, another save will 548 // state properly. If it does eventually become active, another save will
557 // be triggered to properly capture the end result. 549 // be triggered to properly capture the end result.
558 [self saveSessionImmediately:NO]; 550 [self saveSessionImmediately:NO];
559
560 ++_newTabCount;
561 } 551 }
562 552
563 - (void)insertTab:(Tab*)tab atIndex:(NSUInteger)index opener:(Tab*)parentTab { 553 - (void)insertTab:(Tab*)tab atIndex:(NSUInteger)index opener:(Tab*)parentTab {
564 DCHECK(tab); 554 DCHECK(tab);
565 DCHECK(![_tabRetainer containsObject:tab]); 555 DCHECK(![_tabRetainer containsObject:tab]);
566 DCHECK_LE(index, static_cast<NSUInteger>(INT_MAX)); 556 DCHECK_LE(index, static_cast<NSUInteger>(INT_MAX));
567 557
568 [self insertTab:tab 558 [self insertTab:tab
569 atIndex:index 559 atIndex:index
570 opener:parentTab 560 opener:parentTab
(...skipping 30 matching lines...) Expand all
601 591
602 // The WebState is owned by the associated Tab, so it is safe to ignore 592 // The WebState is owned by the associated Tab, so it is safe to ignore
603 // the result and won't cause a memory leak. Once the ownership is moved 593 // the result and won't cause a memory leak. Once the ownership is moved
604 // to WebStateList, this function will return a std::unique_ptr<> and the 594 // to WebStateList, this function will return a std::unique_ptr<> and the
605 // object destroyed as expected, so it will fine to ignore the result then 595 // object destroyed as expected, so it will fine to ignore the result then
606 // too. See http://crbug.com/546222 for progress of changing the ownership 596 // too. See http://crbug.com/546222 for progress of changing the ownership
607 // of the WebStates. 597 // of the WebStates.
608 ignore_result(_webStateList.ReplaceWebStateAt( 598 ignore_result(_webStateList.ReplaceWebStateAt(
609 index, newTab.webState, GetOpenerForTab(self, newTab).webState)); 599 index, newTab.webState, GetOpenerForTab(self, newTab).webState));
610 600
611 if (self.currentTab == oldTab)
612 [self changeSelectedTabFrom:nil to:newTab persistState:NO];
613
614 [oldTab setParentTabModel:nil]; 601 [oldTab setParentTabModel:nil];
615 [oldTab close]; 602 [oldTab close];
616 } 603 }
617 604
618 - (void)closeTabAtIndex:(NSUInteger)index { 605 - (void)closeTabAtIndex:(NSUInteger)index {
619 DCHECK(index < self.count); 606 DCHECK(index < self.count);
620 [self closeTab:[self tabAtIndex:index]]; 607 [self closeTab:[self tabAtIndex:index]];
621 } 608 }
622 609
623 - (void)closeTab:(Tab*)tab { 610 - (void)closeTab:(Tab*)tab {
624 // Ensure the tab stays alive long enough for us to send out the 611 // Ensure the tab stays alive long enough for us to send out the
625 // notice of its destruction to the delegate. 612 // notice of its destruction to the delegate.
626 [_observers tabModel:self willRemoveTab:tab]; 613 [_observers tabModel:self willRemoveTab:tab];
627 [tab close]; // Note it is not safe to access the tab after 'close'. 614 [tab close]; // Note it is not safe to access the tab after 'close'.
628 } 615 }
629 616
630 - (void)closeAllTabs { 617 - (void)closeAllTabs {
631 // If this changes, _closedTabCount metrics need to be adjusted.
632 for (NSInteger i = self.count - 1; i >= 0; --i) 618 for (NSInteger i = self.count - 1; i >= 0; --i)
633 [self closeTabAtIndex:i]; 619 [self closeTabAtIndex:i];
634 [[NSNotificationCenter defaultCenter] 620 [[NSNotificationCenter defaultCenter]
635 postNotificationName:kTabModelAllTabsDidCloseNotification 621 postNotificationName:kTabModelAllTabsDidCloseNotification
636 object:self]; 622 object:self];
637 } 623 }
638 624
639 - (void)haltAllTabs { 625 - (void)haltAllTabs {
640 for (Tab* tab in self) { 626 for (Tab* tab in self) {
641 [tab terminateNetworkActivity]; 627 [tab terminateNetworkActivity];
642 } 628 }
643 } 629 }
644 630
645 - (void)notifyTabChanged:(Tab*)tab { 631 - (void)notifyTabChanged:(Tab*)tab {
646 [_observers tabModel:self didChangeTab:tab]; 632 [_observers tabModel:self didChangeTab:tab];
647 } 633 }
648 634
649 - (void)addObserver:(id<TabModelObserver>)observer { 635 - (void)addObserver:(id<TabModelObserver>)observer {
650 [_observers addObserver:observer]; 636 [_observers addObserver:observer];
651 } 637 }
652 638
653 - (void)removeObserver:(id<TabModelObserver>)observer { 639 - (void)removeObserver:(id<TabModelObserver>)observer {
654 [_observers removeObserver:observer]; 640 [_observers removeObserver:observer];
655 } 641 }
656 642
657 - (void)resetSessionMetrics { 643 - (void)resetSessionMetrics {
658 _closedTabCount = 0; 644 if (_webStateListMetricsObserver)
659 _openedTabCount = 0; 645 _webStateListMetricsObserver->ResetSessionMetrics();
660 _newTabCount = 0;
661 } 646 }
662 647
663 - (void)recordSessionMetrics { 648 - (void)recordSessionMetrics {
664 UMA_HISTOGRAM_CUSTOM_COUNTS("Session.ClosedTabCounts", _closedTabCount, 1, 649 if (_webStateListMetricsObserver)
665 200, 50); 650 _webStateListMetricsObserver->RecordSessionMetrics();
666 UMA_HISTOGRAM_CUSTOM_COUNTS("Session.OpenedTabCounts", _openedTabCount, 1,
667 200, 50);
668 UMA_HISTOGRAM_CUSTOM_COUNTS("Session.NewTabCounts", _newTabCount, 1, 200, 50);
669 } 651 }
670 652
671 - (void)notifyTabSnapshotChanged:(Tab*)tab withImage:(UIImage*)image { 653 - (void)notifyTabSnapshotChanged:(Tab*)tab withImage:(UIImage*)image {
672 DCHECK([NSThread isMainThread]); 654 DCHECK([NSThread isMainThread]);
673 [_observers tabModel:self didChangeTabSnapshot:tab withImage:image]; 655 [_observers tabModel:self didChangeTabSnapshot:tab withImage:image];
674 } 656 }
675 657
676 - (void)resetAllWebViews { 658 - (void)resetAllWebViews {
677 for (Tab* tab in self) { 659 for (Tab* tab in self) {
678 [tab.webController reinitializeWebViewAndReload:(tab == _currentTab)]; 660 [tab.webController reinitializeWebViewAndReload:(tab == self.currentTab)];
679 } 661 }
680 } 662 }
681 663
682 - (void)setWebUsageEnabled:(BOOL)webUsageEnabled { 664 - (void)setWebUsageEnabled:(BOOL)webUsageEnabled {
683 if (webUsageEnabled_ == webUsageEnabled) 665 if (webUsageEnabled_ == webUsageEnabled)
684 return; 666 return;
685 webUsageEnabled_ = webUsageEnabled; 667 webUsageEnabled_ = webUsageEnabled;
686 for (Tab* tab in self) { 668 for (Tab* tab in self) {
687 tab.webUsageEnabled = webUsageEnabled; 669 tab.webUsageEnabled = webUsageEnabled;
688 } 670 }
689 } 671 }
690 672
691 - (void)setPrimary:(BOOL)primary { 673 - (void)setPrimary:(BOOL)primary {
692 if (_tabUsageRecorder) 674 if (_tabUsageRecorder)
693 _tabUsageRecorder->RecordPrimaryTabModelChange(primary, _currentTab); 675 _tabUsageRecorder->RecordPrimaryTabModelChange(primary, self.currentTab);
694 } 676 }
695 677
696 - (NSSet*)currentlyReferencedExternalFiles { 678 - (NSSet*)currentlyReferencedExternalFiles {
697 NSMutableSet* referencedFiles = [NSMutableSet set]; 679 NSMutableSet* referencedFiles = [NSMutableSet set];
698 if (!_browserState) 680 if (!_browserState)
699 return referencedFiles; 681 return referencedFiles;
700 // Check the currently open tabs for external files. 682 // Check the currently open tabs for external files.
701 for (Tab* tab in self) { 683 for (Tab* tab in self) {
702 if (UrlIsExternalFileReference(tab.url)) { 684 if (UrlIsExternalFileReference(tab.url)) {
703 NSString* fileName = base::SysUTF8ToNSString(tab.url.ExtractFileName()); 685 NSString* fileName = base::SysUTF8ToNSString(tab.url.ExtractFileName());
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
747 ? IOSChromeTabRestoreServiceFactory::GetForBrowserState(_browserState) 729 ? IOSChromeTabRestoreServiceFactory::GetForBrowserState(_browserState)
748 : nullptr; 730 : nullptr;
749 web::NavigationManager* navigationManager = [closedTab navigationManager]; 731 web::NavigationManager* navigationManager = [closedTab navigationManager];
750 DCHECK(navigationManager); 732 DCHECK(navigationManager);
751 int itemCount = navigationManager->GetItemCount(); 733 int itemCount = navigationManager->GetItemCount();
752 if (restoreService && (![self isNTPTab:closedTab] || itemCount > 1)) { 734 if (restoreService && (![self isNTPTab:closedTab] || itemCount > 1)) {
753 restoreService->CreateHistoricalTab( 735 restoreService->CreateHistoricalTab(
754 sessions::IOSLiveTab::GetForWebState(closedTab.webState), 736 sessions::IOSLiveTab::GetForWebState(closedTab.webState),
755 closedTabIndex); 737 closedTabIndex);
756 } 738 }
757 // This needs to be called before the tab is removed from the list.
758 Tab* newSelection =
759 [_orderController determineNewSelectedTabFromRemovedTab:closedTab];
760 739
761 base::scoped_nsobject<Tab> kungFuDeathGrip([closedTab retain]); 740 base::scoped_nsobject<Tab> kungFuDeathGrip([closedTab retain]);
762 741
763 // If closing the current tab, clear |_currentTab| before sending any 742 // If a non-current Tab is closed, save the session (it will be saved by
764 // notification. This avoids various parts of the code getting confused 743 // TabModelObserversBridge if the currentTab has been closed).
765 // when the current tab isn't in the tab model. 744 BOOL needToSaveSession = (closedTab != self.currentTab);
766 Tab* savedCurrentTab = _currentTab;
767 if (closedTab == _currentTab)
768 _currentTab.reset(nil);
769 745
770 DCHECK([_tabRetainer containsObject:closedTab]); 746 DCHECK([_tabRetainer containsObject:closedTab]);
771 [_tabRetainer removeObject:closedTab]; 747 [_tabRetainer removeObject:closedTab];
772 748
773 // The WebState is owned by the associated Tab, so it is safe to ignore 749 // The WebState is owned by the associated Tab, so it is safe to ignore
774 // the result and won't cause a memory leak. Once the ownership is moved 750 // the result and won't cause a memory leak. Once the ownership is moved
775 // to WebStateList, this function will return a std::unique_ptr<> and the 751 // to WebStateList, this function will return a std::unique_ptr<> and the
776 // object destroyed as expected, so it will fine to ignore the result then 752 // object destroyed as expected, so it will fine to ignore the result then
777 // too. See http://crbug.com/546222 for progress of changing the ownership 753 // too. See http://crbug.com/546222 for progress of changing the ownership
778 // of the WebStates. 754 // of the WebStates.
779 ignore_result(_webStateList.DetachWebStateAt(closedTabIndex)); 755 ignore_result(_webStateList.DetachWebStateAt(closedTabIndex));
780 756
781 // Current tab has closed, update the selected tab and swap in its 757 if (needToSaveSession)
782 // contents. There is nothing to do if a non-selected tab is closed as
783 // the selection isn't index-based, therefore it hasn't changed.
784 // -changeSelectedTabFrom: will persist the state change, so only do it
785 // if the selection isn't changing.
786 if (closedTab == savedCurrentTab) {
787 [self changeSelectedTabFrom:closedTab to:newSelection persistState:NO];
788 } else {
789 [self saveSessionImmediately:NO]; 758 [self saveSessionImmediately:NO];
790 }
791 ++_closedTabCount;
792 } 759 }
793 760
794 - (void)navigationCommittedInTab:(Tab*)tab { 761 - (void)navigationCommittedInTab:(Tab*)tab {
795 if (self.offTheRecord) 762 if (self.offTheRecord)
796 return; 763 return;
797 if (![tab navigationManager]) 764 if (![tab navigationManager])
798 return; 765 return;
799 766
800 // See if the navigation was within a page; if so ignore it. 767 // See if the navigation was within a page; if so ignore it.
801 web::NavigationItem* previousItem = 768 web::NavigationItem* previousItem =
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
835 count++; 802 count++;
836 } 803 }
837 return count; 804 return count;
838 } 805 }
839 806
840 #pragma mark - Private methods 807 #pragma mark - Private methods
841 808
842 - (SessionWindowIOS*)windowForSavingSession { 809 - (SessionWindowIOS*)windowForSavingSession {
843 // Background tabs will already have their state preserved, but not the 810 // Background tabs will already have their state preserved, but not the
844 // fg tab. Do it now. 811 // fg tab. Do it now.
845 [_currentTab recordStateInHistory]; 812 [self.currentTab recordStateInHistory];
846 813
847 // Build the array of sessions. Copy the session objects as the saving will 814 // Build the array of sessions. Copy the session objects as the saving will
848 // be done on a separate thread. 815 // be done on a separate thread.
849 // TODO(crbug.com/661986): This could get expensive especially since this 816 // TODO(crbug.com/661986): This could get expensive especially since this
850 // window may never be saved (if another call comes in before the delay). 817 // window may never be saved (if another call comes in before the delay).
851 SessionWindowIOS* window = [[[SessionWindowIOS alloc] init] autorelease]; 818 SessionWindowIOS* window = [[[SessionWindowIOS alloc] init] autorelease];
852 for (Tab* tab in self) { 819 for (Tab* tab in self) {
853 web::WebState* webState = tab.webState; 820 web::WebState* webState = tab.webState;
854 DCHECK(webState); 821 DCHECK(webState);
855 [window addSerializedSessionStorage:webState->BuildSessionStorage()]; 822 [window addSerializedSessionStorage:webState->BuildSessionStorage()];
856 } 823 }
857 window.selectedIndex = [self indexOfTab:_currentTab]; 824 window.selectedIndex = [self indexOfTab:self.currentTab];
858 return window; 825 return window;
859 } 826 }
860 827
861 - (BOOL)isNTPTab:(Tab*)tab { 828 - (BOOL)isNTPTab:(Tab*)tab {
862 std::string host = tab.url.host(); 829 std::string host = tab.url.host();
863 return host == kChromeUINewTabHost || host == kChromeUIBookmarksHost; 830 return host == kChromeUINewTabHost || host == kChromeUIBookmarksHost;
864 } 831 }
865 832
866 - (void)changeSelectedTabFrom:(Tab*)oldTab
867 to:(Tab*)newTab
868 persistState:(BOOL)persist {
869 if (oldTab) {
870 // Save state, such as scroll position, before switching tabs.
871 if (oldTab != newTab && persist)
872 [oldTab recordStateInHistory];
873 [self postNotificationName:kTabModelTabDeselectedNotification
874 withTab:oldTab];
875 }
876
877 // No Tab to select (e.g. the last Tab has been closed).
878 if ([self indexOfTab:newTab] == NSNotFound)
879 return;
880
881 _currentTab.reset(newTab);
882 if (newTab) {
883 [_observers tabModel:self
884 didChangeActiveTab:newTab
885 previousTab:oldTab
886 atIndex:[self indexOfTab:newTab]];
887 [newTab updateLastVisitedTimestamp];
888 ++_openedTabCount;
889 }
890 BOOL loadingFinished = [newTab.webController loadPhase] == web::PAGE_LOADED;
891 if (loadingFinished) {
892 // Persist the session state.
893 [self saveSessionImmediately:NO];
894 }
895 }
896
897 - (void)updateSnapshotCache:(Tab*)tab {
898 NSMutableSet* set = [NSMutableSet set];
899 NSUInteger index = [self indexOfTab:tab];
900 if (index > 0) {
901 Tab* previousTab = [self tabAtIndex:(index - 1)];
902 [set addObject:previousTab.tabId];
903 }
904 if (index < self.count - 1) {
905 Tab* nextTab = [self tabAtIndex:(index + 1)];
906 [set addObject:nextTab.tabId];
907 }
908 [SnapshotCache sharedInstance].pinnedIDs = set;
909 }
910
911 - (void)postNotificationName:(NSString*)notificationName withTab:(Tab*)tab { 833 - (void)postNotificationName:(NSString*)notificationName withTab:(Tab*)tab {
912 // A scoped_nsobject is used rather than an NSDictionary with static 834 // A scoped_nsobject is used rather than an NSDictionary with static
913 // initializer dictionaryWithObject, because that approach adds the dictionary 835 // initializer dictionaryWithObject, because that approach adds the dictionary
914 // to the autorelease pool, which in turn holds Tab alive longer than 836 // to the autorelease pool, which in turn holds Tab alive longer than
915 // necessary. 837 // necessary.
916 base::scoped_nsobject<NSDictionary> userInfo( 838 base::scoped_nsobject<NSDictionary> userInfo(
917 [[NSDictionary alloc] initWithObjectsAndKeys:tab, kTabModelTabKey, nil]); 839 [[NSDictionary alloc] initWithObjectsAndKeys:tab, kTabModelTabKey, nil]);
918 [[NSNotificationCenter defaultCenter] postNotificationName:notificationName 840 [[NSNotificationCenter defaultCenter] postNotificationName:notificationName
919 object:self 841 object:self
920 userInfo:userInfo]; 842 userInfo:userInfo];
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
971 DCHECK(opener.webState); 893 DCHECK(opener.webState);
972 _webStateList.SetOpenerOfWebStateAt(index, opener.webState); 894 _webStateList.SetOpenerOfWebStateAt(index, opener.webState);
973 } 895 }
974 } 896 }
975 897
976 // Update the selected tab if there was a selected Tab in the saved session. 898 // Update the selected tab if there was a selected Tab in the saved session.
977 if (window.selectedIndex != NSNotFound) { 899 if (window.selectedIndex != NSNotFound) {
978 NSUInteger selectedIndex = window.selectedIndex + oldCount; 900 NSUInteger selectedIndex = window.selectedIndex + oldCount;
979 DCHECK_LT(selectedIndex, self.count); 901 DCHECK_LT(selectedIndex, self.count);
980 DCHECK([self tabAtIndex:selectedIndex]); 902 DCHECK([self tabAtIndex:selectedIndex]);
981 [self changeSelectedTabFrom:_currentTab 903
982 to:[self tabAtIndex:selectedIndex] 904 if (persistState && self.currentTab)
983 persistState:persistState]; 905 [self.currentTab recordStateInHistory];
906 _webStateList.ActivateWebStateAt(static_cast<int>(selectedIndex));
984 } 907 }
985 908
986 // If there was only one tab and it was the new tab page, clobber it. 909 // If there was only one tab and it was the new tab page, clobber it.
987 BOOL closedNTPTab = NO; 910 BOOL closedNTPTab = NO;
988 if (oldCount == 1) { 911 if (oldCount == 1) {
989 Tab* tab = [self tabAtIndex:0]; 912 Tab* tab = [self tabAtIndex:0];
990 if (tab.url == GURL(kChromeUINewTabURL)) { 913 if (tab.url == GURL(kChromeUINewTabURL)) {
991 [self closeTab:tab]; 914 [self closeTab:tab];
992 closedNTPTab = YES; 915 closedNTPTab = YES;
993 oldCount = 0; 916 oldCount = 0;
994 } 917 }
995 } 918 }
996 if (_tabUsageRecorder) { 919 if (_tabUsageRecorder) {
997 NSMutableArray<Tab*>* restoredTabs = 920 NSMutableArray<Tab*>* restoredTabs =
998 [NSMutableArray arrayWithCapacity:_webStateList.count() - oldCount]; 921 [NSMutableArray arrayWithCapacity:_webStateList.count() - oldCount];
999 for (int index = oldCount; index < _webStateList.count(); ++index) { 922 for (int index = oldCount; index < _webStateList.count(); ++index) {
1000 web::WebState* webState = _webStateList.GetWebStateAt(index); 923 web::WebState* webState = _webStateList.GetWebStateAt(index);
1001 [restoredTabs addObject:LegacyTabHelper::GetTabForWebState(webState)]; 924 [restoredTabs addObject:LegacyTabHelper::GetTabForWebState(webState)];
1002 } 925 }
1003 _tabUsageRecorder->InitialRestoredTabs(_currentTab, restoredTabs); 926 _tabUsageRecorder->InitialRestoredTabs(self.currentTab, restoredTabs);
1004 } 927 }
1005 return closedNTPTab; 928 return closedNTPTab;
1006 } 929 }
1007 930
1008 #pragma mark - Notification Handlers 931 #pragma mark - Notification Handlers
1009 932
1010 // Called when UIApplicationWillResignActiveNotification is received. 933 // Called when UIApplicationWillResignActiveNotification is received.
1011 - (void)willResignActive:(NSNotification*)notify { 934 - (void)willResignActive:(NSNotification*)notify {
1012 if (webUsageEnabled_ && _currentTab) { 935 if (webUsageEnabled_ && self.currentTab) {
1013 [[SnapshotCache sharedInstance] 936 [[SnapshotCache sharedInstance]
1014 willBeSavedGreyWhenBackgrounding:_currentTab.get().tabId]; 937 willBeSavedGreyWhenBackgrounding:self.currentTab.tabId];
1015 } 938 }
1016 } 939 }
1017 940
1018 // Called when UIApplicationDidEnterBackgroundNotification is received. 941 // Called when UIApplicationDidEnterBackgroundNotification is received.
1019 - (void)applicationDidEnterBackground:(NSNotification*)notify { 942 - (void)applicationDidEnterBackground:(NSNotification*)notify {
1020 if (!_browserState) 943 if (!_browserState)
1021 return; 944 return;
1022 945
1023 // Evict all the certificate policies except for the current entries of the 946 // Evict all the certificate policies except for the current entries of the
1024 // active sessions. 947 // active sessions.
1025 CleanCertificatePolicyCache( 948 CleanCertificatePolicyCache(
1026 &_clearPoliciesTaskTracker, 949 &_clearPoliciesTaskTracker,
1027 web::WebThread::GetTaskRunnerForThread(web::WebThread::IO), 950 web::WebThread::GetTaskRunnerForThread(web::WebThread::IO),
1028 web::BrowserState::GetCertificatePolicyCache(_browserState), 951 web::BrowserState::GetCertificatePolicyCache(_browserState),
1029 &_webStateList); 952 &_webStateList);
1030 953
1031 if (_tabUsageRecorder) 954 if (_tabUsageRecorder)
1032 _tabUsageRecorder->AppDidEnterBackground(); 955 _tabUsageRecorder->AppDidEnterBackground();
1033 956
1034 // Normally, the session is saved after some timer expires but since the app 957 // Normally, the session is saved after some timer expires but since the app
1035 // is about to enter the background send YES to save the session immediately. 958 // is about to enter the background send YES to save the session immediately.
1036 [self saveSessionImmediately:YES]; 959 [self saveSessionImmediately:YES];
1037 960
1038 // Write out a grey version of the current website to disk. 961 // Write out a grey version of the current website to disk.
1039 if (webUsageEnabled_ && _currentTab) { 962 if (webUsageEnabled_ && self.currentTab) {
1040 [[SnapshotCache sharedInstance] 963 [[SnapshotCache sharedInstance]
1041 saveGreyInBackgroundForSessionID:_currentTab.get().tabId]; 964 saveGreyInBackgroundForSessionID:self.currentTab.tabId];
1042 } 965 }
1043 } 966 }
1044 967
1045 // Called when UIApplicationWillEnterForegroundNotification is received. 968 // Called when UIApplicationWillEnterForegroundNotification is received.
1046 - (void)applicationWillEnterForeground:(NSNotification*)notify { 969 - (void)applicationWillEnterForeground:(NSNotification*)notify {
1047 if (_tabUsageRecorder) { 970 if (_tabUsageRecorder) {
1048 _tabUsageRecorder->AppWillEnterForeground(); 971 _tabUsageRecorder->AppWillEnterForeground();
1049 } 972 }
1050 } 973 }
1051 974
(...skipping 20 matching lines...) Expand all
1072 web::NavigationManager::WebLoadParams params(URL); 995 web::NavigationManager::WebLoadParams params(URL);
1073 params.referrer = referrer; 996 params.referrer = referrer;
1074 params.transition_type = ui::PAGE_TRANSITION_TYPED; 997 params.transition_type = ui::PAGE_TRANSITION_TYPED;
1075 [[tab webController] loadWithParams:params]; 998 [[tab webController] loadWithParams:params];
1076 [tab webController].webUsageEnabled = webUsageEnabled_; 999 [tab webController].webUsageEnabled = webUsageEnabled_;
1077 [self insertTab:tab atIndex:index opener:parentTab]; 1000 [self insertTab:tab atIndex:index opener:parentTab];
1078 return tab; 1001 return tab;
1079 } 1002 }
1080 1003
1081 @end 1004 @end
OLDNEW
« no previous file with comments | « ios/chrome/browser/tabs/tab.mm ('k') | ios/chrome/browser/tabs/tab_model_observers_bridge.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698