Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 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/intents/web_intent_picker_controller.h" | 5 #include "chrome/browser/ui/intents/web_intent_picker_controller.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
| 11 #include "base/memory/scoped_ptr.h" | 11 #include "base/memory/scoped_ptr.h" |
| 12 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
| 13 #include "chrome/browser/extensions/webstore_installer.h" | 13 #include "chrome/browser/extensions/webstore_installer.h" |
| 14 #include "chrome/browser/favicon/favicon_service.h" | 14 #include "chrome/browser/favicon/favicon_service.h" |
| 15 #include "chrome/browser/intents/default_web_intent_service.h" | 15 #include "chrome/browser/intents/default_web_intent_service.h" |
| 16 #include "chrome/browser/intents/web_intents_registry_factory.h" | 16 #include "chrome/browser/intents/web_intents_registry_factory.h" |
| 17 #include "chrome/browser/intents/cws_intents_registry_factory.h" | 17 #include "chrome/browser/intents/cws_intents_registry_factory.h" |
| 18 #include "chrome/browser/profiles/profile.h" | 18 #include "chrome/browser/profiles/profile.h" |
| 19 #include "chrome/browser/tab_contents/tab_util.h" | 19 #include "chrome/browser/tab_contents/tab_util.h" |
| 20 #include "chrome/browser/tabs/tab_strip_model.h" | 20 #include "chrome/browser/tabs/tab_strip_model.h" |
| 21 #include "chrome/browser/ui/browser.h" | 21 #include "chrome/browser/ui/browser.h" |
| 22 #include "chrome/browser/ui/browser_list.h" | 22 #include "chrome/browser/ui/browser_list.h" |
| 23 #include "chrome/browser/ui/browser_navigator.h" | 23 #include "chrome/browser/ui/browser_navigator.h" |
| 24 #include "chrome/browser/ui/intents/web_intent_picker.h" | 24 #include "chrome/browser/ui/intents/web_intent_picker.h" |
| 25 #include "chrome/browser/ui/intents/web_intent_picker_model.h" | 25 #include "chrome/browser/ui/intents/web_intent_picker_model.h" |
| 26 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" | 26 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| 27 #include "chrome/browser/webdata/web_data_service.h" | 27 #include "chrome/browser/webdata/web_data_service.h" |
| 28 #include "chrome/common/chrome_notification_types.h" | 28 #include "chrome/common/chrome_notification_types.h" |
| 29 #include "chrome/common/url_constants.h" | |
| 29 #include "content/public/browser/browser_thread.h" | 30 #include "content/public/browser/browser_thread.h" |
| 30 #include "content/public/browser/navigation_controller.h" | 31 #include "content/public/browser/navigation_controller.h" |
| 31 #include "content/public/browser/notification_source.h" | 32 #include "content/public/browser/notification_source.h" |
| 32 #include "content/public/browser/web_contents.h" | 33 #include "content/public/browser/web_contents.h" |
| 33 #include "content/public/browser/web_intents_dispatcher.h" | 34 #include "content/public/browser/web_intents_dispatcher.h" |
| 34 #include "content/public/common/url_fetcher.h" | 35 #include "content/public/common/url_fetcher.h" |
| 35 #include "content/public/common/url_fetcher_delegate.h" | 36 #include "content/public/common/url_fetcher_delegate.h" |
| 36 #include "grit/generated_resources.h" | 37 #include "grit/generated_resources.h" |
| 37 #include "net/base/load_flags.h" | 38 #include "net/base/load_flags.h" |
| 38 #include "skia/ext/image_operations.h" | 39 #include "skia/ext/image_operations.h" |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 157 intents_dispatcher_ = intents_dispatcher; | 158 intents_dispatcher_ = intents_dispatcher; |
| 158 intents_dispatcher_->RegisterReplyNotification( | 159 intents_dispatcher_->RegisterReplyNotification( |
| 159 base::Bind(&WebIntentPickerController::OnSendReturnMessage, | 160 base::Bind(&WebIntentPickerController::OnSendReturnMessage, |
| 160 weak_ptr_factory_.GetWeakPtr())); | 161 weak_ptr_factory_.GetWeakPtr())); |
| 161 } | 162 } |
| 162 | 163 |
| 163 void WebIntentPickerController::ShowDialog(Browser* browser, | 164 void WebIntentPickerController::ShowDialog(Browser* browser, |
| 164 const string16& action, | 165 const string16& action, |
| 165 const string16& type) { | 166 const string16& type) { |
| 166 // Only show a picker once. | 167 // Only show a picker once. |
| 167 if (picker_shown_) | 168 // ??? Is this good enough? There's a hole if we don't create the picker |
| 168 return; | 169 // in this method, but only after disk retrieval. |
| 169 | |
| 170 // TODO(binji): Figure out what to do when intents are invoked from incognito | 170 // TODO(binji): Figure out what to do when intents are invoked from incognito |
| 171 // mode. | 171 // mode. |
| 172 if (wrapper_->profile()->IsOffTheRecord()) | 172 if (picker_shown_ || wrapper_->profile()->IsOffTheRecord()) { |
| 173 if (intents_dispatcher_) { | |
| 174 intents_dispatcher_->SendReplyMessage( | |
| 175 webkit_glue::WEB_INTENT_REPLY_FAILURE, ASCIIToUTF16("")); | |
| 176 } | |
| 173 return; | 177 return; |
| 178 } | |
| 174 | 179 |
| 180 browser_ = browser; | |
| 181 action_ = action; | |
| 175 picker_model_->Clear(); | 182 picker_model_->Clear(); |
| 176 picker_model_->set_action(action); | 183 picker_model_->set_action(action); |
| 177 picker_model_->set_mimetype(type); | 184 picker_model_->set_mimetype(type); |
| 178 | 185 |
| 179 // If picker is non-NULL, it was set by a test. | 186 // If the intent is explicit, skip showing the picker. |
| 180 if (picker_ == NULL) { | 187 if (intents_dispatcher_) { |
| 181 picker_ = WebIntentPicker::Create(browser, wrapper_, this, | 188 const GURL& service = intents_dispatcher_->GetIntent().service; |
| 182 picker_model_.get()); | 189 // TODO(gbillock): When we can parse pages for the intent tag, |
| 190 // take out this requirement that explicit intents dispatch to | |
| 191 // extension urls. | |
| 192 if (!service.is_valid() || !service.SchemeIs(chrome::kExtensionScheme)) { | |
| 193 intents_dispatcher_->SendReplyMessage( | |
| 194 webkit_glue::WEB_INTENT_REPLY_FAILURE, ASCIIToUTF16( | |
| 195 "Only extension urls are supported for explicit invocation")); | |
| 196 return; | |
| 197 } | |
| 198 | |
| 199 // We get services from the registry because that must retrieve the | |
| 200 // registered extension page for this action/type if it is permitted to be | |
| 201 // dispatched. | |
| 202 pending_async_count_++; | |
| 203 GetWebIntentsRegistry(wrapper_)->GetIntentServices( | |
| 204 action, type, base::Bind( | |
| 205 &WebIntentPickerController::WebIntentServicesForExplicitIntent, | |
| 206 weak_ptr_factory_.GetWeakPtr())); | |
| 207 return; | |
| 183 } | 208 } |
| 184 | 209 |
| 185 picker_->SetActionString(GetIntentActionString(UTF16ToUTF8(action))); | 210 pending_async_count_ += 2; |
|
groby-ooo-7-16
2012/04/24 21:36:51
Why exactly do we keep a pending count? (Nobody im
Greg Billock
2012/04/25 16:04:32
I thought it was used to guide the operation of th
| |
| 211 pending_registry_calls_count_ += 1; | |
|
groby-ooo-7-16
2012/04/24 21:36:51
Why add 1 here? We already do that when we call th
Greg Billock
2012/04/25 16:04:32
There's now two registry callbacks we need to wait
| |
| 186 | 212 |
| 187 picker_shown_ = true; | |
| 188 pending_async_count_+= 2; | |
| 189 GetWebIntentsRegistry(wrapper_)->GetIntentServices( | 213 GetWebIntentsRegistry(wrapper_)->GetIntentServices( |
| 190 action, type, | 214 action, type, |
| 191 base::Bind(&WebIntentPickerController::OnWebIntentServicesAvailable, | 215 base::Bind(&WebIntentPickerController::OnWebIntentServicesAvailable, |
| 192 weak_ptr_factory_.GetWeakPtr())); | 216 weak_ptr_factory_.GetWeakPtr())); |
| 217 | |
| 218 GURL invoking_url = wrapper_->web_contents()->GetURL(); | |
| 219 if (invoking_url.is_valid()) { | |
| 220 pending_async_count_++; | |
| 221 pending_registry_calls_count_++; | |
| 222 GetWebIntentsRegistry(wrapper_)->GetDefaultIntentService( | |
| 223 action, type, invoking_url, | |
| 224 base::Bind(&WebIntentPickerController::OnWebIntentDefaultsAvailable, | |
| 225 weak_ptr_factory_.GetWeakPtr())); | |
| 226 } | |
| 227 | |
| 193 GetCWSIntentsRegistry(wrapper_)->GetIntentServices( | 228 GetCWSIntentsRegistry(wrapper_)->GetIntentServices( |
| 194 action, type, | 229 action, type, |
| 195 base::Bind(&WebIntentPickerController::OnCWSIntentServicesAvailable, | 230 base::Bind(&WebIntentPickerController::OnCWSIntentServicesAvailable, |
| 196 weak_ptr_factory_.GetWeakPtr())); | 231 weak_ptr_factory_.GetWeakPtr())); |
| 197 } | 232 } |
| 198 | 233 |
| 199 void WebIntentPickerController::Observe( | 234 void WebIntentPickerController::Observe( |
| 200 int type, | 235 int type, |
| 201 const content::NotificationSource& source, | 236 const content::NotificationSource& source, |
| 202 const content::NotificationDetails& details) { | 237 const content::NotificationDetails& details) { |
| 203 DCHECK(type == content::NOTIFICATION_LOAD_START || | 238 DCHECK(type == content::NOTIFICATION_LOAD_START || |
| 204 type == chrome::NOTIFICATION_TAB_CLOSING); | 239 type == chrome::NOTIFICATION_TAB_CLOSING); |
| 205 ClosePicker(); | 240 ClosePicker(); |
| 206 } | 241 } |
| 207 | 242 |
| 208 void WebIntentPickerController::OnServiceChosen(const GURL& url, | 243 void WebIntentPickerController::OnServiceChosen(const GURL& url, |
| 209 Disposition disposition) { | 244 Disposition disposition) { |
| 210 switch (disposition) { | 245 switch (disposition) { |
| 211 case WebIntentPickerModel::DISPOSITION_INLINE: | 246 case WebIntentPickerModel::DISPOSITION_INLINE: |
| 212 // Set the model to inline disposition. It will notify the picker which | 247 // Set the model to inline disposition. It will notify the picker which |
| 213 // will respond (via OnInlineDispositionWebContentsCreated) with the | 248 // will respond (via OnInlineDispositionWebContentsCreated) with the |
| 214 // WebContents to dispatch the intent to. | 249 // WebContents to dispatch the intent to. |
| 215 picker_model_->SetInlineDisposition(url); | 250 picker_model_->SetInlineDisposition(url); |
| 216 break; | 251 break; |
| 217 | 252 |
| 218 case WebIntentPickerModel::DISPOSITION_WINDOW: { | 253 case WebIntentPickerModel::DISPOSITION_WINDOW: { |
| 219 // TODO(gbillock): This really only handles the 'window' disposition in a | |
| 220 // quite prototype way. We need to flesh out what happens to the picker | |
| 221 // during the lifetime of the service url context, and that may mean we | |
| 222 // need to pass more information into the injector to find the picker | |
| 223 // again and close it. | |
| 224 int index = TabStripModel::kNoTab; | 254 int index = TabStripModel::kNoTab; |
| 255 // TODO(gbillock): use browser_? | |
|
groby-ooo-7-16
2012/04/24 21:36:51
I believe there has been a CL (or there is one in
Greg Billock
2012/04/25 16:04:32
got rid of this. I'll add a todo to scrap the Show
| |
| 225 Browser* browser = Browser::GetBrowserForController( | 256 Browser* browser = Browser::GetBrowserForController( |
| 226 &wrapper_->web_contents()->GetController(), &index); | 257 &wrapper_->web_contents()->GetController(), &index); |
| 227 TabContentsWrapper* contents = Browser::TabContentsFactory( | 258 TabContentsWrapper* contents = Browser::TabContentsFactory( |
| 228 browser->profile(), | 259 browser->profile(), |
| 229 tab_util::GetSiteInstanceForNewTab( | 260 tab_util::GetSiteInstanceForNewTab( |
| 230 NULL, browser->profile(), url), | 261 NULL, browser->profile(), url), |
| 231 MSG_ROUTING_NONE, NULL, NULL); | 262 MSG_ROUTING_NONE, NULL, NULL); |
| 232 | 263 |
| 233 intents_dispatcher_->DispatchIntent(contents->web_contents()); | 264 intents_dispatcher_->DispatchIntent(contents->web_contents()); |
| 234 service_tab_ = contents->web_contents(); | 265 service_tab_ = contents->web_contents(); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 270 wrapper_->profile(), this, &wrapper_->web_contents()->GetController(), id, | 301 wrapper_->profile(), this, &wrapper_->web_contents()->GetController(), id, |
| 271 scoped_ptr<WebstoreInstaller::Approval>(NULL), | 302 scoped_ptr<WebstoreInstaller::Approval>(NULL), |
| 272 WebstoreInstaller::FLAG_INLINE_INSTALL); | 303 WebstoreInstaller::FLAG_INLINE_INSTALL); |
| 273 | 304 |
| 274 pending_async_count_++; | 305 pending_async_count_++; |
| 275 installer->Start(); | 306 installer->Start(); |
| 276 } | 307 } |
| 277 | 308 |
| 278 void WebIntentPickerController::OnExtensionLinkClicked(const std::string& id) { | 309 void WebIntentPickerController::OnExtensionLinkClicked(const std::string& id) { |
| 279 // Navigate from source tab. | 310 // Navigate from source tab. |
| 311 // TODO(gbillock): use browser_? | |
|
groby-ooo-7-16
2012/04/24 21:36:51
See above
Greg Billock
2012/04/25 16:04:32
Done.
| |
| 280 Browser* browser = | 312 Browser* browser = |
| 281 BrowserList::FindBrowserWithWebContents(wrapper_->web_contents()); | 313 BrowserList::FindBrowserWithWebContents(wrapper_->web_contents()); |
| 282 GURL extension_url(extension_urls::GetWebstoreItemDetailURLPrefix() + id); | 314 GURL extension_url(extension_urls::GetWebstoreItemDetailURLPrefix() + id); |
| 283 browser::NavigateParams params(browser, extension_url, | 315 browser::NavigateParams params(browser, extension_url, |
| 284 content::PAGE_TRANSITION_AUTO_BOOKMARK); | 316 content::PAGE_TRANSITION_AUTO_BOOKMARK); |
| 285 params.disposition = NEW_FOREGROUND_TAB; | 317 params.disposition = NEW_FOREGROUND_TAB; |
| 286 browser::Navigate(¶ms); | 318 browser::Navigate(¶ms); |
| 287 } | 319 } |
| 288 | 320 |
| 289 void WebIntentPickerController::OnSuggestionsLinkClicked() { | 321 void WebIntentPickerController::OnSuggestionsLinkClicked() { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 338 AsyncOperationFinished(); | 370 AsyncOperationFinished(); |
| 339 } | 371 } |
| 340 | 372 |
| 341 void WebIntentPickerController::OnSendReturnMessage( | 373 void WebIntentPickerController::OnSendReturnMessage( |
| 342 webkit_glue::WebIntentReplyType reply_type) { | 374 webkit_glue::WebIntentReplyType reply_type) { |
| 343 ClosePicker(); | 375 ClosePicker(); |
| 344 | 376 |
| 345 if (service_tab_ && | 377 if (service_tab_ && |
| 346 reply_type != webkit_glue::WEB_INTENT_SERVICE_CONTENTS_CLOSED) { | 378 reply_type != webkit_glue::WEB_INTENT_SERVICE_CONTENTS_CLOSED) { |
| 347 int index = TabStripModel::kNoTab; | 379 int index = TabStripModel::kNoTab; |
| 380 // TODO(gbillock): use browser_? | |
|
groby-ooo-7-16
2012/04/24 21:36:51
See above
Greg Billock
2012/04/25 16:04:32
Done.
| |
| 348 Browser* browser = Browser::GetBrowserForController( | 381 Browser* browser = Browser::GetBrowserForController( |
| 349 &service_tab_->GetController(), &index); | 382 &service_tab_->GetController(), &index); |
| 350 if (browser) { | 383 if (browser) { |
| 351 browser->tabstrip_model()->CloseTabContentsAt( | 384 browser->tabstrip_model()->CloseTabContentsAt( |
| 352 index, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB); | 385 index, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB); |
| 353 | 386 |
| 354 // Activate source tab. | 387 // Activate source tab. |
| 355 Browser* source_browser = | 388 Browser* source_browser = |
| 356 BrowserList::FindBrowserWithWebContents(wrapper_->web_contents()); | 389 BrowserList::FindBrowserWithWebContents(wrapper_->web_contents()); |
| 357 if (source_browser) { | 390 if (source_browser) { |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 379 FaviconService::Handle handle = favicon_service->GetFaviconForURL( | 412 FaviconService::Handle handle = favicon_service->GetFaviconForURL( |
| 380 services[i].service_url, | 413 services[i].service_url, |
| 381 history::FAVICON, | 414 history::FAVICON, |
| 382 &favicon_consumer_, | 415 &favicon_consumer_, |
| 383 base::Bind( | 416 base::Bind( |
| 384 &WebIntentPickerController::OnFaviconDataAvailable, | 417 &WebIntentPickerController::OnFaviconDataAvailable, |
| 385 weak_ptr_factory_.GetWeakPtr())); | 418 weak_ptr_factory_.GetWeakPtr())); |
| 386 favicon_consumer_.SetClientData(favicon_service, handle, i); | 419 favicon_consumer_.SetClientData(favicon_service, handle, i); |
| 387 } | 420 } |
| 388 | 421 |
| 422 RegistryCallsCompleted(); | |
|
groby-ooo-7-16
2012/04/24 21:36:51
Why do we flag registry calls completed here, not
Greg Billock
2012/04/25 16:04:32
Bad name. This is the method we want to happen whe
| |
| 389 AsyncOperationFinished(); | 423 AsyncOperationFinished(); |
| 390 } | 424 } |
| 391 | 425 |
| 426 void WebIntentPickerController::WebIntentServicesForExplicitIntent( | |
| 427 const std::vector<webkit_glue::WebIntentServiceData>& services) { | |
| 428 DCHECK(intents_dispatcher_); | |
| 429 DCHECK(intents_dispatcher_->GetIntent().service.is_valid()); | |
| 430 for (size_t i = 0; i < services.size(); ++i) { | |
| 431 if (services[i].service_url != intents_dispatcher_->GetIntent().service) | |
| 432 continue; | |
| 433 | |
| 434 if (services[i].disposition == | |
| 435 webkit_glue::WebIntentServiceData::DISPOSITION_INLINE) | |
| 436 CreatePicker(); | |
|
groby-ooo-7-16
2012/04/24 21:36:51
This is more of a TBD, but I really think we need
Greg Billock
2012/04/25 16:04:32
Makes sense.
| |
| 437 OnServiceChosen(services[i].service_url, | |
| 438 ConvertDisposition(services[i].disposition)); | |
| 439 return; | |
| 440 } | |
| 441 | |
| 442 // We did not find an acceptable extension. The intent cannot | |
| 443 // be dispatched. | |
| 444 intents_dispatcher_->SendReplyMessage( | |
| 445 webkit_glue::WEB_INTENT_REPLY_FAILURE, ASCIIToUTF16( | |
| 446 "Explicit extension URL is not available.")); | |
| 447 | |
| 448 // Finished. | |
| 449 AsyncOperationFinished(); | |
| 450 } | |
| 451 | |
| 452 void WebIntentPickerController::OnWebIntentDefaultsAvailable( | |
| 453 const DefaultWebIntentService& default_service) { | |
| 454 if (!default_service.service_url.empty()) { | |
| 455 DCHECK(default_service.suppression == 0); | |
| 456 default_service_url_ = default_service.service_url; | |
| 457 } | |
| 458 | |
| 459 RegistryCallsCompleted(); | |
| 460 AsyncOperationFinished(); | |
| 461 } | |
| 462 | |
| 463 void WebIntentPickerController::RegistryCallsCompleted() { | |
| 464 if (--pending_registry_calls_count_ != 0) return; | |
| 465 | |
| 466 if (!default_service_url_.empty()) { | |
| 467 // If there's a default service, dispatch to it immediately | |
| 468 // without showing the picker. | |
| 469 const WebIntentPickerModel::InstalledService* default_service = | |
| 470 picker_model_->GetInstalledServiceWithURL(GURL(default_service_url_)); | |
| 471 | |
| 472 if (default_service != NULL) { | |
| 473 if (default_service->disposition == | |
| 474 WebIntentPickerModel::DISPOSITION_INLINE) | |
| 475 CreatePicker(); | |
| 476 OnServiceChosen(default_service->url, default_service->disposition); | |
| 477 return; | |
| 478 } | |
| 479 } | |
| 480 | |
| 481 CreatePicker(); | |
| 482 picker_->SetActionString(GetIntentActionString(UTF16ToUTF8(action_))); | |
| 483 | |
| 484 // TODO(gbillock): handle the case of having only one service -- set | |
| 485 // the make-default checkbox to "true" upon display. | |
| 486 } | |
| 487 | |
| 392 void WebIntentPickerController::OnFaviconDataAvailable( | 488 void WebIntentPickerController::OnFaviconDataAvailable( |
| 393 FaviconService::Handle handle, history::FaviconData favicon_data) { | 489 FaviconService::Handle handle, history::FaviconData favicon_data) { |
| 394 size_t index = favicon_consumer_.GetClientDataForCurrentRequest(); | 490 size_t index = favicon_consumer_.GetClientDataForCurrentRequest(); |
| 395 if (favicon_data.is_valid()) { | 491 if (favicon_data.is_valid()) { |
| 396 SkBitmap icon_bitmap; | 492 SkBitmap icon_bitmap; |
| 397 | 493 |
| 398 if (gfx::PNGCodec::Decode(favicon_data.image_data->front(), | 494 if (gfx::PNGCodec::Decode(favicon_data.image_data->front(), |
| 399 favicon_data.image_data->size(), | 495 favicon_data.image_data->size(), |
| 400 &icon_bitmap)) { | 496 &icon_bitmap)) { |
| 401 gfx::Image icon_image(new SkBitmap(icon_bitmap)); | 497 gfx::Image icon_image(new SkBitmap(icon_bitmap)); |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 542 } | 638 } |
| 543 | 639 |
| 544 void WebIntentPickerController::AsyncOperationFinished() { | 640 void WebIntentPickerController::AsyncOperationFinished() { |
| 545 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 641 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 546 if (--pending_async_count_ == 0) { | 642 if (--pending_async_count_ == 0) { |
| 547 if (picker_) | 643 if (picker_) |
| 548 picker_->OnPendingAsyncCompleted(); | 644 picker_->OnPendingAsyncCompleted(); |
| 549 } | 645 } |
| 550 } | 646 } |
| 551 | 647 |
| 648 void WebIntentPickerController::CreatePicker() { | |
| 649 // If picker is non-NULL, it was set by a test. | |
| 650 // Use browser_? | |
| 651 Browser* browser = | |
| 652 BrowserList::FindBrowserWithWebContents(wrapper_->web_contents()); | |
| 653 if (picker_ == NULL) { | |
| 654 picker_ = WebIntentPicker::Create(browser, wrapper_, this, | |
| 655 picker_model_.get()); | |
| 656 } | |
| 657 picker_shown_ = true; | |
| 658 } | |
| 659 | |
| 552 void WebIntentPickerController::ClosePicker() { | 660 void WebIntentPickerController::ClosePicker() { |
| 553 if (picker_) | 661 if (picker_) |
| 554 picker_->Close(); | 662 picker_->Close(); |
| 555 } | 663 } |
| OLD | NEW |