summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbinji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-24 04:58:52 +0000
committerbinji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-24 04:58:52 +0000
commit625d9f8fc428a36e29e6868d3a9bc9f33245d810 (patch)
tree625bd090aa1b5684ff258ea2799c5b6afb1e1bbe
parentf8116b6fd136c5c86eaaede373b0363e77e08646 (diff)
downloadchromium_src-625d9f8fc428a36e29e6868d3a9bc9f33245d810.zip
chromium_src-625d9f8fc428a36e29e6868d3a9bc9f33245d810.tar.gz
chromium_src-625d9f8fc428a36e29e6868d3a9bc9f33245d810.tar.bz2
Web Intent Picker UI (implemented as a constrained dialog, linux only)
BUG=none TEST=none Review URL: http://codereview.chromium.org/7648061 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@97990 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/generated_resources.grd3
-rw-r--r--chrome/browser/ui/cocoa/web_intent_picker_cocoa.mm14
-rw-r--r--chrome/browser/ui/gtk/web_intent_picker_gtk.cc142
-rw-r--r--chrome/browser/ui/gtk/web_intent_picker_gtk.h76
-rw-r--r--chrome/browser/ui/intents/web_intent_constrained_dialog_factory.cc47
-rw-r--r--chrome/browser/ui/intents/web_intent_constrained_dialog_factory.h40
-rw-r--r--chrome/browser/ui/intents/web_intent_picker.h44
-rw-r--r--chrome/browser/ui/intents/web_intent_picker_controller.cc264
-rw-r--r--chrome/browser/ui/intents/web_intent_picker_controller.h97
-rw-r--r--chrome/browser/ui/intents/web_intent_picker_controller_unittest.cc273
-rw-r--r--chrome/browser/ui/intents/web_intent_picker_delegate.h20
-rw-r--r--chrome/browser/ui/intents/web_intent_picker_factory.h26
-rw-r--r--chrome/browser/ui/tab_contents/tab_contents_wrapper.cc7
-rw-r--r--chrome/browser/ui/tab_contents/tab_contents_wrapper.h8
-rw-r--r--chrome/browser/ui/views/web_intent_picker_view.cc14
-rw-r--r--chrome/chrome_browser.gypi11
-rw-r--r--chrome/chrome_tests.gypi1
17 files changed, 1087 insertions, 0 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index fc11849..6b8b0a5 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -13375,6 +13375,9 @@ Keep your key file in a safe place. You will need it to create new versions of y
<message name="IDS_REGISTER_INTENT_HANDLER_DENY" desc="Text to show for the deny button for the register intent handler request infobar.">
No
</message>
+ <message name="IDS_CHOOSE_INTENT_HANDLER_MESSAGE" desc="Text to display when user is choosing a intent handler to respond to a web intent.">
+ Complete action using:
+ </message>
<!-- PDF with unsupported feature Info Bar -->
<message name="IDS_PDF_INFOBAR_QUESTION_READER_INSTALLED" desc="Question asked on the info bar when a user views a PDF with an unsupported feature and they have Adobe Reader installed.">
diff --git a/chrome/browser/ui/cocoa/web_intent_picker_cocoa.mm b/chrome/browser/ui/cocoa/web_intent_picker_cocoa.mm
new file mode 100644
index 0000000..fe96858
--- /dev/null
+++ b/chrome/browser/ui/cocoa/web_intent_picker_cocoa.mm
@@ -0,0 +1,14 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/intents/web_intent_picker.h"
+#include "chrome/browser/ui/intents/web_intent_picker_delegate.h"
+#include "content/browser/tab_contents/tab_contents.h"
+
+// static
+WebIntentPicker* WebIntentPicker::Create(TabContents* tab_contents,
+ WebIntentPickerDelegate* delegate) {
+ // TODO(binji) Implement. See http://crbug.com/93915.
+ return NULL;
+}
diff --git a/chrome/browser/ui/gtk/web_intent_picker_gtk.cc b/chrome/browser/ui/gtk/web_intent_picker_gtk.cc
new file mode 100644
index 0000000..90c7901
--- /dev/null
+++ b/chrome/browser/ui/gtk/web_intent_picker_gtk.cc
@@ -0,0 +1,142 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/gtk/web_intent_picker_gtk.h"
+
+#include "chrome/browser/favicon/favicon_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/gtk/custom_button.h"
+#include "chrome/browser/ui/gtk/gtk_theme_service.h"
+#include "chrome/browser/ui/gtk/gtk_util.h"
+#include "chrome/browser/ui/intents/web_intent_picker_controller.h"
+#include "chrome/browser/ui/intents/web_intent_picker_delegate.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "content/browser/tab_contents/tab_contents.h"
+#include "content/common/content_notification_types.h"
+#include "googleurl/src/gurl.h"
+#include "grit/generated_resources.h"
+#include "grit/ui_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/gtk_util.h"
+#include "ui/gfx/image/image.h"
+
+namespace {
+
+GtkThemeService *GetThemeService(TabContents* tab_contents) {
+ Profile* profile = Profile::FromBrowserContext(
+ tab_contents->browser_context());
+ return GtkThemeService::GetFrom(profile);
+}
+
+} // namespace
+
+// static
+WebIntentPicker* WebIntentPicker::Create(TabContents* tab_contents,
+ WebIntentPickerDelegate* delegate) {
+ return new WebIntentPickerGtk(tab_contents, delegate);
+}
+
+WebIntentPickerGtk::WebIntentPickerGtk(TabContents* tab_contents,
+ WebIntentPickerDelegate* delegate)
+ : tab_contents_(tab_contents),
+ delegate_(delegate),
+ window_(NULL) {
+ DCHECK(delegate_ != NULL);
+ root_.Own(gtk_vbox_new(FALSE, gtk_util::kContentAreaBorder));
+ GtkWidget* hbox = gtk_hbox_new(FALSE, 0);
+ GtkWidget* label = gtk_label_new(
+ l10n_util::GetStringUTF8(IDS_CHOOSE_INTENT_HANDLER_MESSAGE).c_str());
+ gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
+
+ close_button_.reset(
+ CustomDrawButton::CloseButton(GetThemeService(tab_contents_)));
+ g_signal_connect(close_button_->widget(),
+ "clicked",
+ G_CALLBACK(OnCloseButtonClickThunk),
+ this);
+ gtk_widget_set_can_focus(close_button_->widget(), FALSE);
+ gtk_box_pack_end(GTK_BOX(hbox), close_button_->widget(), FALSE, FALSE, 0);
+
+ gtk_box_pack_start(GTK_BOX(root_.get()), hbox, FALSE, FALSE, 0);
+
+ button_hbox_ = gtk_hbox_new(FALSE, gtk_util::kContentAreaBorder);
+ gtk_box_pack_start(GTK_BOX(root_.get()), button_hbox_, TRUE, TRUE, 0);
+}
+
+WebIntentPickerGtk::~WebIntentPickerGtk() {
+ DCHECK(window_ == NULL) << "Should have closed window before destroying.";
+}
+
+void WebIntentPickerGtk::SetServiceURLs(const std::vector<GURL>& urls) {
+ for (size_t i = 0; i < urls.size(); ++i) {
+ GtkWidget* button = gtk_button_new();
+ gtk_widget_set_tooltip_text(button, urls[i].spec().c_str());
+ gtk_box_pack_start(GTK_BOX(button_hbox_), button, FALSE, FALSE, 0);
+ g_signal_connect(button,
+ "clicked",
+ G_CALLBACK(OnServiceButtonClickThunk),
+ this);
+ }
+
+ gtk_widget_show_all(button_hbox_);
+}
+
+void WebIntentPickerGtk::SetServiceIcon(size_t index, const SkBitmap& icon) {
+ if (icon.empty())
+ return;
+
+ GList* button_list = gtk_container_get_children(GTK_CONTAINER(button_hbox_));
+ GtkButton* button = GTK_BUTTON(g_list_nth_data(button_list, index));
+ DCHECK(button != NULL) << "Invalid index.";
+
+ GdkPixbuf* icon_pixbuf = gfx::GdkPixbufFromSkBitmap(&icon);
+ gtk_button_set_image(button, gtk_image_new_from_pixbuf(icon_pixbuf));
+ g_object_unref(icon_pixbuf);
+}
+
+void WebIntentPickerGtk::SetDefaultServiceIcon(size_t index) {
+ GList* button_list = gtk_container_get_children(GTK_CONTAINER(button_hbox_));
+ GtkButton* button = GTK_BUTTON(g_list_nth_data(button_list, index));
+ DCHECK(button != NULL) << "Invalid index.";
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ GdkPixbuf* icon_pixbuf = rb.GetNativeImageNamed(IDR_DEFAULT_FAVICON);
+ gtk_button_set_image(button, gtk_image_new_from_pixbuf(icon_pixbuf));
+}
+
+void WebIntentPickerGtk::Show() {
+ DCHECK(window_ == NULL) << "Show already called.";
+ window_ = tab_contents_->CreateConstrainedDialog(this);
+}
+
+void WebIntentPickerGtk::Close() {
+ DCHECK(window_ != NULL) << "Show not called.";
+ window_->CloseConstrainedWindow();
+ window_ = NULL;
+}
+
+GtkWidget* WebIntentPickerGtk::GetWidgetRoot() {
+ return root_.get();
+}
+
+GtkWidget* WebIntentPickerGtk::GetFocusWidget() {
+ return root_.get();
+}
+
+void WebIntentPickerGtk::DeleteDelegate() {
+ MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+}
+
+void WebIntentPickerGtk::OnCloseButtonClick(GtkWidget* button) {
+ delegate_->OnCancelled();
+}
+
+void WebIntentPickerGtk::OnServiceButtonClick(GtkWidget* button) {
+ GList* button_list = gtk_container_get_children(GTK_CONTAINER(button_hbox_));
+ gint index = g_list_index(button_list, button);
+ DCHECK(index != -1);
+
+ delegate_->OnServiceChosen(static_cast<size_t>(index));
+}
diff --git a/chrome/browser/ui/gtk/web_intent_picker_gtk.h b/chrome/browser/ui/gtk/web_intent_picker_gtk.h
new file mode 100644
index 0000000..b85fd80
--- /dev/null
+++ b/chrome/browser/ui/gtk/web_intent_picker_gtk.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_GTK_WEB_INTENT_PICKER_GTK_H_
+#define CHROME_BROWSER_UI_GTK_WEB_INTENT_PICKER_GTK_H_
+#pragma once
+
+#include <vector>
+
+#include <gtk/gtk.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/ui/gtk/constrained_window_gtk.h"
+#include "chrome/browser/ui/intents/web_intent_picker.h"
+#include "ui/base/gtk/gtk_signal.h"
+
+class CustomDrawButton;
+class GURL;
+class TabContents;
+class WebIntentController;
+class WebIntentPickerDelegate;
+
+// Gtk implementation of WebIntentPicker.
+class WebIntentPickerGtk : public WebIntentPicker,
+ public ConstrainedDialogDelegate {
+ public:
+ WebIntentPickerGtk(TabContents* tab_contents,
+ WebIntentPickerDelegate* delegate);
+ virtual ~WebIntentPickerGtk();
+
+ // WebIntentPicker implementation.
+ virtual void SetServiceURLs(const std::vector<GURL>& urls) OVERRIDE;
+ virtual void SetServiceIcon(size_t index, const SkBitmap& icon) OVERRIDE;
+ virtual void SetDefaultServiceIcon(size_t index) OVERRIDE;
+ virtual void Show() OVERRIDE;
+ virtual void Close() OVERRIDE;
+
+ // ConstrainedDialogDelegate implementation.
+ virtual GtkWidget* GetWidgetRoot() OVERRIDE;
+ virtual GtkWidget* GetFocusWidget() OVERRIDE;
+ virtual void DeleteDelegate() OVERRIDE;
+
+ private:
+ // Callback when a service button is clicked.
+ CHROMEGTK_CALLBACK_0(WebIntentPickerGtk, void, OnServiceButtonClick);
+ // Callback when close button is clicked.
+ CHROMEGTK_CALLBACK_0(WebIntentPickerGtk, void, OnCloseButtonClick);
+
+ // A weak pointer to the tab contents on which to display the picker UI.
+ TabContents* tab_contents_;
+
+ // A weak pointer to the WebIntentPickerDelegate to notify when the user
+ // chooses a service or cancels.
+ WebIntentPickerDelegate* delegate_;
+
+ // The root GtkWidget of the dialog.
+ ui::OwnedWidgetGtk root_;
+
+ // A weak pointer to the hbox that contains the buttons used to choose the
+ // service.
+ GtkWidget* button_hbox_;
+
+ // A button to close the dialog delegate.
+ scoped_ptr<CustomDrawButton> close_button_;
+
+ // The displayed constrained window. Technically owned by the TabContents
+ // page, but this object tells it when to destroy.
+ ConstrainedWindow* window_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebIntentPickerGtk);
+};
+
+#endif // CHROME_BROWSER_UI_GTK_WEB_INTENT_PICKER_GTK_H_
diff --git a/chrome/browser/ui/intents/web_intent_constrained_dialog_factory.cc b/chrome/browser/ui/intents/web_intent_constrained_dialog_factory.cc
new file mode 100644
index 0000000..0aa6bbb
--- /dev/null
+++ b/chrome/browser/ui/intents/web_intent_constrained_dialog_factory.cc
@@ -0,0 +1,47 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/intents/web_intent_constrained_dialog_factory.h"
+
+#include "chrome/browser/ui/intents/web_intent_picker.h"
+#include "content/browser/tab_contents/constrained_window.h"
+#include "content/browser/tab_contents/tab_contents.h"
+
+WebIntentConstrainedDialogFactory::WebIntentConstrainedDialogFactory()
+ : picker_(NULL) {
+}
+
+WebIntentConstrainedDialogFactory::~WebIntentConstrainedDialogFactory() {
+ CloseDialog();
+}
+
+WebIntentPicker* WebIntentConstrainedDialogFactory::Create(
+ TabContents* tab_contents,
+ WebIntentPickerDelegate* delegate) {
+ // Only allow one picker per factory.
+ DCHECK(picker_ == NULL);
+
+ picker_ = WebIntentPicker::Create(tab_contents, delegate);
+
+ // TODO(binji) Remove this check when there are implementations of the picker
+ // for windows and mac.
+ if (picker_ == NULL)
+ return NULL;
+
+ picker_->Show();
+
+ return picker_;
+}
+
+void WebIntentConstrainedDialogFactory::ClosePicker(WebIntentPicker* picker) {
+ DCHECK(picker == picker_);
+ CloseDialog();
+}
+
+void WebIntentConstrainedDialogFactory::CloseDialog() {
+ if (picker_) {
+ picker_->Close();
+ picker_ = NULL;
+ }
+}
diff --git a/chrome/browser/ui/intents/web_intent_constrained_dialog_factory.h b/chrome/browser/ui/intents/web_intent_constrained_dialog_factory.h
new file mode 100644
index 0000000..5efe89f
--- /dev/null
+++ b/chrome/browser/ui/intents/web_intent_constrained_dialog_factory.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_INTENTS_WEB_INTENT_CONSTRAINED_DIALOG_FACTORY_H_
+#define CHROME_BROWSER_UI_INTENTS_WEB_INTENT_CONSTRAINED_DIALOG_FACTORY_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "chrome/browser/ui/intents/web_intent_picker_factory.h"
+
+class TabContents;
+class WebIntentPickerDelegate;
+
+// A factory for creating a constrained dialog as the intent picker UI for a
+// given TabContents.
+class WebIntentConstrainedDialogFactory : public WebIntentPickerFactory {
+ public:
+ WebIntentConstrainedDialogFactory();
+ virtual ~WebIntentConstrainedDialogFactory();
+
+ // WebIntentPickerFactory implementation.
+ virtual WebIntentPicker* Create(
+ TabContents* tab_contents,
+ WebIntentPickerDelegate* delegate) OVERRIDE;
+ virtual void ClosePicker(WebIntentPicker* picker) OVERRIDE;
+
+ private:
+ // Closes the dialog and destroys it.
+ void CloseDialog();
+
+ // A weak pointer to the currently active picker, or NULL if there is no
+ // active picker.
+ WebIntentPicker* picker_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebIntentConstrainedDialogFactory);
+};
+
+#endif // CHROME_BROWSER_UI_INTENTS_WEB_INTENT_CONSTRAINED_DIALOG_FACTORY_H_
diff --git a/chrome/browser/ui/intents/web_intent_picker.h b/chrome/browser/ui/intents/web_intent_picker.h
new file mode 100644
index 0000000..af2cb19
--- /dev/null
+++ b/chrome/browser/ui/intents/web_intent_picker.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_INTENTS_WEB_INTENT_PICKER_H_
+#define CHROME_BROWSER_UI_INTENTS_WEB_INTENT_PICKER_H_
+#pragma once
+
+#include <vector>
+
+class GURL;
+class SkBitmap;
+class TabContents;
+class WebIntentPickerDelegate;
+
+// Base class for the web intent picker dialog.
+class WebIntentPicker {
+ public:
+ class Delegate;
+
+ // Platform specific factory function.
+ static WebIntentPicker* Create(TabContents* tab_contents,
+ WebIntentPickerDelegate* delegate);
+
+ // Initalizes this picker with the |urls|.
+ virtual void SetServiceURLs(const std::vector<GURL>& urls) = 0;
+
+ // Sets the icon for a service at |index|.
+ virtual void SetServiceIcon(size_t index, const SkBitmap& icon) = 0;
+
+ // Sets the icon for a service at |index| to be the default favicon.
+ virtual void SetDefaultServiceIcon(size_t index) = 0;
+
+ // Shows the UI for this picker.
+ virtual void Show() = 0;
+
+ // Hides the UI for this picker, and destroys its UI.
+ virtual void Close() = 0;
+
+ protected:
+ virtual ~WebIntentPicker() {}
+};
+
+#endif // CHROME_BROWSER_UI_INTENTS_WEB_INTENT_PICKER_H_
diff --git a/chrome/browser/ui/intents/web_intent_picker_controller.cc b/chrome/browser/ui/intents/web_intent_picker_controller.cc
new file mode 100644
index 0000000..d348e47
--- /dev/null
+++ b/chrome/browser/ui/intents/web_intent_picker_controller.cc
@@ -0,0 +1,264 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/intents/web_intent_picker_controller.h"
+
+#include <vector>
+
+#include "chrome/browser/favicon/favicon_service.h"
+#include "chrome/browser/intents/web_intent_data.h"
+#include "chrome/browser/intents/web_intents_registry.h"
+#include "chrome/browser/intents/web_intents_registry_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/intents/web_intent_picker.h"
+#include "chrome/browser/ui/intents/web_intent_picker_factory.h"
+#include "chrome/browser/webdata/web_data_service.h"
+#include "content/browser/tab_contents/tab_contents.h"
+#include "content/common/notification_source.h"
+#include "ui/gfx/codec/png_codec.h"
+
+namespace {
+
+// Gets the favicon service for the profile in |tab_contents|.
+FaviconService* GetFaviconService(TabContents* tab_contents) {
+ Profile* profile = Profile::FromBrowserContext(
+ tab_contents->browser_context());
+ return profile->GetFaviconService(Profile::EXPLICIT_ACCESS);
+}
+
+// Gets the web intents registry for the profile in |tab_contents|.
+WebIntentsRegistry* GetWebIntentsRegistry(TabContents* tab_contents) {
+ Profile* profile = Profile::FromBrowserContext(
+ tab_contents->browser_context());
+ return WebIntentsRegistryFactory::GetForProfile(profile);
+}
+
+} // namespace
+
+// A class that asynchronously fetches web intent data from the web intents
+// registry.
+class WebIntentPickerController::WebIntentDataFetcher
+ : public WebIntentsRegistry::Consumer {
+ public:
+ WebIntentDataFetcher(WebIntentPickerController* controller,
+ WebIntentsRegistry* web_intents_registry);
+ ~WebIntentDataFetcher();
+
+ // Asynchronously fetches WebIntentData for the given |action| |type| pair.
+ void Fetch(const string16& action, const string16& type);
+
+ // Cancels the WebDataService request.
+ void Cancel();
+
+ private:
+ // WebIntentsRegistry::Consumer implementation.
+ virtual void OnIntentsQueryDone(
+ WebIntentsRegistry::QueryID,
+ const std::vector<WebIntentData>& intents) OVERRIDE;
+
+ // A weak pointer to the picker controller.
+ WebIntentPickerController* controller_;
+
+ // A weak pointer to the web intents registry.
+ WebIntentsRegistry* web_intents_registry_;
+
+ // The ID of the current web intents request. The value will be -1 if
+ // there is no request in flight.
+ WebIntentsRegistry::QueryID query_id_;
+};
+
+// A class that asynchronously fetches favicons for a vector of URLs.
+class WebIntentPickerController::FaviconFetcher {
+ public:
+ FaviconFetcher(WebIntentPickerController* controller,
+ FaviconService *favicon_service);
+ ~FaviconFetcher();
+
+ // Asynchronously fetches favicons for the each URL in |urls|.
+ void Fetch(const std::vector<GURL>& urls);
+
+ // Cancels all favicon requests.
+ void Cancel();
+
+ private:
+ // Callback called when a favicon is received.
+ void OnFaviconDataAvailable(FaviconService::Handle handle,
+ history::FaviconData favicon_data);
+
+ // A weak pointer to the picker controller.
+ WebIntentPickerController* controller_;
+
+ // A weak pointer to the favicon service.
+ FaviconService* favicon_service_;
+
+ // The Consumer to handle asynchronous favicon requests.
+ CancelableRequestConsumerTSimple<size_t> load_consumer_;
+
+ DISALLOW_COPY_AND_ASSIGN(FaviconFetcher);
+};
+
+WebIntentPickerController::WebIntentPickerController(
+ TabContents* tab_contents,
+ WebIntentPickerFactory* factory)
+ : tab_contents_(tab_contents),
+ picker_factory_(factory),
+ web_intent_data_fetcher_(
+ new WebIntentDataFetcher(this,
+ GetWebIntentsRegistry(tab_contents))),
+ favicon_fetcher_(
+ new FaviconFetcher(this, GetFaviconService(tab_contents))),
+ picker_(NULL),
+ pending_async_count_(0) {
+ NavigationController* controller = &tab_contents->controller();
+ registrar_.Add(this, content::NOTIFICATION_LOAD_START,
+ Source<NavigationController>(controller));
+ registrar_.Add(this, content::NOTIFICATION_TAB_CLOSING,
+ Source<NavigationController>(controller));
+}
+
+WebIntentPickerController::~WebIntentPickerController() {
+}
+
+void WebIntentPickerController::ShowDialog(const string16& action,
+ const string16& type) {
+ if (picker_ != NULL)
+ return;
+
+ picker_ = picker_factory_->Create(tab_contents_, this);
+
+ // TODO(binji) Remove this check when there are implementations of the picker
+ // for windows and mac.
+ if (picker_ == NULL)
+ return;
+
+ web_intent_data_fetcher_->Fetch(action, type);
+}
+
+void WebIntentPickerController::Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(type == content::NOTIFICATION_LOAD_START ||
+ type == content::NOTIFICATION_TAB_CLOSING);
+ ClosePicker();
+}
+
+void WebIntentPickerController::OnServiceChosen(size_t index) {
+ DCHECK(index < urls_.size());
+
+ // TODO(binji) Send the chosen service back to the renderer.
+ LOG(INFO) << "Chose index: " << index << " url: " << urls_[index];
+ ClosePicker();
+}
+
+void WebIntentPickerController::OnCancelled() {
+ // TODO(binji) Tell the renderer that the intent was cancelled.
+ ClosePicker();
+}
+
+void WebIntentPickerController::OnWebIntentDataAvailable(
+ const std::vector<WebIntentData>& intent_data) {
+ urls_.clear();
+ for (size_t i = 0; i < intent_data.size(); ++i) {
+ urls_.push_back(intent_data[i].service_url);
+ }
+
+ // Tell the picker to initialize N urls to the default favicon
+ picker_->SetServiceURLs(urls_);
+ favicon_fetcher_->Fetch(urls_);
+ pending_async_count_--;
+}
+
+void WebIntentPickerController::OnFaviconDataAvailable(
+ size_t index,
+ const SkBitmap& icon_bitmap) {
+ picker_->SetServiceIcon(index, icon_bitmap);
+ pending_async_count_--;
+}
+
+void WebIntentPickerController::OnFaviconDataUnavailable(size_t index) {
+ picker_->SetDefaultServiceIcon(index);
+ pending_async_count_--;
+}
+
+void WebIntentPickerController::ClosePicker() {
+ if (picker_) {
+ picker_factory_->ClosePicker(picker_);
+ picker_ = NULL;
+ }
+}
+
+WebIntentPickerController::WebIntentDataFetcher::WebIntentDataFetcher(
+ WebIntentPickerController* controller,
+ WebIntentsRegistry* web_intents_registry)
+ : controller_(controller),
+ web_intents_registry_(web_intents_registry),
+ query_id_(-1) {
+}
+
+WebIntentPickerController::WebIntentDataFetcher::~WebIntentDataFetcher() {
+}
+
+void WebIntentPickerController::WebIntentDataFetcher::Fetch(
+ const string16& action,
+ const string16& type) {
+ DCHECK(query_id_ == -1) << "Fetch already in process.";
+ controller_->pending_async_count_++;
+ query_id_ = web_intents_registry_->GetIntentProviders(action, this);
+}
+
+void WebIntentPickerController::WebIntentDataFetcher::OnIntentsQueryDone(
+ WebIntentsRegistry::QueryID,
+ const std::vector<WebIntentData>& intents) {
+ controller_->OnWebIntentDataAvailable(intents);
+ query_id_ = -1;
+}
+
+WebIntentPickerController::FaviconFetcher::FaviconFetcher(
+ WebIntentPickerController* controller,
+ FaviconService* favicon_service)
+ : controller_(controller),
+ favicon_service_(favicon_service) {
+}
+
+WebIntentPickerController::FaviconFetcher::~FaviconFetcher() {
+}
+
+void WebIntentPickerController::FaviconFetcher::Fetch(
+ const std::vector<GURL>& urls) {
+ if (!favicon_service_)
+ return;
+
+ for (size_t index = 0; index < urls.size(); ++index) {
+ controller_->pending_async_count_++;
+ FaviconService::Handle handle = favicon_service_->GetFaviconForURL(
+ urls[index],
+ history::FAVICON,
+ &load_consumer_,
+ NewCallback(this, &WebIntentPickerController::FaviconFetcher::
+ OnFaviconDataAvailable));
+ load_consumer_.SetClientData(favicon_service_, handle, index);
+ }
+}
+
+void WebIntentPickerController::FaviconFetcher::Cancel() {
+ load_consumer_.CancelAllRequests();
+}
+
+void WebIntentPickerController::FaviconFetcher::OnFaviconDataAvailable(
+ FaviconService::Handle handle,
+ history::FaviconData favicon_data) {
+ size_t index = load_consumer_.GetClientDataForCurrentRequest();
+ if (favicon_data.is_valid()) {
+ SkBitmap icon_bitmap;
+
+ if (gfx::PNGCodec::Decode(favicon_data.image_data->front(),
+ favicon_data.image_data->size(),
+ &icon_bitmap)) {
+ controller_->OnFaviconDataAvailable(index, icon_bitmap);
+ return;
+ }
+ }
+
+ controller_->OnFaviconDataUnavailable(index);
+}
diff --git a/chrome/browser/ui/intents/web_intent_picker_controller.h b/chrome/browser/ui/intents/web_intent_picker_controller.h
new file mode 100644
index 0000000..369878c
--- /dev/null
+++ b/chrome/browser/ui/intents/web_intent_picker_controller.h
@@ -0,0 +1,97 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_INTENTS_WEB_INTENT_PICKER_CONTROLLER_H_
+#define CHROME_BROWSER_UI_INTENTS_WEB_INTENT_PICKER_CONTROLLER_H_
+#pragma once
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/string16.h"
+#include "chrome/browser/ui/intents/web_intent_picker.h"
+#include "chrome/browser/ui/intents/web_intent_picker_delegate.h"
+#include "content/common/notification_observer.h"
+#include "content/common/notification_registrar.h"
+
+class FaviconService;
+class GURL;
+class SkBitmap;
+class TabContents;
+class WebDataService;
+class WebIntentPickerFactory;
+struct WebIntentData;
+
+// Controls the creation of the WebIntentPicker UI and forwards the user's
+// intent handler choice back to the TabContents object.
+class WebIntentPickerController : public NotificationObserver,
+ public WebIntentPickerDelegate {
+ public:
+ // Takes ownership of |factory|.
+ WebIntentPickerController(TabContents* tab_contents,
+ WebIntentPickerFactory* factory);
+ virtual ~WebIntentPickerController();
+
+ // Shows the web intent picker, given the intent |action| and mime-type
+ // |type|.
+ void ShowDialog(const string16& action, const string16& type);
+
+ protected:
+ // NotificationObserver implementation.
+ virtual void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) OVERRIDE;
+
+ // WebIntentPickerDelegate implementation.
+ virtual void OnServiceChosen(size_t index) OVERRIDE;
+ virtual void OnCancelled() OVERRIDE;
+
+ private:
+ friend class WebIntentPickerControllerTest;
+ class WebIntentDataFetcher;
+ class FaviconFetcher;
+
+ int pending_async_count() const { return pending_async_count_; }
+
+ // Called from the WebIntentDataFetcher when intent data is available.
+ void OnWebIntentDataAvailable(const std::vector<WebIntentData>& intent_data);
+
+ // Called from the FaviconDataFetcher when a favicon is available.
+ void OnFaviconDataAvailable(size_t index, const SkBitmap& icon_bitmap);
+
+ // Called from the FaviconDataFetcher when a favicon is not available.
+ void OnFaviconDataUnavailable(size_t index);
+
+ // Closes the currently active picker.
+ void ClosePicker();
+
+ // A weak pointer to the tab contents that the picker is displayed on.
+ TabContents* tab_contents_;
+
+ // A notification registrar, listening for notifications when the tab closes
+ // to close the picker ui.
+ NotificationRegistrar registrar_;
+
+ // A factory to create a new picker.
+ scoped_ptr<WebIntentPickerFactory> picker_factory_;
+
+ // A helper class to fetch web intent data asynchronously.
+ scoped_ptr<WebIntentDataFetcher> web_intent_data_fetcher_;
+
+ // A helper class to fetch favicon data asynchronously.
+ scoped_ptr<FaviconFetcher> favicon_fetcher_;
+
+ // A weak pointer to the picker this controller controls.
+ WebIntentPicker* picker_;
+
+ // A list of URLs to display in the UI.
+ std::vector<GURL> urls_;
+
+ // A count of the outstanding asynchronous calls.
+ int pending_async_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebIntentPickerController);
+};
+
+#endif // CHROME_BROWSER_UI_INTENTS_WEB_INTENT_PICKER_CONTROLLER_H_
diff --git a/chrome/browser/ui/intents/web_intent_picker_controller_unittest.cc b/chrome/browser/ui/intents/web_intent_picker_controller_unittest.cc
new file mode 100644
index 0000000..89a2e14
--- /dev/null
+++ b/chrome/browser/ui/intents/web_intent_picker_controller_unittest.cc
@@ -0,0 +1,273 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/favicon/favicon_service.h"
+#include "chrome/browser/intents/web_intent_data.h"
+#include "chrome/browser/intents/web_intents_registry.h"
+#include "chrome/browser/intents/web_intents_registry_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/intents/web_intent_picker.h"
+#include "chrome/browser/ui/intents/web_intent_picker_controller.h"
+#include "chrome/browser/ui/intents/web_intent_picker_factory.h"
+#include "chrome/browser/ui/tab_contents/test_tab_contents_wrapper.h"
+#include "chrome/browser/webdata/web_data_service.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/browser/browser_thread.h"
+#include "content/browser/tab_contents/constrained_window.h"
+#include "content/browser/tab_contents/tab_contents.h"
+#include "content/browser/tab_contents/test_tab_contents.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "ui/gfx/codec/png_codec.h"
+
+using testing::_;
+using testing::AtMost;
+using testing::DoAll;
+using testing::Invoke;
+using testing::Return;
+using testing::SaveArg;
+
+namespace {
+
+const string16 kAction1(ASCIIToUTF16("http://www.example.com/share"));
+const string16 kAction2(ASCIIToUTF16("http://www.example.com/foobar"));
+const string16 kType(ASCIIToUTF16("image/png"));
+const GURL kServiceURL1("http://www.google.com");
+const GURL kServiceURL2("http://www.chromium.org");
+const GURL kServiceURL3("http://www.test.com");
+
+// Fill the given bmp with valid png data.
+void FillDataToBitmap(int w, int h, SkBitmap* bmp) {
+ bmp->setConfig(SkBitmap::kARGB_8888_Config, w, h);
+ bmp->allocPixels();
+
+ unsigned char* src_data =
+ reinterpret_cast<unsigned char*>(bmp->getAddr32(0, 0));
+ for (int i = 0; i < w * h; i++) {
+ src_data[i * 4 + 0] = static_cast<unsigned char>(i % 255);
+ src_data[i * 4 + 1] = static_cast<unsigned char>(i % 255);
+ src_data[i * 4 + 2] = static_cast<unsigned char>(i % 255);
+ src_data[i * 4 + 3] = static_cast<unsigned char>(i % 255);
+ }
+}
+
+// Fill the given data buffer with valid png data.
+void FillBitmap(int w, int h, std::vector<unsigned char>* output) {
+ SkBitmap bitmap;
+ FillDataToBitmap(w, h, &bitmap);
+ gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, output);
+}
+
+GURL MakeFaviconURL(const GURL& url) {
+ return GURL(url.spec() + "/favicon.png");
+}
+
+MATCHER_P(VectorIsOfSize, n, "") {
+ return arg.size() == static_cast<size_t>(n);
+}
+
+} // namespace
+
+class WebIntentPickerMock : public WebIntentPicker {
+ public:
+ MOCK_METHOD1(SetServiceURLs, void(const std::vector<GURL>& urls));
+ MOCK_METHOD2(SetServiceIcon, void(size_t index, const SkBitmap& icon));
+ MOCK_METHOD1(SetDefaultServiceIcon, void(size_t index));
+ MOCK_METHOD0(Show, void(void));
+ MOCK_METHOD0(Close, void(void));
+};
+
+class WebIntentPickerFactoryMock : public WebIntentPickerFactory {
+ public:
+ MOCK_METHOD2(Create,
+ WebIntentPicker*(TabContents* tab_contents,
+ WebIntentPickerDelegate* delegate));
+ MOCK_METHOD1(ClosePicker, void(WebIntentPicker* picker));
+};
+
+class TestWebIntentPickerController : public WebIntentPickerController {
+ public:
+ TestWebIntentPickerController(TabContents* tab_contents,
+ WebIntentPickerFactory* factory)
+ : WebIntentPickerController(tab_contents, factory) {
+ }
+
+ MOCK_METHOD1(OnServiceChosen, void(size_t index));
+ MOCK_METHOD0(OnCancelled, void(void));
+
+ // helper functions to forward to the base class.
+ void BaseOnServiceChosen(size_t index) {
+ WebIntentPickerController::OnServiceChosen(index);
+ }
+
+ void BaseOnCancelled() {
+ WebIntentPickerController::OnCancelled();
+ }
+};
+
+class WebIntentPickerControllerTest : public TabContentsWrapperTestHarness {
+ public:
+ WebIntentPickerControllerTest()
+ : ui_thread_(BrowserThread::UI, &message_loop_),
+ db_thread_(BrowserThread::DB, &message_loop_),
+ picker_factory_(NULL),
+ delegate_(NULL) {
+ }
+
+ virtual void SetUp() {
+ TabContentsWrapperTestHarness::SetUp();
+
+ profile_->CreateFaviconService();
+ profile_->CreateWebDataService(true);
+ web_data_service_ = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
+ favicon_service_ = profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
+ WebIntentsRegistry *registry =
+ WebIntentsRegistryFactory::GetForProfile(profile_.get());
+ registry->Initialize(web_data_service_);
+
+ picker_factory_ = new WebIntentPickerFactoryMock();
+ controller_.reset(new TestWebIntentPickerController(contents(),
+ picker_factory_));
+ }
+
+ virtual void TearDown() {
+ controller_.reset();
+
+ TabContentsWrapperTestHarness::TearDown();
+ }
+
+ protected:
+ void AddWebIntentService(const string16& action,
+ const GURL& service_url) {
+ WebIntentData web_intent_data;
+ web_intent_data.action = action;
+ web_intent_data.type = kType;
+ web_intent_data.service_url = service_url;
+ web_data_service_->AddWebIntent(web_intent_data);
+ }
+
+ void AddFaviconForURL(const GURL& url) {
+ std::vector<unsigned char> image_data;
+ FillBitmap(16, 16, &image_data);
+
+ favicon_service_->SetFavicon(url,
+ MakeFaviconURL(url),
+ image_data,
+ history::FAVICON);
+ }
+
+ void SetPickerExpectations(int expected_service_count,
+ int expected_default_favicons) {
+ EXPECT_CALL(*picker_factory_, Create(_, _)).
+ WillOnce(DoAll(SaveArg<1>(&delegate_), Return(&picker_)));
+ EXPECT_CALL(picker_,
+ SetServiceURLs(VectorIsOfSize(expected_service_count))).
+ Times(1);
+ EXPECT_CALL(picker_, SetDefaultServiceIcon(_)).
+ Times(expected_default_favicons);
+ }
+
+ void CheckPendingAsync() {
+ if (controller_->pending_async_count() > 0) {
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&WebIntentPickerControllerTest::CheckPendingAsync,
+ base::Unretained(this)));
+ return;
+ }
+
+ MessageLoop::current()->Quit();
+ }
+
+ void WaitForDialogToShow() {
+ CheckPendingAsync();
+ MessageLoop::current()->Run();
+ }
+
+ BrowserThread ui_thread_;
+ BrowserThread db_thread_;
+ WebIntentPickerMock picker_;
+ WebIntentPickerFactoryMock* picker_factory_; // controller_ takes ownership.
+ scoped_ptr<TestWebIntentPickerController> controller_;
+ WebIntentPickerDelegate* delegate_;
+ WebDataService* web_data_service_;
+ FaviconService* favicon_service_;
+};
+
+TEST_F(WebIntentPickerControllerTest, ShowDialogWith3Services) {
+ SetPickerExpectations(3, 3);
+ AddWebIntentService(kAction1, kServiceURL1);
+ AddWebIntentService(kAction1, kServiceURL2);
+ AddWebIntentService(kAction1, kServiceURL3);
+
+ controller_->ShowDialog(kAction1, kType);
+ WaitForDialogToShow();
+}
+
+TEST_F(WebIntentPickerControllerTest, ShowDialogWithNoServices) {
+ SetPickerExpectations(0, 0);
+
+ EXPECT_CALL(picker_, SetServiceIcon(_, _)).Times(0);
+
+ controller_->ShowDialog(kAction1, kType);
+ WaitForDialogToShow();
+}
+
+// TODO(binji) SetServiceIcon isn't called unless I create the HistoryService,
+// but when I do, the test hangs...
+TEST_F(WebIntentPickerControllerTest, DISABLED_ShowFavicon) {
+ SetPickerExpectations(3, 2);
+ AddWebIntentService(kAction1, kServiceURL1);
+ AddWebIntentService(kAction1, kServiceURL2);
+ AddWebIntentService(kAction1, kServiceURL3);
+ AddFaviconForURL(kServiceURL1);
+ AddFaviconForURL(kServiceURL3);
+
+ EXPECT_CALL(picker_, SetServiceIcon(0, _)).Times(1);
+ EXPECT_CALL(picker_, SetDefaultServiceIcon(1)).Times(1);
+ EXPECT_CALL(picker_, SetServiceIcon(2, _)).Times(1);
+
+ controller_->ShowDialog(kAction1, kType);
+ WaitForDialogToShow();
+}
+
+TEST_F(WebIntentPickerControllerTest, ChooseService) {
+ SetPickerExpectations(2, 2);
+ AddWebIntentService(kAction1, kServiceURL1);
+ AddWebIntentService(kAction1, kServiceURL2);
+
+ EXPECT_CALL(*controller_, OnServiceChosen(0))
+ .WillOnce(Invoke(controller_.get(),
+ &TestWebIntentPickerController::BaseOnServiceChosen));
+ EXPECT_CALL(*controller_, OnCancelled())
+ .Times(0);
+ EXPECT_CALL(*picker_factory_, ClosePicker(_));
+
+ controller_->ShowDialog(kAction1, kType);
+ WaitForDialogToShow();
+ delegate_->OnServiceChosen(0);
+}
+
+TEST_F(WebIntentPickerControllerTest, Cancel) {
+ SetPickerExpectations(2, 2);
+ AddWebIntentService(kAction1, kServiceURL1);
+ AddWebIntentService(kAction1, kServiceURL2);
+
+ EXPECT_CALL(*controller_, OnServiceChosen(0))
+ .Times(0);
+ EXPECT_CALL(*controller_, OnCancelled())
+ .WillOnce(Invoke(controller_.get(),
+ &TestWebIntentPickerController::BaseOnCancelled));
+ EXPECT_CALL(*picker_factory_, ClosePicker(_));
+
+ controller_->ShowDialog(kAction1, kType);
+ WaitForDialogToShow();
+ delegate_->OnCancelled();
+}
diff --git a/chrome/browser/ui/intents/web_intent_picker_delegate.h b/chrome/browser/ui/intents/web_intent_picker_delegate.h
new file mode 100644
index 0000000..e540e62
--- /dev/null
+++ b/chrome/browser/ui/intents/web_intent_picker_delegate.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_INTENTS_WEB_INTENT_PICKER_DELEGATE_H_
+#define CHROME_BROWSER_UI_INTENTS_WEB_INTENT_PICKER_DELEGATE_H_
+#pragma once
+
+// A class used to notify the delegate when the user has chosen a web intent
+// service.
+class WebIntentPickerDelegate {
+ public:
+ // Callback called when the user has chosen a service.
+ virtual void OnServiceChosen(size_t index) = 0;
+
+ // Callback called when the user cancels out of the dialog.
+ virtual void OnCancelled() = 0;
+};
+
+#endif // CHROME_BROWSER_UI_INTENTS_WEB_INTENT_PICKER_DELEGATE_H_
diff --git a/chrome/browser/ui/intents/web_intent_picker_factory.h b/chrome/browser/ui/intents/web_intent_picker_factory.h
new file mode 100644
index 0000000..716bac5
--- /dev/null
+++ b/chrome/browser/ui/intents/web_intent_picker_factory.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_INTENTS_WEB_INTENT_PICKER_FACTORY_H_
+#define CHROME_BROWSER_UI_INTENTS_WEB_INTENT_PICKER_FACTORY_H_
+#pragma once
+
+class TabContents;
+class WebIntentPicker;
+class WebIntentPickerDelegate;
+
+// Interface to create and close the WebIntentPicker UI.
+class WebIntentPickerFactory {
+ public:
+ virtual ~WebIntentPickerFactory() {}
+
+ // Creates a new WebIntentPicker. The picker is owned by the factory.
+ virtual WebIntentPicker* Create(TabContents* tab_contents,
+ WebIntentPickerDelegate* delegate) = 0;
+
+ // Closes and destroys the picker.
+ virtual void ClosePicker(WebIntentPicker* picker) = 0;
+};
+
+#endif // CHROME_BROWSER_UI_INTENTS_WEB_INTENT_PICKER_FACTORY_H_
diff --git a/chrome/browser/ui/tab_contents/tab_contents_wrapper.cc b/chrome/browser/ui/tab_contents/tab_contents_wrapper.cc
index a8d396d..7f92a88 100644
--- a/chrome/browser/ui/tab_contents/tab_contents_wrapper.cc
+++ b/chrome/browser/ui/tab_contents/tab_contents_wrapper.cc
@@ -54,6 +54,8 @@
#include "chrome/browser/ui/blocked_content/blocked_content_tab_helper.h"
#include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h"
#include "chrome/browser/ui/find_bar/find_tab_helper.h"
+#include "chrome/browser/ui/intents/web_intent_constrained_dialog_factory.h"
+#include "chrome/browser/ui/intents/web_intent_picker_controller.h"
#include "chrome/browser/ui/search_engines/search_engine_tab_helper.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper_delegate.h"
#include "chrome/common/chrome_notification_types.h"
@@ -156,6 +158,9 @@ TabContentsWrapper::TabContentsWrapper(TabContents* contents)
content_settings_.reset(new TabSpecificContentSettings(contents));
translate_tab_helper_.reset(new TranslateTabHelper(contents));
print_view_manager_.reset(new printing::PrintViewManager(this));
+ web_intent_picker_controller_.reset(new WebIntentPickerController(
+ contents,
+ new WebIntentConstrainedDialogFactory()));
// Create the per-tab observers.
external_protocol_observer_.reset(new ExternalProtocolObserver(contents));
@@ -645,6 +650,8 @@ void TabContentsWrapper::OnWebIntentDispatch(const IPC::Message& message,
<< "\ntype=" << UTF16ToASCII(type)
<< "\nrenderer_id=" << message.routing_id()
<< "\nid=" << intent_id;
+
+ web_intent_picker_controller_->ShowDialog(action, type);
}
void TabContentsWrapper::OnSnapshot(const SkBitmap& bitmap) {
diff --git a/chrome/browser/ui/tab_contents/tab_contents_wrapper.h b/chrome/browser/ui/tab_contents/tab_contents_wrapper.h
index 77e2d4c..fdceb25 100644
--- a/chrome/browser/ui/tab_contents/tab_contents_wrapper.h
+++ b/chrome/browser/ui/tab_contents/tab_contents_wrapper.h
@@ -59,6 +59,7 @@ class TabContentsWrapperDelegate;
class TabSpecificContentSettings;
class ThumbnailGenerator;
class TranslateTabHelper;
+class WebIntentPickerController;
namespace safe_browsing {
class ClientSideDetectionHost;
@@ -195,6 +196,10 @@ class TabContentsWrapper : public TabContentsObserver,
return restore_tab_helper_.get();
}
+ WebIntentPickerController* web_intent_picker_controller() {
+ return web_intent_picker_controller_.get();
+ }
+
// Overrides -----------------------------------------------------------------
// TabContentsObserver overrides:
@@ -327,6 +332,9 @@ class TabContentsWrapper : public TabContentsObserver,
// Handles print job for this contents.
scoped_ptr<printing::PrintViewManager> print_view_manager_;
+ // Handles displaying a web intents picker to the user.
+ scoped_ptr<WebIntentPickerController> web_intent_picker_controller_;
+
// Handles IPCs related to SafeBrowsing client-side phishing detection.
scoped_ptr<safe_browsing::ClientSideDetectionHost>
safebrowsing_detection_host_;
diff --git a/chrome/browser/ui/views/web_intent_picker_view.cc b/chrome/browser/ui/views/web_intent_picker_view.cc
new file mode 100644
index 0000000..fe96858
--- /dev/null
+++ b/chrome/browser/ui/views/web_intent_picker_view.cc
@@ -0,0 +1,14 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/intents/web_intent_picker.h"
+#include "chrome/browser/ui/intents/web_intent_picker_delegate.h"
+#include "content/browser/tab_contents/tab_contents.h"
+
+// static
+WebIntentPicker* WebIntentPicker::Create(TabContents* tab_contents,
+ WebIntentPickerDelegate* delegate) {
+ // TODO(binji) Implement. See http://crbug.com/93915.
+ return NULL;
+}
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index fc6b188..1888e54 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2698,6 +2698,7 @@
'browser/ui/cocoa/view_id_util.h',
'browser/ui/cocoa/view_id_util.mm',
'browser/ui/cocoa/view_resizer.h',
+ 'browser/ui/cocoa/web_intent_picker_cocoa.mm',
'browser/ui/cocoa/window_restore_utils.h',
'browser/ui/cocoa/window_restore_utils.mm',
'browser/ui/cocoa/window_size_autosaver.h',
@@ -2944,9 +2945,18 @@
'browser/ui/gtk/update_recommended_dialog.h',
'browser/ui/gtk/view_id_util.cc',
'browser/ui/gtk/view_id_util.h',
+ 'browser/ui/gtk/web_intent_picker_gtk.cc',
+ 'browser/ui/gtk/web_intent_picker_gtk.h',
'browser/ui/input_window_dialog.h',
'browser/ui/input_window_dialog_gtk.cc',
'browser/ui/input_window_dialog_win.cc',
+ 'browser/ui/intents/web_intent_constrained_dialog_factory.cc',
+ 'browser/ui/intents/web_intent_constrained_dialog_factory.h',
+ 'browser/ui/intents/web_intent_picker.h',
+ 'browser/ui/intents/web_intent_picker_controller.cc',
+ 'browser/ui/intents/web_intent_picker_controller.h',
+ 'browser/ui/intents/web_intent_picker_delegate.h',
+ 'browser/ui/intents/web_intent_picker_factory.h',
'browser/ui/login/login_model.h',
'browser/ui/login/login_prompt.cc',
'browser/ui/login/login_prompt.h',
@@ -3397,6 +3407,7 @@
'browser/ui/views/update_recommended_message_box.h',
'browser/ui/views/user_data_dir_dialog.cc',
'browser/ui/views/user_data_dir_dialog.h',
+ 'browser/ui/views/web_intent_picker_view.cc',
'browser/ui/views/window.cc',
'browser/ui/views/window.h',
'browser/ui/views/wrench_menu.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index c30bb85..4079279 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1869,6 +1869,7 @@
'browser/ui/gtk/reload_button_gtk_unittest.cc',
'browser/ui/gtk/status_icons/status_tray_gtk_unittest.cc',
'browser/ui/gtk/tabs/tab_renderer_gtk_unittest.cc',
+ 'browser/ui/intents/web_intent_picker_controller_unittest.cc',
'browser/ui/login/login_prompt_unittest.cc',
'browser/ui/omnibox/omnibox_view_unittest.cc',
'browser/ui/panels/panel_browser_window_cocoa_unittest.mm',