Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 #include "chrome/browser/ui/webui/signin/inline_login_handler_impl.h" | 5 #include "chrome/browser/ui/webui/signin/inline_login_handler_impl.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 40 public SigninOAuthHelper::Consumer { | 40 public SigninOAuthHelper::Consumer { |
| 41 public: | 41 public: |
| 42 InlineSigninHelper( | 42 InlineSigninHelper( |
| 43 base::WeakPtr<InlineLoginHandlerImpl> handler, | 43 base::WeakPtr<InlineLoginHandlerImpl> handler, |
| 44 net::URLRequestContextGetter* getter, | 44 net::URLRequestContextGetter* getter, |
| 45 Profile* profile, | 45 Profile* profile, |
| 46 const GURL& current_url, | 46 const GURL& current_url, |
| 47 const std::string& email, | 47 const std::string& email, |
| 48 const std::string& password, | 48 const std::string& password, |
| 49 const std::string& session_index, | 49 const std::string& session_index, |
| 50 bool choose_what_to_sync); | 50 bool choose_what_to_sync, |
| 51 bool confirm_untrusted_signin); | |
| 51 | 52 |
| 52 private: | 53 private: |
| 53 // Overriden from SigninOAuthHelper::Consumer. | 54 // Overriden from SigninOAuthHelper::Consumer. |
| 54 virtual void OnSigninOAuthInformationAvailable( | 55 virtual void OnSigninOAuthInformationAvailable( |
| 55 const std::string& email, | 56 const std::string& email, |
| 56 const std::string& display_email, | 57 const std::string& display_email, |
| 57 const std::string& refresh_token) OVERRIDE; | 58 const std::string& refresh_token) OVERRIDE; |
| 58 virtual void OnSigninOAuthInformationFailure( | 59 virtual void OnSigninOAuthInformationFailure( |
| 59 const GoogleServiceAuthError& error) OVERRIDE; | 60 const GoogleServiceAuthError& error) OVERRIDE; |
| 60 | 61 |
| 61 base::WeakPtr<InlineLoginHandlerImpl> handler_; | 62 base::WeakPtr<InlineLoginHandlerImpl> handler_; |
| 62 Profile* profile_; | 63 Profile* profile_; |
| 63 GURL current_url_; | 64 GURL current_url_; |
| 64 std::string email_; | 65 std::string email_; |
| 65 std::string password_; | 66 std::string password_; |
| 66 std::string session_index_; | 67 std::string session_index_; |
| 67 bool choose_what_to_sync_; | 68 bool choose_what_to_sync_; |
| 69 bool confirm_untrusted_signin_; | |
| 68 | 70 |
| 69 DISALLOW_COPY_AND_ASSIGN(InlineSigninHelper); | 71 DISALLOW_COPY_AND_ASSIGN(InlineSigninHelper); |
| 70 }; | 72 }; |
| 71 | 73 |
| 72 InlineSigninHelper::InlineSigninHelper( | 74 InlineSigninHelper::InlineSigninHelper( |
| 73 base::WeakPtr<InlineLoginHandlerImpl> handler, | 75 base::WeakPtr<InlineLoginHandlerImpl> handler, |
| 74 net::URLRequestContextGetter* getter, | 76 net::URLRequestContextGetter* getter, |
| 75 Profile* profile, | 77 Profile* profile, |
| 76 const GURL& current_url, | 78 const GURL& current_url, |
| 77 const std::string& email, | 79 const std::string& email, |
| 78 const std::string& password, | 80 const std::string& password, |
| 79 const std::string& session_index, | 81 const std::string& session_index, |
| 80 bool choose_what_to_sync) | 82 bool choose_what_to_sync, |
| 83 bool confirm_untrusted_signin) | |
| 81 : SigninOAuthHelper(getter, session_index, this), | 84 : SigninOAuthHelper(getter, session_index, this), |
| 82 handler_(handler), | 85 handler_(handler), |
| 83 profile_(profile), | 86 profile_(profile), |
| 84 current_url_(current_url), | 87 current_url_(current_url), |
| 85 email_(email), | 88 email_(email), |
| 86 password_(password), | 89 password_(password), |
| 87 session_index_(session_index), | 90 session_index_(session_index), |
| 88 choose_what_to_sync_(choose_what_to_sync) { | 91 choose_what_to_sync_(choose_what_to_sync), |
| 92 confirm_untrusted_signin_(confirm_untrusted_signin) { | |
| 89 DCHECK(profile_); | 93 DCHECK(profile_); |
| 90 DCHECK(!email_.empty()); | 94 DCHECK(!email_.empty()); |
| 91 DCHECK(!session_index_.empty()); | 95 DCHECK(!session_index_.empty()); |
| 92 } | 96 } |
| 93 | 97 |
| 94 void InlineSigninHelper::OnSigninOAuthInformationAvailable( | 98 void InlineSigninHelper::OnSigninOAuthInformationAvailable( |
| 95 const std::string& email, | 99 const std::string& email, |
| 96 const std::string& display_email, | 100 const std::string& display_email, |
| 97 const std::string& refresh_token) { | 101 const std::string& refresh_token) { |
| 98 content::WebContents* contents = NULL; | 102 content::WebContents* contents = NULL; |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 126 SigninErrorController* error_controller = | 130 SigninErrorController* error_controller = |
| 127 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)-> | 131 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)-> |
| 128 signin_error_controller(); | 132 signin_error_controller(); |
| 129 OneClickSigninSyncStarter::StartSyncMode start_mode = | 133 OneClickSigninSyncStarter::StartSyncMode start_mode = |
| 130 source == signin::SOURCE_SETTINGS || choose_what_to_sync_ ? | 134 source == signin::SOURCE_SETTINGS || choose_what_to_sync_ ? |
| 131 (error_controller->HasError() && | 135 (error_controller->HasError() && |
| 132 sync_service && sync_service->HasSyncSetupCompleted()) ? | 136 sync_service && sync_service->HasSyncSetupCompleted()) ? |
| 133 OneClickSigninSyncStarter::SHOW_SETTINGS_WITHOUT_CONFIGURE : | 137 OneClickSigninSyncStarter::SHOW_SETTINGS_WITHOUT_CONFIGURE : |
| 134 OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST : | 138 OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST : |
| 135 OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS; | 139 OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS; |
| 136 OneClickSigninSyncStarter::ConfirmationRequired confirmation_required = | 140 |
| 137 source == signin::SOURCE_SETTINGS || | 141 OneClickSigninSyncStarter::ConfirmationRequired confirmation_required; |
| 138 source == signin::SOURCE_WEBSTORE_INSTALL || | 142 if (confirm_untrusted_signin_) { |
| 139 choose_what_to_sync_ ? | 143 confirmation_required = |
| 140 OneClickSigninSyncStarter::NO_CONFIRMATION : | 144 OneClickSigninSyncStarter::CONFIRM_UNTRUSTED_SIGNIN; |
| 141 OneClickSigninSyncStarter::CONFIRM_AFTER_SIGNIN; | 145 } else { |
| 146 confirmation_required = | |
| 147 source == signin::SOURCE_SETTINGS || | |
| 148 source == signin::SOURCE_WEBSTORE_INSTALL || | |
| 149 choose_what_to_sync_ ? | |
| 150 OneClickSigninSyncStarter::NO_CONFIRMATION : | |
| 151 OneClickSigninSyncStarter::CONFIRM_AFTER_SIGNIN; | |
| 152 } | |
| 142 | 153 |
| 143 bool start_signin = | 154 bool start_signin = |
| 144 !OneClickSigninHelper::HandleCrossAccountError( | 155 !OneClickSigninHelper::HandleCrossAccountError( |
| 145 contents, "", | 156 contents, "", |
| 146 email, password_, refresh_token, | 157 email, password_, refresh_token, |
| 147 OneClickSigninHelper::AUTO_ACCEPT_EXPLICIT, | 158 OneClickSigninHelper::AUTO_ACCEPT_EXPLICIT, |
| 148 source, start_mode, | 159 source, start_mode, |
| 149 base::Bind(&InlineLoginHandlerImpl::SyncStarterCallback, | 160 base::Bind(&InlineLoginHandlerImpl::SyncStarterCallback, |
| 150 handler_)); | 161 handler_)); |
| 151 if (start_signin) { | 162 if (start_signin) { |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 172 | 183 |
| 173 AboutSigninInternals* about_signin_internals = | 184 AboutSigninInternals* about_signin_internals = |
| 174 AboutSigninInternalsFactory::GetForProfile(profile_); | 185 AboutSigninInternalsFactory::GetForProfile(profile_); |
| 175 about_signin_internals->OnRefreshTokenReceived("Failure"); | 186 about_signin_internals->OnRefreshTokenReceived("Failure"); |
| 176 | 187 |
| 177 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); | 188 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); |
| 178 } | 189 } |
| 179 | 190 |
| 180 } // namespace | 191 } // namespace |
| 181 | 192 |
| 182 InlineLoginHandlerImpl::InlineLoginHandlerImpl() | 193 InlineLoginHandlerImpl::InlineLoginHandlerImpl() : weak_factory_(this) {} |
| 183 : weak_factory_(this), | |
| 184 choose_what_to_sync_(false) { | |
| 185 } | |
| 186 | 194 |
| 187 InlineLoginHandlerImpl::~InlineLoginHandlerImpl() {} | 195 InlineLoginHandlerImpl::~InlineLoginHandlerImpl() {} |
| 188 | 196 |
| 189 void InlineLoginHandlerImpl::SetExtraInitParams(base::DictionaryValue& params) { | 197 void InlineLoginHandlerImpl::SetExtraInitParams(base::DictionaryValue& params) { |
| 190 params.SetString("service", "chromiumsync"); | 198 params.SetString("service", "chromiumsync"); |
| 191 | 199 |
| 192 signin::Source source = | 200 signin::Source source = |
| 193 signin::GetSourceForPromoURL(web_ui()->GetWebContents()->GetURL()); | 201 signin::GetSourceForPromoURL(web_ui()->GetWebContents()->GetURL()); |
| 194 OneClickSigninHelper::LogHistogramValue( | 202 OneClickSigninHelper::LogHistogramValue( |
| 195 source, one_click_signin::HISTOGRAM_SHOWN); | 203 source, one_click_signin::HISTOGRAM_SHOWN); |
| 196 } | 204 } |
| 197 | 205 |
| 198 void InlineLoginHandlerImpl::CompleteLogin(const base::ListValue* args) { | 206 void InlineLoginHandlerImpl::CompleteLogin(const base::ListValue* args) { |
| 199 content::WebContents* contents = web_ui()->GetWebContents(); | 207 content::WebContents* contents = web_ui()->GetWebContents(); |
| 200 const GURL& current_url = contents->GetURL(); | 208 const GURL& current_url = contents->GetURL(); |
| 201 | 209 |
| 202 const base::DictionaryValue* dict = NULL; | 210 const base::DictionaryValue* dict = NULL; |
| 203 args->GetDictionary(0, &dict); | 211 args->GetDictionary(0, &dict); |
| 204 | 212 |
| 205 bool skip_for_now = false; | 213 bool skip_for_now = false; |
| 206 dict->GetBoolean("skipForNow", &skip_for_now); | 214 dict->GetBoolean("skipForNow", &skip_for_now); |
| 207 if (skip_for_now) { | 215 if (skip_for_now) { |
| 208 signin::SetUserSkippedPromo(Profile::FromWebUI(web_ui())); | 216 signin::SetUserSkippedPromo(Profile::FromWebUI(web_ui())); |
| 209 SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE); | 217 SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE); |
| 210 return; | 218 return; |
| 211 } | 219 } |
| 212 | 220 |
| 213 base::string16 email; | 221 base::string16 email_string16; |
| 214 dict->GetString("email", &email); | 222 dict->GetString("email", &email_string16); |
| 215 DCHECK(!email.empty()); | 223 DCHECK(!email_string16.empty()); |
| 216 email_ = base::UTF16ToASCII(email); | 224 std::string email(base::UTF16ToASCII(email_string16)); |
| 217 base::string16 password; | 225 |
| 218 dict->GetString("password", &password); | 226 base::string16 password_string16; |
| 219 password_ = base::UTF16ToASCII(password); | 227 dict->GetString("password", &password_string16); |
| 228 std::string password(base::UTF16ToASCII(password_string16)); | |
| 220 | 229 |
| 221 // When doing a SAML sign in, this email check may result in a false | 230 // When doing a SAML sign in, this email check may result in a false |
| 222 // positive. This happens when the user types one email address in the | 231 // positive. This happens when the user types one email address in the |
| 223 // gaia sign in page, but signs in to a different account in the SAML sign in | 232 // gaia sign in page, but signs in to a different account in the SAML sign in |
| 224 // page. | 233 // page. |
| 225 std::string default_email; | 234 std::string default_email; |
| 226 std::string validate_email; | 235 std::string validate_email; |
| 227 if (net::GetValueForKeyInQuery(current_url, "email", &default_email) && | 236 if (net::GetValueForKeyInQuery(current_url, "email", &default_email) && |
| 228 net::GetValueForKeyInQuery(current_url, "validateEmail", | 237 net::GetValueForKeyInQuery(current_url, "validateEmail", |
| 229 &validate_email) && | 238 &validate_email) && |
| 230 validate_email == "1") { | 239 validate_email == "1") { |
| 231 if (!gaia::AreEmailsSame(email_, default_email)) { | 240 if (!gaia::AreEmailsSame(email, default_email)) { |
| 232 SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE); | 241 SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE); |
| 233 return; | 242 return; |
| 234 } | 243 } |
| 235 } | 244 } |
| 236 | 245 |
| 237 base::string16 session_index; | 246 base::string16 session_index_string16; |
| 238 dict->GetString("sessionIndex", &session_index); | 247 dict->GetString("sessionIndex", &session_index_string16); |
| 239 session_index_ = base::UTF16ToASCII(session_index); | 248 std::string session_index = base::UTF16ToASCII(session_index_string16); |
| 240 DCHECK(!session_index_.empty()); | 249 DCHECK(!session_index.empty()); |
| 241 dict->GetBoolean("chooseWhatToSync", &choose_what_to_sync_); | 250 |
| 251 bool choose_what_to_sync = false; | |
| 252 dict->GetBoolean("chooseWhatToSync", &choose_what_to_sync); | |
| 253 bool confirm_untrusted_signin = false; | |
| 254 dict->GetBoolean("confirmUntrustedSignin", &confirm_untrusted_signin); | |
|
nasko
2014/06/10 16:29:41
Does this value come from the renderer? If yes, th
| |
| 242 | 255 |
| 243 signin::Source source = signin::GetSourceForPromoURL(current_url); | 256 signin::Source source = signin::GetSourceForPromoURL(current_url); |
| 244 OneClickSigninHelper::LogHistogramValue( | 257 OneClickSigninHelper::LogHistogramValue( |
| 245 source, one_click_signin::HISTOGRAM_ACCEPTED); | 258 source, one_click_signin::HISTOGRAM_ACCEPTED); |
| 246 bool switch_to_advanced = | 259 bool switch_to_advanced = |
| 247 choose_what_to_sync_ && (source != signin::SOURCE_SETTINGS); | 260 choose_what_to_sync && (source != signin::SOURCE_SETTINGS); |
| 248 OneClickSigninHelper::LogHistogramValue( | 261 OneClickSigninHelper::LogHistogramValue( |
| 249 source, | 262 source, |
| 250 switch_to_advanced ? one_click_signin::HISTOGRAM_WITH_ADVANCED : | 263 switch_to_advanced ? one_click_signin::HISTOGRAM_WITH_ADVANCED : |
| 251 one_click_signin::HISTOGRAM_WITH_DEFAULTS); | 264 one_click_signin::HISTOGRAM_WITH_DEFAULTS); |
| 252 | 265 |
| 253 OneClickSigninHelper::CanOfferFor can_offer_for = | 266 OneClickSigninHelper::CanOfferFor can_offer_for = |
| 254 OneClickSigninHelper::CAN_OFFER_FOR_ALL; | 267 OneClickSigninHelper::CAN_OFFER_FOR_ALL; |
| 255 switch (source) { | 268 switch (source) { |
| 256 case signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT: | 269 case signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT: |
| 257 can_offer_for = OneClickSigninHelper::CAN_OFFER_FOR_SECONDARY_ACCOUNT; | 270 can_offer_for = OneClickSigninHelper::CAN_OFFER_FOR_SECONDARY_ACCOUNT; |
| 258 break; | 271 break; |
| 259 case signin::SOURCE_REAUTH: { | 272 case signin::SOURCE_REAUTH: { |
| 260 std::string primary_username = | 273 std::string primary_username = |
| 261 SigninManagerFactory::GetForProfile( | 274 SigninManagerFactory::GetForProfile( |
| 262 Profile::FromWebUI(web_ui()))->GetAuthenticatedUsername(); | 275 Profile::FromWebUI(web_ui()))->GetAuthenticatedUsername(); |
| 263 if (!gaia::AreEmailsSame(default_email, primary_username)) | 276 if (!gaia::AreEmailsSame(default_email, primary_username)) |
| 264 can_offer_for = OneClickSigninHelper::CAN_OFFER_FOR_SECONDARY_ACCOUNT; | 277 can_offer_for = OneClickSigninHelper::CAN_OFFER_FOR_SECONDARY_ACCOUNT; |
| 265 break; | 278 break; |
| 266 } | 279 } |
| 267 default: | 280 default: |
| 268 // No need to change |can_offer_for|. | 281 // No need to change |can_offer_for|. |
| 269 break; | 282 break; |
| 270 } | 283 } |
| 271 | 284 |
| 272 std::string error_msg; | 285 std::string error_msg; |
| 273 bool can_offer = OneClickSigninHelper::CanOffer( | 286 bool can_offer = OneClickSigninHelper::CanOffer( |
| 274 contents, can_offer_for, email_, &error_msg); | 287 contents, can_offer_for, email, &error_msg); |
| 275 if (!can_offer) { | 288 if (!can_offer) { |
| 276 HandleLoginError(error_msg); | 289 HandleLoginError(error_msg); |
| 277 return; | 290 return; |
| 278 } | 291 } |
| 279 | 292 |
| 280 AboutSigninInternals* about_signin_internals = | 293 AboutSigninInternals* about_signin_internals = |
| 281 AboutSigninInternalsFactory::GetForProfile(Profile::FromWebUI(web_ui())); | 294 AboutSigninInternalsFactory::GetForProfile(Profile::FromWebUI(web_ui())); |
| 282 about_signin_internals->OnAuthenticationResultReceived( | 295 about_signin_internals->OnAuthenticationResultReceived( |
| 283 "GAIA Auth Successful"); | 296 "GAIA Auth Successful"); |
| 284 | 297 |
| 285 content::StoragePartition* partition = | 298 content::StoragePartition* partition = |
| 286 content::BrowserContext::GetStoragePartitionForSite( | 299 content::BrowserContext::GetStoragePartitionForSite( |
| 287 contents->GetBrowserContext(), | 300 contents->GetBrowserContext(), |
| 288 GURL(chrome::kChromeUIChromeSigninURL)); | 301 GURL(chrome::kChromeUIChromeSigninURL)); |
| 289 | 302 |
| 290 // InlineSigninHelper will delete itself. | 303 // InlineSigninHelper will delete itself. |
| 291 new InlineSigninHelper(GetWeakPtr(), partition->GetURLRequestContext(), | 304 new InlineSigninHelper(GetWeakPtr(), partition->GetURLRequestContext(), |
| 292 Profile::FromWebUI(web_ui()), current_url, | 305 Profile::FromWebUI(web_ui()), current_url, |
| 293 email_, password_, session_index_, | 306 email, password, session_index, |
| 294 choose_what_to_sync_); | 307 choose_what_to_sync, confirm_untrusted_signin); |
| 295 | 308 |
| 296 email_.clear(); | |
| 297 password_.clear(); | |
| 298 session_index_.clear(); | |
| 299 web_ui()->CallJavascriptFunction("inline.login.closeDialog"); | 309 web_ui()->CallJavascriptFunction("inline.login.closeDialog"); |
| 300 } | 310 } |
| 301 | 311 |
| 302 void InlineLoginHandlerImpl::HandleLoginError(const std::string& error_msg) { | 312 void InlineLoginHandlerImpl::HandleLoginError(const std::string& error_msg) { |
| 303 SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE); | 313 SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE); |
| 304 | 314 |
| 305 Browser* browser = GetDesktopBrowser(); | 315 Browser* browser = GetDesktopBrowser(); |
| 306 if (browser && !error_msg.empty()) { | 316 if (browser && !error_msg.empty()) { |
| 307 VLOG(1) << "InlineLoginHandlerImpl::HandleLoginError shows error message: " | 317 VLOG(1) << "InlineLoginHandlerImpl::HandleLoginError shows error message: " |
| 308 << error_msg; | 318 << error_msg; |
| 309 OneClickSigninHelper::ShowSigninErrorBubble(browser, error_msg); | 319 OneClickSigninHelper::ShowSigninErrorBubble(browser, error_msg); |
| 310 } | 320 } |
| 311 | |
| 312 email_.clear(); | |
| 313 password_.clear(); | |
| 314 session_index_.clear(); | |
| 315 } | 321 } |
| 316 | 322 |
| 317 Browser* InlineLoginHandlerImpl::GetDesktopBrowser() { | 323 Browser* InlineLoginHandlerImpl::GetDesktopBrowser() { |
| 318 Browser* browser = chrome::FindBrowserWithWebContents( | 324 Browser* browser = chrome::FindBrowserWithWebContents( |
| 319 web_ui()->GetWebContents()); | 325 web_ui()->GetWebContents()); |
| 320 if (!browser) { | 326 if (!browser) { |
| 321 browser = chrome::FindLastActiveWithProfile( | 327 browser = chrome::FindLastActiveWithProfile( |
| 322 Profile::FromWebUI(web_ui()), chrome::GetActiveDesktop()); | 328 Profile::FromWebUI(web_ui()), chrome::GetActiveDesktop()); |
| 323 } | 329 } |
| 324 return browser; | 330 return browser; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 358 TabStripModel* tab_strip_model = browser->tab_strip_model(); | 364 TabStripModel* tab_strip_model = browser->tab_strip_model(); |
| 359 if (tab_strip_model) { | 365 if (tab_strip_model) { |
| 360 int index = tab_strip_model->GetIndexOfWebContents(tab); | 366 int index = tab_strip_model->GetIndexOfWebContents(tab); |
| 361 if (index != TabStripModel::kNoTab) { | 367 if (index != TabStripModel::kNoTab) { |
| 362 tab_strip_model->ExecuteContextMenuCommand( | 368 tab_strip_model->ExecuteContextMenuCommand( |
| 363 index, TabStripModel::CommandCloseTab); | 369 index, TabStripModel::CommandCloseTab); |
| 364 } | 370 } |
| 365 } | 371 } |
| 366 } | 372 } |
| 367 } | 373 } |
| OLD | NEW |