Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 <list> | 7 #include <list> |
| 8 #include <utility> | 8 #include <utility> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 150 // The |index| parameter can be set to | 150 // The |index| parameter can be set to |
| 151 // TabModelConstants::kTabPositionAutomatically if the caller doesn't have a | 151 // TabModelConstants::kTabPositionAutomatically if the caller doesn't have a |
| 152 // preference for the position of the tab. | 152 // preference for the position of the tab. |
| 153 - (Tab*)insertTabWithLoadParams: | 153 - (Tab*)insertTabWithLoadParams: |
| 154 (const web::NavigationManager::WebLoadParams&)params | 154 (const web::NavigationManager::WebLoadParams&)params |
| 155 windowName:(NSString*)windowName | 155 windowName:(NSString*)windowName |
| 156 opener:(Tab*)parentTab | 156 opener:(Tab*)parentTab |
| 157 openedByDOM:(BOOL)openedByDOM | 157 openedByDOM:(BOOL)openedByDOM |
| 158 atIndex:(NSUInteger)index | 158 atIndex:(NSUInteger)index |
| 159 inBackground:(BOOL)inBackground; | 159 inBackground:(BOOL)inBackground; |
| 160 | |
| 160 // Call to switch the selected tab. Broadcasts about the change in selection. | 161 // Call to switch the selected tab. Broadcasts about the change in selection. |
| 161 // It's ok for |newTab| to be nil in case the last tab is going away. In that | 162 // It's ok for |newTab| to be nil in case the last tab is going away. In that |
| 162 // case, the "tab deselected" notification gets sent, but no corresponding | 163 // case, the "tab deselected" notification gets sent, but no corresponding |
| 163 // "tab selected" notification is sent. |persist| indicates whether or not | 164 // "tab selected" notification is sent. |persist| indicates whether or not |
| 164 // the tab's state should be persisted in history upon switching. | 165 // the tab's state should be persisted in history upon switching. |
| 165 - (void)changeSelectedTabFrom:(Tab*)oldTab | 166 - (void)changeSelectedTabFrom:(Tab*)oldTab |
| 166 to:(Tab*)newTab | 167 to:(Tab*)newTab |
| 167 persistState:(BOOL)persist; | 168 persistState:(BOOL)persist; |
| 169 | |
| 168 // Tells the snapshot cache the adjacent tab session ids. | 170 // Tells the snapshot cache the adjacent tab session ids. |
| 169 - (void)updateSnapshotCache:(Tab*)tab; | 171 - (void)updateSnapshotCache:(Tab*)tab; |
| 172 | |
| 170 // Helper method that posts a notification with the given name with |tab| | 173 // Helper method that posts a notification with the given name with |tab| |
| 171 // in the userInfo dictionary under the kTabModelTabKey. | 174 // in the userInfo dictionary under the kTabModelTabKey. |
| 172 - (void)postNotificationName:(NSString*)notificationName withTab:(Tab*)tab; | 175 - (void)postNotificationName:(NSString*)notificationName withTab:(Tab*)tab; |
| 176 | |
| 177 // Helper method to restore a saved session and control if the state should | |
| 178 // be persisted or not. Used to implement the public -restoreSessionWindow: | |
| 179 // method and restoring session in the initialiser. | |
| 180 - (BOOL)restoreSessionWindow:(SessionWindowIOS*)window | |
| 181 persistState:(BOOL)persistState; | |
| 182 | |
| 173 @end | 183 @end |
| 174 | 184 |
| 175 @implementation TabModel | 185 @implementation TabModel |
| 176 | 186 |
| 177 @synthesize browserState = _browserState; | 187 @synthesize browserState = _browserState; |
| 178 @synthesize sessionID = _sessionID; | 188 @synthesize sessionID = _sessionID; |
| 179 @synthesize webUsageEnabled = webUsageEnabled_; | 189 @synthesize webUsageEnabled = webUsageEnabled_; |
| 180 | 190 |
| 181 #pragma mark - Overriden | 191 #pragma mark - Overriden |
| 182 | 192 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 249 // Normal browser states are the only ones to get tab restore. Tab sync | 259 // Normal browser states are the only ones to get tab restore. Tab sync |
| 250 // handles incognito browser states by filtering on profile, so it's | 260 // handles incognito browser states by filtering on profile, so it's |
| 251 // important to the backend code to always have a sync window delegate. | 261 // important to the backend code to always have a sync window delegate. |
| 252 if (!_browserState->IsOffTheRecord()) { | 262 if (!_browserState->IsOffTheRecord()) { |
| 253 // Set up the usage recorder before tabs are created. | 263 // Set up the usage recorder before tabs are created. |
| 254 _tabUsageRecorder.reset(new TabUsageRecorder(self)); | 264 _tabUsageRecorder.reset(new TabUsageRecorder(self)); |
| 255 } | 265 } |
| 256 _syncedWindowDelegate.reset(new TabModelSyncedWindowDelegate(self)); | 266 _syncedWindowDelegate.reset(new TabModelSyncedWindowDelegate(self)); |
| 257 | 267 |
| 258 _tabs.reset([[NSMutableArray alloc] init]); | 268 _tabs.reset([[NSMutableArray alloc] init]); |
| 259 NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter]; | |
| 260 if (window) { | 269 if (window) { |
| 261 web::WebState::CreateParams params(_browserState); | 270 // Restore the session and reset the session metrics (as the event have |
| 262 for (CRWNavigationManagerStorage* session in window.sessions) { | 271 // not been generated by the user but by a cold start cycle). |
| 263 std::unique_ptr<web::WebState> webState = | 272 [self restoreSessionWindow:window persistState:NO]; |
|
rohitrao (ping after 24h)
2017/02/06 13:45:40
Is it worth DCHECKing that _observers is still emp
sdefresne
2017/02/06 14:10:45
The only code path that can lead to adding observe
rohitrao (ping after 24h)
2017/02/06 14:15:57
As an example, what would happen if we modified _t
sdefresne
2017/02/06 14:34:02
Called public method on an object that is not init
| |
| 264 web::WebState::Create(params, session); | 273 [self resetSessionMetrics]; |
|
rohitrao (ping after 24h)
2017/02/06 13:45:40
This was another difference between the two functi
sdefresne
2017/02/06 14:10:45
Done.
| |
| 265 DCHECK_EQ(webState->GetBrowserState(), _browserState); | |
| 266 // Restore the CertificatePolicyCache. | |
| 267 UpdateCertificatePolicyCacheFromWebState(webState.get()); | |
| 268 // Create a new tab for each entry in the window. Don't send delegate | |
| 269 // notifications for each restored tab, only when all done. | |
| 270 base::scoped_nsobject<Tab> tab( | |
| 271 [[Tab alloc] initWithWebState:std::move(webState) model:self]); | |
| 272 [tab webController].usePlaceholderOverlay = YES; | |
| 273 [tab fetchFavicon]; | |
| 274 [_tabs addObject:tab]; | |
| 275 | |
| 276 TabParentingGlobalObserver::GetInstance()->OnTabParented( | |
| 277 tab.get().webState); | |
| 278 } | |
| 279 if ([_tabs count]) { | |
| 280 DCHECK(window.selectedIndex < [_tabs count]); | |
| 281 _currentTab.reset([self tabAtIndex:window.selectedIndex]); | |
| 282 DCHECK(_currentTab); | |
| 283 if (_tabUsageRecorder) | |
| 284 _tabUsageRecorder->InitialRestoredTabs(_currentTab, _tabs); | |
| 285 // Perform initializations for affiliated objects which update the | |
| 286 // session information related to the current tab. | |
| 287 [_currentTab updateLastVisitedTimestamp]; | |
| 288 [self saveSessionImmediately:NO]; | |
| 289 } | |
| 290 } | 274 } |
| 291 | 275 |
| 292 _orderController.reset( | 276 _orderController.reset( |
| 293 [[TabModelOrderController alloc] initWithTabModel:self]); | 277 [[TabModelOrderController alloc] initWithTabModel:self]); |
| 278 | |
| 294 // Register for resign active notification. | 279 // Register for resign active notification. |
| 295 [defaultCenter addObserver:self | 280 [[NSNotificationCenter defaultCenter] |
| 296 selector:@selector(willResignActive:) | 281 addObserver:self |
| 297 name:UIApplicationWillResignActiveNotification | 282 selector:@selector(willResignActive:) |
| 298 object:nil]; | 283 name:UIApplicationWillResignActiveNotification |
| 284 object:nil]; | |
| 299 // Register for background notification. | 285 // Register for background notification. |
| 300 [defaultCenter addObserver:self | 286 [[NSNotificationCenter defaultCenter] |
| 301 selector:@selector(applicationDidEnterBackground:) | 287 addObserver:self |
| 302 name:UIApplicationDidEnterBackgroundNotification | 288 selector:@selector(applicationDidEnterBackground:) |
| 303 object:nil]; | 289 name:UIApplicationDidEnterBackgroundNotification |
| 290 object:nil]; | |
| 304 // Register for foregrounding notification. | 291 // Register for foregrounding notification. |
| 305 [defaultCenter addObserver:self | 292 [[NSNotificationCenter defaultCenter] |
| 306 selector:@selector(applicationWillEnterForeground:) | 293 addObserver:self |
| 307 name:UIApplicationWillEnterForegroundNotification | 294 selector:@selector(applicationWillEnterForeground:) |
| 308 object:nil]; | 295 name:UIApplicationWillEnterForegroundNotification |
| 296 object:nil]; | |
| 309 | 297 |
| 310 // Associate with ios::ChromeBrowserState. | 298 // Associate with ios::ChromeBrowserState. |
| 311 RegisterTabModelWithChromeBrowserState(_browserState, self); | 299 RegisterTabModelWithChromeBrowserState(_browserState, self); |
| 312 } | 300 } |
| 313 return self; | 301 return self; |
| 314 } | 302 } |
| 315 | 303 |
| 316 - (instancetype)init { | 304 - (instancetype)init { |
| 317 NOTREACHED(); | 305 NOTREACHED(); |
| 318 return nil; | 306 return nil; |
| 319 } | 307 } |
| 320 | 308 |
| 321 - (BOOL)restoreSessionWindow:(SessionWindowIOS*)window { | 309 - (BOOL)restoreSessionWindow:(SessionWindowIOS*)window { |
| 322 DCHECK(_browserState); | 310 return [self restoreSessionWindow:window persistState:YES]; |
| 323 DCHECK(window); | |
| 324 NSArray* sessions = window.sessions; | |
| 325 if (!sessions.count) | |
| 326 return NO; | |
| 327 size_t oldCount = [_tabs count]; | |
| 328 size_t index = oldCount; | |
| 329 web::WebState::CreateParams params(_browserState); | |
| 330 for (CRWNavigationManagerStorage* session in sessions) { | |
| 331 std::unique_ptr<web::WebState> webState = | |
| 332 web::WebState::Create(params, session); | |
| 333 DCHECK_EQ(webState->GetBrowserState(), _browserState); | |
| 334 Tab* tab = [self insertTabWithWebState:std::move(webState) atIndex:index++]; | |
| 335 tab.webController.usePlaceholderOverlay = YES; | |
| 336 // Restore the CertificatePolicyCache. Note that after calling Pass() | |
| 337 // |webState| is invalid, so we need to get the webstate from |tab|. | |
| 338 UpdateCertificatePolicyCacheFromWebState(tab.webState); | |
| 339 } | |
| 340 DCHECK([_tabs count] > oldCount); | |
| 341 // If any tab was restored, the saved selected tab must be selected. | |
| 342 if ([_tabs count] > oldCount) { | |
| 343 NSUInteger selectedIndex = window.selectedIndex; | |
| 344 if (selectedIndex == NSNotFound) | |
| 345 selectedIndex = oldCount; | |
| 346 else | |
| 347 selectedIndex += oldCount; | |
| 348 DCHECK(selectedIndex < [_tabs count]); | |
| 349 Tab* newTab = [self tabAtIndex:selectedIndex]; | |
| 350 DCHECK(newTab); | |
| 351 [self changeSelectedTabFrom:_currentTab to:newTab persistState:YES]; | |
| 352 | |
| 353 // If there was only one tab and it was the new tab page, clobber it. | |
| 354 if (oldCount == 1) { | |
| 355 Tab* tab = [_tabs objectAtIndex:0]; | |
| 356 if (tab.url == GURL(kChromeUINewTabURL)) { | |
| 357 [self closeTab:tab]; | |
| 358 if (_tabUsageRecorder) | |
| 359 _tabUsageRecorder->InitialRestoredTabs(_currentTab, _tabs); | |
| 360 return YES; | |
| 361 } | |
| 362 } | |
| 363 if (_tabUsageRecorder) { | |
| 364 _tabUsageRecorder->InitialRestoredTabs( | |
| 365 _currentTab, | |
| 366 [_tabs subarrayWithRange:NSMakeRange(oldCount, | |
| 367 [_tabs count] - oldCount)]); | |
| 368 } | |
| 369 } | |
| 370 return NO; | |
| 371 } | 311 } |
| 372 | 312 |
| 373 - (void)saveSessionImmediately:(BOOL)immediately { | 313 - (void)saveSessionImmediately:(BOOL)immediately { |
| 374 // Do nothing if there are tabs in the model but no selected tab. This is | 314 // Do nothing if there are tabs in the model but no selected tab. This is |
| 375 // a transitional state. | 315 // a transitional state. |
| 376 if ((!_currentTab && [_tabs count]) || !_browserState) | 316 if ((!_currentTab && [_tabs count]) || !_browserState) |
| 377 return; | 317 return; |
| 378 [_sessionService saveWindow:self.windowForSavingSession | 318 [_sessionService saveWindow:self.windowForSavingSession |
| 379 forBrowserState:_browserState | 319 forBrowserState:_browserState |
| 380 immediately:immediately]; | 320 immediately:immediately]; |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 574 [self insertTab:tab atIndex:index]; | 514 [self insertTab:tab atIndex:index]; |
| 575 return tab; | 515 return tab; |
| 576 } | 516 } |
| 577 | 517 |
| 578 - (void)insertTab:(Tab*)tab atIndex:(NSUInteger)index { | 518 - (void)insertTab:(Tab*)tab atIndex:(NSUInteger)index { |
| 579 DCHECK(tab); | 519 DCHECK(tab); |
| 580 DCHECK(index <= [_tabs count]); | 520 DCHECK(index <= [_tabs count]); |
| 581 [tab fetchFavicon]; | 521 [tab fetchFavicon]; |
| 582 [_tabs insertObject:tab atIndex:index]; | 522 [_tabs insertObject:tab atIndex:index]; |
| 583 | 523 |
| 524 TabParentingGlobalObserver::GetInstance()->OnTabParented(tab.webState); | |
|
rohitrao (ping after 24h)
2017/02/06 13:45:40
This is called a lot more often now, isn't it? It
sdefresne
2017/02/06 14:10:45
The method should have been called here too. The m
rohitrao (ping after 24h)
2017/02/06 14:15:57
I looked at the callsites as well and decided that
sdefresne
2017/02/06 14:34:02
Sure, done => https://codereview.chromium.org/2678
| |
| 584 [_observers tabModel:self didInsertTab:tab atIndex:index inForeground:NO]; | 525 [_observers tabModel:self didInsertTab:tab atIndex:index inForeground:NO]; |
| 585 [_observers tabModelDidChangeTabCount:self]; | 526 [_observers tabModelDidChangeTabCount:self]; |
| 586 | 527 |
| 587 base::RecordAction(base::UserMetricsAction("MobileNewTabOpened")); | 528 base::RecordAction(base::UserMetricsAction("MobileNewTabOpened")); |
| 588 // Persist the session due to a new tab being inserted. If this is a | 529 // Persist the session due to a new tab being inserted. If this is a |
| 589 // background tab (will not become active), saving now will capture the | 530 // background tab (will not become active), saving now will capture the |
| 590 // state properly. If it does eventually become active, another save will | 531 // state properly. If it does eventually become active, another save will |
| 591 // be triggered to properly capture the end result. | 532 // be triggered to properly capture the end result. |
| 592 [self saveSessionImmediately:NO]; | 533 [self saveSessionImmediately:NO]; |
| 593 ++_newTabCount; | 534 ++_newTabCount; |
| (...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 993 // initializer dictionaryWithObject, because that approach adds the dictionary | 934 // initializer dictionaryWithObject, because that approach adds the dictionary |
| 994 // to the autorelease pool, which in turn holds Tab alive longer than | 935 // to the autorelease pool, which in turn holds Tab alive longer than |
| 995 // necessary. | 936 // necessary. |
| 996 base::scoped_nsobject<NSDictionary> userInfo( | 937 base::scoped_nsobject<NSDictionary> userInfo( |
| 997 [[NSDictionary alloc] initWithObjectsAndKeys:tab, kTabModelTabKey, nil]); | 938 [[NSDictionary alloc] initWithObjectsAndKeys:tab, kTabModelTabKey, nil]); |
| 998 [[NSNotificationCenter defaultCenter] postNotificationName:notificationName | 939 [[NSNotificationCenter defaultCenter] postNotificationName:notificationName |
| 999 object:self | 940 object:self |
| 1000 userInfo:userInfo]; | 941 userInfo:userInfo]; |
| 1001 } | 942 } |
| 1002 | 943 |
| 944 - (BOOL)restoreSessionWindow:(SessionWindowIOS*)window | |
| 945 persistState:(BOOL)persistState { | |
| 946 DCHECK(_browserState); | |
| 947 DCHECK(window); | |
| 948 | |
| 949 NSArray* sessions = window.sessions; | |
| 950 if (!sessions.count) | |
| 951 return NO; | |
| 952 | |
| 953 size_t oldCount = [_tabs count]; | |
| 954 web::WebState::CreateParams params(_browserState); | |
| 955 | |
| 956 for (CRWNavigationManagerStorage* session in sessions) { | |
| 957 std::unique_ptr<web::WebState> webState = | |
| 958 web::WebState::Create(params, session); | |
| 959 DCHECK_EQ(webState->GetBrowserState(), _browserState); | |
| 960 Tab* tab = | |
| 961 [self insertTabWithWebState:std::move(webState) atIndex:[_tabs count]]; | |
| 962 tab.webController.usePlaceholderOverlay = YES; | |
| 963 | |
| 964 // Restore the CertificatePolicyCache (note that webState is invalid after | |
| 965 // passing it via move semantic to -insertTabWithWebState:atIndex:). | |
| 966 UpdateCertificatePolicyCacheFromWebState(tab.webState); | |
| 967 } | |
| 968 DCHECK_GT([_tabs count], oldCount); | |
| 969 | |
| 970 // Update the selected tab if there was a selected Tab in the saved session. | |
| 971 if (window.selectedIndex != NSNotFound) { | |
| 972 NSUInteger selectedIndex = window.selectedIndex + oldCount; | |
| 973 DCHECK_LT(selectedIndex, [_tabs count]); | |
| 974 DCHECK([self tabAtIndex:selectedIndex]); | |
| 975 [self changeSelectedTabFrom:_currentTab | |
| 976 to:[self tabAtIndex:selectedIndex] | |
| 977 persistState:persistState]; | |
| 978 } | |
| 979 | |
| 980 // If there was only one tab and it was the new tab page, clobber it. | |
| 981 BOOL closedNTPTab = NO; | |
| 982 if (oldCount == 1) { | |
| 983 Tab* tab = [_tabs objectAtIndex:0]; | |
| 984 if (tab.url == GURL(kChromeUINewTabURL)) { | |
| 985 [self closeTab:tab]; | |
| 986 closedNTPTab = YES; | |
| 987 oldCount = 0; | |
| 988 } | |
| 989 } | |
| 990 if (_tabUsageRecorder) { | |
| 991 _tabUsageRecorder->InitialRestoredTabs( | |
| 992 _currentTab, | |
| 993 [_tabs | |
| 994 subarrayWithRange:NSMakeRange(oldCount, [_tabs count] - oldCount)]); | |
| 995 } | |
| 996 return closedNTPTab; | |
| 997 } | |
| 998 | |
| 1003 #pragma mark - Notification Handlers | 999 #pragma mark - Notification Handlers |
| 1004 | 1000 |
| 1005 // Called when UIApplicationWillResignActiveNotification is received. | 1001 // Called when UIApplicationWillResignActiveNotification is received. |
| 1006 - (void)willResignActive:(NSNotification*)notify { | 1002 - (void)willResignActive:(NSNotification*)notify { |
| 1007 if (webUsageEnabled_ && _currentTab) { | 1003 if (webUsageEnabled_ && _currentTab) { |
| 1008 [[SnapshotCache sharedInstance] | 1004 [[SnapshotCache sharedInstance] |
| 1009 willBeSavedGreyWhenBackgrounding:_currentTab.get().tabId]; | 1005 willBeSavedGreyWhenBackgrounding:_currentTab.get().tabId]; |
| 1010 } | 1006 } |
| 1011 } | 1007 } |
| 1012 | 1008 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1073 web::NavigationManager::WebLoadParams params(URL); | 1069 web::NavigationManager::WebLoadParams params(URL); |
| 1074 params.referrer = referrer; | 1070 params.referrer = referrer; |
| 1075 params.transition_type = ui::PAGE_TRANSITION_TYPED; | 1071 params.transition_type = ui::PAGE_TRANSITION_TYPED; |
| 1076 [[tab webController] loadWithParams:params]; | 1072 [[tab webController] loadWithParams:params]; |
| 1077 [tab webController].webUsageEnabled = webUsageEnabled_; | 1073 [tab webController].webUsageEnabled = webUsageEnabled_; |
| 1078 [self insertTab:tab atIndex:index]; | 1074 [self insertTab:tab atIndex:index]; |
| 1079 return tab; | 1075 return tab; |
| 1080 } | 1076 } |
| 1081 | 1077 |
| 1082 @end | 1078 @end |
| OLD | NEW |