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

Side by Side Diff: chrome/browser/ui/intents/web_intent_picker_controller.cc

Issue 10204010: Handling default service in the web intents picker controller. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 8 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 | Annotate | Revision Log
OLDNEW
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
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
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(&params); 318 browser::Navigate(&params);
287 } 319 }
288 320
289 void WebIntentPickerController::OnSuggestionsLinkClicked() { 321 void WebIntentPickerController::OnSuggestionsLinkClicked() {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698