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

Unified Diff: chrome/browser/ui/intents/web_intent_picker_controller.cc

Issue 12225076: Delete most web intents code. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 10 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/intents/web_intent_picker_controller.cc
diff --git a/chrome/browser/ui/intents/web_intent_picker_controller.cc b/chrome/browser/ui/intents/web_intent_picker_controller.cc
deleted file mode 100644
index 185b3ef0d9fa73aa34ab01f44512facdc2f6c760..0000000000000000000000000000000000000000
--- a/chrome/browser/ui/intents/web_intent_picker_controller.cc
+++ /dev/null
@@ -1,972 +0,0 @@
-// Copyright (c) 2012 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 "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/md5.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/time.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/download/download_item_model.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/extensions/platform_app_launcher.h"
-#include "chrome/browser/extensions/webstore_installer.h"
-#include "chrome/browser/intents/cws_intents_registry_factory.h"
-#include "chrome/browser/intents/default_web_intent_service.h"
-#include "chrome/browser/intents/intent_service_host.h"
-#include "chrome/browser/intents/native_services.h"
-#include "chrome/browser/intents/web_intents_registry_factory.h"
-#include "chrome/browser/intents/web_intents_reporting.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/tab_contents/tab_util.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/browser_navigator.h"
-#include "chrome/browser/ui/browser_tabstrip.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/intents/web_intent_icon_loader.h"
-#include "chrome/browser/ui/intents/web_intent_picker.h"
-#include "chrome/browser/ui/intents/web_intent_picker_model.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/web_contents_modal_dialog_manager.h"
-#include "chrome/browser/webdata/web_data_service.h"
-#include "chrome/common/url_constants.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/download_manager.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/browser/web_intents_dispatcher.h"
-#include "ui/gfx/favicon_size.h"
-#include "ui/gfx/image/image.h"
-
-using extensions::WebstoreInstaller;
-
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(WebIntentPickerController);
-
-namespace {
-
-// Maximum amount of time to delay displaying dialog while waiting for data.
-const int kMaxHiddenSetupTimeMs = 200;
-
-// Minimum amount of time to show waiting dialog, if it is shown.
-const int kMinThrobberDisplayTimeMs = 800;
-
-// Gets the web intents registry for the specified profile.
-WebIntentsRegistry* GetWebIntentsRegistry(Profile* profile) {
- return WebIntentsRegistryFactory::GetForProfile(profile);
-}
-
-// Gets the Chrome web store intents registry for the specified profile.
-CWSIntentsRegistry* GetCWSIntentsRegistry(Profile* profile) {
- return CWSIntentsRegistryFactory::GetForProfile(profile);
-}
-
-class SourceWindowObserver : content::WebContentsObserver {
- public:
- SourceWindowObserver(content::WebContents* web_contents,
- base::WeakPtr<WebIntentPickerController> controller)
- : content::WebContentsObserver(web_contents),
- controller_(controller) {}
- virtual ~SourceWindowObserver() {}
-
- // Implement WebContentsObserver
- virtual void WebContentsDestroyed(
- content::WebContents* web_contents) OVERRIDE {
- if (controller_)
- controller_->SourceWebContentsDestroyed(web_contents);
- delete this;
- }
-
- private:
- base::WeakPtr<WebIntentPickerController> controller_;
-};
-
-// Deletes |service|, presumably called from a dispatcher callback.
-void DeleteIntentService(
- web_intents::IntentServiceHost* service,
- webkit_glue::WebIntentReplyType type) {
- delete service;
-}
-
-} // namespace
-
-// UMAReporter handles reporting Web Intents events to UMA.
-class WebIntentPickerController::UMAReporter {
- public:
-
- // Resets the service active duration timer to "now".
- void ResetServiceActiveTimer();
-
- // Records the duration of time spent using the service. Uses |reply_type|
- // to distinguish between successful and failed service calls.
- void RecordServiceActiveDuration(webkit_glue::WebIntentReplyType reply_type);
-
- private:
-
- // The time when the user began using the service.
- base::TimeTicks service_start_time_;
-};
-
-void WebIntentPickerController::UMAReporter::ResetServiceActiveTimer() {
- service_start_time_ = base::TimeTicks::Now();
-}
-
-void WebIntentPickerController::UMAReporter::RecordServiceActiveDuration(
- webkit_glue::WebIntentReplyType reply_type) {
- if (!service_start_time_.is_null()) {
- web_intents::RecordServiceActiveDuration(reply_type,
- base::TimeTicks::Now() - service_start_time_);
- }
-}
-
-WebIntentPickerController::WebIntentPickerController(
- content::WebContents* web_contents)
- : dialog_state_(kPickerHidden),
- web_contents_(web_contents),
- profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
- picker_(NULL),
- picker_model_(new WebIntentPickerModel()),
- uma_reporter_(new UMAReporter()),
- pending_async_count_(0),
- pending_registry_calls_count_(0),
- pending_cws_request_(false),
- picker_shown_(false),
- window_disposition_source_(NULL),
- source_intents_dispatcher_(NULL),
- intents_dispatcher_(NULL),
- location_bar_button_indicated_(true),
- service_tab_(NULL),
- icon_loader_(NULL),
- ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)),
- ALLOW_THIS_IN_INITIALIZER_LIST(timer_factory_(this)),
- ALLOW_THIS_IN_INITIALIZER_LIST(dispatcher_factory_(this)) {
- native_services_.reset(new web_intents::NativeServiceFactory());
-#if defined(TOOLKIT_VIEWS)
- cancelled_ = true;
-#endif
- icon_loader_.reset(
- new web_intents::IconLoader(profile_, picker_model_.get()));
-}
-
-WebIntentPickerController::~WebIntentPickerController() {
- if (picker_)
- picker_->InvalidateDelegate();
- if (webstore_installer_.get())
- webstore_installer_->InvalidateDelegate();
-}
-
-// TODO(gbillock): combine this with ShowDialog.
-void WebIntentPickerController::SetIntentsDispatcher(
- content::WebIntentsDispatcher* intents_dispatcher) {
- // TODO(gbillock): This is to account for multiple dispatches in the same tab.
- // That is currently not a well-handled case, and this is a band-aid.
- dispatcher_factory_.InvalidateWeakPtrs();
- intents_dispatcher_ = intents_dispatcher;
- intents_dispatcher_->RegisterReplyNotification(
- base::Bind(&WebIntentPickerController::OnSendReturnMessage,
- dispatcher_factory_.GetWeakPtr()));
-
- // Initialize the reporting bucket.
- const webkit_glue::WebIntentData& intent = intents_dispatcher_->GetIntent();
- uma_bucket_ = web_intents::ToUMABucket(intent.action, intent.type);
-}
-
-// TODO(smckay): rename this "StartActivity".
-void WebIntentPickerController::ShowDialog(const string16& action,
- const string16& type) {
- ShowDialog(kEnableDefaults);
-}
-
-void WebIntentPickerController::ReshowDialog() {
- ShowDialog(kSuppressDefaults);
-}
-
-void WebIntentPickerController::ShowDialog(DefaultsUsage suppress_defaults) {
- web_intents::RecordIntentDispatched(uma_bucket_);
-
- DCHECK(intents_dispatcher_);
-
-#if defined(TOOLKIT_VIEWS)
- cancelled_ = true;
-#endif
-
- // Only show a picker once.
- // TODO(gbillock): There's a hole potentially admitting multiple
- // in-flight dispatches since we don't create the picker
- // in this method, but only after calling the registry.
- if (picker_shown_) {
- intents_dispatcher_->SendReply(webkit_glue::WebIntentReply(
- webkit_glue::WEB_INTENT_REPLY_FAILURE,
- ASCIIToUTF16("Simultaneous intent invocation.")));
- return;
- }
-
- // TODO(binji): Figure out what to do when intents are invoked from incognito
- // mode.
- if (profile_->IsOffTheRecord()) {
- intents_dispatcher_->SendReply(webkit_glue::WebIntentReply(
- webkit_glue::WEB_INTENT_REPLY_FAILURE, string16()));
- return;
- }
-
- picker_model_->Clear();
- picker_model_->set_action(intents_dispatcher_->GetIntent().action);
- picker_model_->set_type(intents_dispatcher_->GetIntent().type);
-
- // If the intent is explicit, skip showing the picker.
- const GURL& service = intents_dispatcher_->GetIntent().service;
- // TODO(gbillock): Decide whether to honor the default suppression flag
- // here or suppress the control for explicit intents.
- if (service.is_valid() && !suppress_defaults) {
- // Get services from the registry to verify a registered extension
- // page for this action/type if it is permitted to be dispatched. (Also
- // required to find disposition set by service.)
- pending_async_count_++;
- GetWebIntentsRegistry(profile_)->GetIntentServices(
- picker_model_->action(), picker_model_->type(),
- base::Bind(
- &WebIntentPickerController::
- OnWebIntentServicesAvailableForExplicitIntent,
- weak_ptr_factory_.GetWeakPtr()));
- return;
- }
-
- // As soon as the dialog is requested, block all input events
- // on the original tab.
- WebContentsModalDialogManager* web_contents_modal_dialog_manager =
- WebContentsModalDialogManager::FromWebContents(web_contents_);
- web_contents_modal_dialog_manager->BlockWebContentsInteraction(true);
- SetDialogState(kPickerSetup);
-
- pending_async_count_++;
- pending_registry_calls_count_++;
- GetWebIntentsRegistry(profile_)->GetIntentServices(
- picker_model_->action(), picker_model_->type(),
- base::Bind(&WebIntentPickerController::OnWebIntentServicesAvailable,
- weak_ptr_factory_.GetWeakPtr()));
-
- GURL invoking_url = web_contents_->GetURL();
- if (invoking_url.is_valid() && !suppress_defaults) {
- pending_async_count_++;
- pending_registry_calls_count_++;
- GetWebIntentsRegistry(profile_)->GetDefaultIntentService(
- picker_model_->action(), picker_model_->type(), invoking_url,
- base::Bind(&WebIntentPickerController::OnWebIntentDefaultsAvailable,
- weak_ptr_factory_.GetWeakPtr()));
- }
-
- pending_cws_request_ = true;
- pending_async_count_++;
- GetCWSIntentsRegistry(profile_)->GetIntentServices(
- picker_model_->action(), picker_model_->type(),
- base::Bind(&WebIntentPickerController::OnCWSIntentServicesAvailable,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
-void WebIntentPickerController::OnServiceChosen(
- const GURL& url,
- webkit_glue::WebIntentServiceData::Disposition disposition,
- DefaultsUsage suppress_defaults) {
- web_intents::RecordServiceInvoke(uma_bucket_);
- uma_reporter_->ResetServiceActiveTimer();
- ExtensionService* extension_service =
- extensions::ExtensionSystem::Get(profile_)->extension_service();
- DCHECK(extension_service);
-
-#if defined(TOOLKIT_VIEWS)
- cancelled_ = false;
-#endif
-
- // Set the default here. Activating the intent resets the picker model.
- // TODO(gbillock): we should perhaps couple the model to the dispatcher so
- // we can re-activate the model on use-another-service.
- if (!suppress_defaults)
- SetDefaultServiceForSelection(url);
-
-
- // TODO(smckay): this basically smells like another disposition.
- const extensions::Extension* extension =
- extension_service->GetInstalledApp(url);
- if (extension && extension->is_platform_app()) {
- extensions::LaunchPlatformAppWithWebIntent(profile_,
- extension, intents_dispatcher_, web_contents_);
- ClosePicker();
- return;
- }
-
- // TODO(smckay): This entire method shold basically be pulled out
- // into a separate class dedicated to the execution of intents.
- // The tricky part is with the "INLINE" disposition where we
- // want to (re)use the picker to handle the intent. A bit of
- // artful composition + lazy instantiation should make that possible.
- switch (disposition) {
- case webkit_glue::WebIntentServiceData::DISPOSITION_NATIVE: {
- web_intents::IntentServiceHost* service =
- native_services_->CreateServiceInstance(
- url, intents_dispatcher_->GetIntent(), web_contents_);
- DCHECK(service);
-
- intents_dispatcher_->RegisterReplyNotification(
- base::Bind(&DeleteIntentService, base::Unretained(service)));
-
- service->HandleIntent(intents_dispatcher_);
- break;
- }
-
- case webkit_glue::WebIntentServiceData::DISPOSITION_INLINE: {
- // Set the model to inline disposition. It will notify the picker which
- // will respond (via OnInlineDispositionWebContentsCreated) with the
- // WebContents to dispatch the intent to.
- picker_model_->SetInlineDisposition(url);
- break;
- }
-
- case webkit_glue::WebIntentServiceData::DISPOSITION_WINDOW: {
- content::WebContents* contents = content::WebContents::Create(
- content::WebContents::CreateParams(
- profile_, tab_util::GetSiteInstanceForNewTab(profile_, url)));
- WebIntentPickerController::CreateForWebContents(contents);
-
- // Let the controller for the target WebContents know that it is hosting a
- // web intents service. Suppress if we're not showing the
- // use-another-service button.
- if (picker_model_->show_use_another_service()) {
- WebIntentPickerController::FromWebContents(contents)->
- SetWindowDispositionSource(web_contents_, intents_dispatcher_);
- }
-
- intents_dispatcher_->DispatchIntent(contents);
- service_tab_ = contents;
-
- // This call performs all the tab strip manipulation, notifications, etc.
- // Since we're passing in a target_contents, it assumes that we will
- // navigate the page ourselves, though.
- chrome::NavigateParams params(profile_, url,
- content::PAGE_TRANSITION_LINK);
- params.target_contents = contents;
- params.disposition = NEW_FOREGROUND_TAB;
- params.tabstrip_add_types = TabStripModel::ADD_INHERIT_GROUP;
- chrome::Navigate(&params);
-
- service_tab_->GetController().LoadURL(
- url, content::Referrer(),
- content::PAGE_TRANSITION_AUTO_BOOKMARK, std::string());
-
- ClosePicker();
- break;
- }
-
- default:
- NOTREACHED();
- break;
- }
-}
-
-content::WebContents*
-WebIntentPickerController::CreateWebContentsForInlineDisposition(
- Profile* profile, const GURL& url) {
- content::WebContents::CreateParams create_params(
- profile, tab_util::GetSiteInstanceForNewTab(profile, url));
- content::WebContents* web_contents = content::WebContents::Create(
- create_params);
- intents_dispatcher_->DispatchIntent(web_contents);
- return web_contents;
-}
-
-void WebIntentPickerController::SetDefaultServiceForSelection(const GURL& url) {
- DCHECK(picker_model_.get());
- if (url == picker_model_->default_service_url())
- return;
-
- DefaultWebIntentService record;
- record.action = picker_model_->action();
- record.type = picker_model_->type();
- record.service_url = url.spec();
- record.user_date = static_cast<int>(floor(base::Time::Now().ToDoubleT()));
- GetWebIntentsRegistry(profile_)->RegisterDefaultIntentService(record);
-}
-
-void WebIntentPickerController::OnExtensionInstallRequested(
- const std::string& id) {
- // Create a local copy of |id| since it is a reference to a member on a UI
- // object, and SetPendingExtensionInstallId triggers an OnModelChanged and
- // a subsequent rebuild of UI objects.
- std::string extension_id(id);
-
- picker_model_->SetPendingExtensionInstallId(extension_id);
-
- scoped_ptr<WebstoreInstaller::Approval> approval(
- WebstoreInstaller::Approval::CreateWithInstallPrompt(profile_));
- // Don't show a bubble pointing to the extension or any other post
- // installation UI.
- approval->skip_post_install_ui = true;
- approval->show_dialog_callback = base::Bind(
- &WebIntentPickerController::OnShowExtensionInstallDialog,
- weak_ptr_factory_.GetWeakPtr());
-
- webstore_installer_ = new WebstoreInstaller(profile_, this,
- &web_contents_->GetController(), extension_id,
- approval.Pass(), WebstoreInstaller::FLAG_INLINE_INSTALL);
-
- pending_async_count_++;
- webstore_installer_->Start();
-}
-
-void WebIntentPickerController::OnExtensionLinkClicked(
- const std::string& id,
- WindowOpenDisposition disposition) {
- // Navigate from source tab.
- GURL extension_url(extension_urls::GetWebstoreItemDetailURLPrefix() + id);
- chrome::NavigateParams params(profile_, extension_url,
- content::PAGE_TRANSITION_LINK);
- params.disposition =
- (disposition == CURRENT_TAB) ? NEW_FOREGROUND_TAB : disposition;
- chrome::Navigate(&params);
-}
-
-void WebIntentPickerController::OnSuggestionsLinkClicked(
- WindowOpenDisposition disposition) {
- // Navigate from source tab.
- GURL query_url = extension_urls::GetWebstoreIntentQueryURL(
- UTF16ToUTF8(picker_model_->action()),
- UTF16ToUTF8(picker_model_->type()));
- chrome::NavigateParams params(profile_, query_url,
- content::PAGE_TRANSITION_LINK);
- params.disposition =
- (disposition == CURRENT_TAB) ? NEW_FOREGROUND_TAB : disposition;
- chrome::Navigate(&params);
-}
-
-void WebIntentPickerController::OnUserCancelledPickerDialog() {
- if (!intents_dispatcher_)
- return;
-
- intents_dispatcher_->SendReply(webkit_glue::WebIntentReply(
- webkit_glue::WEB_INTENT_PICKER_CANCELLED, string16()));
- web_intents::RecordPickerCancel(uma_bucket_);
-
- ClosePicker();
-}
-
-void WebIntentPickerController::OnChooseAnotherService() {
- DCHECK(intents_dispatcher_);
- web_intents::RecordChooseAnotherService(uma_bucket_);
- intents_dispatcher_->ResetDispatch();
- picker_model_->SetInlineDisposition(GURL::EmptyGURL());
-}
-
-void WebIntentPickerController::OnClosing() {
- SetDialogState(kPickerHidden);
- picker_ = NULL;
- picker_model_->ClearPendingExtensionInstall();
- CancelDownload();
-#if defined(TOOLKIT_VIEWS)
- if (cancelled_)
- OnUserCancelledPickerDialog();
-#endif
-}
-
-void WebIntentPickerController::OnExtensionDownloadStarted(
- const std::string& id,
- content::DownloadItem* item) {
- DownloadItemModel(item).SetShouldShowInShelf(false);
- download_id_ = item->GetGlobalId();
- picker_model_->UpdateExtensionDownloadState(item);
-}
-
-void WebIntentPickerController::OnExtensionDownloadProgress(
- const std::string& id,
- content::DownloadItem* item) {
- picker_model_->UpdateExtensionDownloadState(item);
-}
-
-void WebIntentPickerController::OnExtensionInstallSuccess(
- const std::string& extension_id) {
- webstore_installer_ = NULL; // Release reference.
-
- // OnExtensionInstallSuccess is called via NotificationService::Notify before
- // the extension is added to the ExtensionService. Dispatch via PostTask to
- // allow ExtensionService to update.
- MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(
- &WebIntentPickerController::DispatchToInstalledExtension,
- base::Unretained(this),
- extension_id));
-}
-
-void WebIntentPickerController::DispatchToInstalledExtension(
- const std::string& extension_id) {
- web_intents::RecordCWSExtensionInstalled(uma_bucket_);
-
- download_id_ = content::DownloadId();
- picker_model_->ClearPendingExtensionInstall();
- if (picker_)
- picker_->OnExtensionInstallSuccess(extension_id);
-
- WebIntentsRegistry::IntentServiceList services;
- GetWebIntentsRegistry(profile_)->GetIntentServicesForExtensionFilter(
- picker_model_->action(), picker_model_->type(),
- extension_id,
- &services);
-
- // Extension must be registered with registry by now.
- DCHECK(services.size() > 0);
-
- // TODO(binji): We're going to need to disambiguate if there are multiple
- // services. For now, just choose the first.
- const webkit_glue::WebIntentServiceData& service_data = services[0];
-
- picker_model_->RemoveSuggestedExtension(extension_id);
- AddServiceToModel(service_data);
- OnServiceChosen(service_data.service_url, service_data.disposition,
- kEnableDefaults);
- AsyncOperationFinished();
-}
-
-void WebIntentPickerController::OnExtensionInstallFailure(
- const std::string& id,
- const std::string& error,
- WebstoreInstaller::FailureReason reason) {
- webstore_installer_ = NULL; // Release reference.
-
- // If the user cancelled the install then don't show an error message.
- if (reason == WebstoreInstaller::FAILURE_REASON_CANCELLED)
- picker_model_->ClearPendingExtensionInstall();
- else
- picker_model_->SetPendingExtensionInstallStatusString(UTF8ToUTF16(error));
-
- if (picker_)
- picker_->OnExtensionInstallFailure(id);
- AsyncOperationFinished();
-}
-
-void WebIntentPickerController::OnSendReturnMessage(
- webkit_glue::WebIntentReplyType reply_type) {
- ClosePicker();
- uma_reporter_->RecordServiceActiveDuration(reply_type);
-
- if (service_tab_ &&
- reply_type != webkit_glue::WEB_INTENT_SERVICE_CONTENTS_CLOSED) {
- Browser* browser = chrome::FindBrowserWithWebContents(service_tab_);
- if (browser) {
- int index = browser->tab_strip_model()->GetIndexOfWebContents(
- service_tab_);
- browser->tab_strip_model()->CloseWebContentsAt(
- index, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
-
- // Activate source tab.
- Browser* source_browser =
- chrome::FindBrowserWithWebContents(web_contents_);
- if (source_browser) {
- int source_index = source_browser->tab_strip_model()->
- GetIndexOfWebContents(web_contents_);
- source_browser->tab_strip_model()->ActivateTabAt(source_index, false);
- }
- }
- service_tab_ = NULL;
- }
-
- intents_dispatcher_ = NULL;
-}
-
-void WebIntentPickerController::AddServiceToModel(
- const webkit_glue::WebIntentServiceData& service) {
-
- picker_model_->AddInstalledService(
- service.title,
- service.service_url,
- service.disposition);
-
- icon_loader_->LoadFavicon(service.service_url);
-}
-
-void WebIntentPickerController::OnWebIntentServicesAvailable(
- const std::vector<webkit_glue::WebIntentServiceData>& services) {
- for (size_t i = 0; i < services.size(); ++i)
- AddServiceToModel(services[i]);
-
- RegistryCallsCompleted();
- AsyncOperationFinished();
-}
-
-void WebIntentPickerController::OnWebIntentServicesAvailableForExplicitIntent(
- const std::vector<webkit_glue::WebIntentServiceData>& services) {
- DCHECK(intents_dispatcher_);
- DCHECK(intents_dispatcher_->GetIntent().service.is_valid());
- for (size_t i = 0; i < services.size(); ++i) {
- if (services[i].service_url != intents_dispatcher_->GetIntent().service)
- continue;
-
- InvokeServiceWithSelection(services[i]);
- AsyncOperationFinished();
- return;
- }
-
- // No acceptable extension. The intent cannot be dispatched.
- intents_dispatcher_->SendReply(webkit_glue::WebIntentReply(
- webkit_glue::WEB_INTENT_REPLY_FAILURE, ASCIIToUTF16(
- "Explicit extension URL is not available.")));
-
- AsyncOperationFinished();
-}
-
-void WebIntentPickerController::OnWebIntentDefaultsAvailable(
- const DefaultWebIntentService& default_service) {
- if (!default_service.service_url.empty()) {
- // TODO(gbillock): this doesn't belong in the model, but keep it there
- // for now.
- picker_model_->set_default_service_url(GURL(default_service.service_url));
- }
-
- RegistryCallsCompleted();
- AsyncOperationFinished();
-}
-
-void WebIntentPickerController::RegistryCallsCompleted() {
- pending_registry_calls_count_--;
- if (pending_registry_calls_count_ != 0) return;
-
- if (picker_model_->default_service_url().is_valid()) {
- // If there's a default service, dispatch to it immediately
- // without showing the picker.
- const WebIntentPickerModel::InstalledService* default_service =
- picker_model_->GetInstalledServiceWithURL(
- GURL(picker_model_->default_service_url()));
- if (default_service != NULL) {
- InvokeService(*default_service);
- return;
- }
- }
-
- OnPickerEvent(kPickerEventRegistryDataComplete);
- OnIntentDataArrived();
-}
-
-void WebIntentPickerController::OnCWSIntentServicesAvailable(
- const CWSIntentsRegistry::IntentExtensionList& extensions) {
- ExtensionServiceInterface* extension_service =
- extensions::ExtensionSystem::Get(profile_)->extension_service();
-
- std::vector<WebIntentPickerModel::SuggestedExtension> suggestions;
- for (size_t i = 0; i < extensions.size(); ++i) {
- const CWSIntentsRegistry::IntentExtensionInfo& info = extensions[i];
-
- // Do not include suggestions for already installed extensions.
- if (extension_service->GetExtensionById(info.id, true))
- continue;
-
- suggestions.push_back(WebIntentPickerModel::SuggestedExtension(
- info.name, info.id, info.average_rating));
-
- icon_loader_->LoadExtensionIcon(info.icon_url, info.id);
- }
-
- picker_model_->AddSuggestedExtensions(suggestions);
-
- AsyncOperationFinished();
- pending_cws_request_ = false;
- OnIntentDataArrived();
-}
-
-
-void WebIntentPickerController::OnIntentDataArrived() {
- DCHECK(picker_model_.get());
-
- if (!pending_cws_request_ &&
- pending_registry_calls_count_ == 0)
- OnPickerEvent(kPickerEventAsyncDataComplete);
-}
-
-void WebIntentPickerController::Reset() {
- // Abandon all callbacks.
- weak_ptr_factory_.InvalidateWeakPtrs();
- timer_factory_.InvalidateWeakPtrs();
-
- // Reset state associated with callbacks.
- pending_async_count_ = 0;
- pending_registry_calls_count_ = 0;
- pending_cws_request_ = false;
-
- // Reset picker.
- icon_loader_.reset();
- picker_model_.reset(new WebIntentPickerModel());
- icon_loader_.reset(
- new web_intents::IconLoader(profile_, picker_model_.get()));
-
- picker_shown_ = false;
-
- DCHECK(web_contents_);
- WebContentsModalDialogManager* web_contents_modal_dialog_manager =
- WebContentsModalDialogManager::FromWebContents(web_contents_);
- web_contents_modal_dialog_manager->BlockWebContentsInteraction(false);
-}
-
-void WebIntentPickerController::OnShowExtensionInstallDialog(
- const ExtensionInstallPrompt::ShowParams& show_params,
- ExtensionInstallPrompt::Delegate* delegate,
- const ExtensionInstallPrompt::Prompt& prompt) {
- picker_model_->SetPendingExtensionInstallDelegate(delegate);
- picker_model_->SetPendingExtensionInstallPrompt(prompt);
- if (picker_)
- picker_->OnShowExtensionInstallDialog(show_params, delegate, prompt);
-}
-
-void WebIntentPickerController::SetWindowDispositionSource(
- content::WebContents* source,
- content::WebIntentsDispatcher* dispatcher) {
- DCHECK(source);
- DCHECK(dispatcher);
- location_bar_button_indicated_ = false;
- window_disposition_source_ = source;
- if (window_disposition_source_) {
- // This object is self-deleting when the source WebContents is destroyed.
- new SourceWindowObserver(window_disposition_source_,
- weak_ptr_factory_.GetWeakPtr());
- }
-
- if (dispatcher) {
- dispatcher->RegisterReplyNotification(
- base::Bind(&WebIntentPickerController::SourceDispatcherReplied,
- weak_ptr_factory_.GetWeakPtr()));
- }
- source_intents_dispatcher_ = dispatcher;
-}
-
-void WebIntentPickerController::SourceWebContentsDestroyed(
- content::WebContents* source) {
- window_disposition_source_ = NULL;
- // TODO(gbillock): redraw location bar to kill button
-}
-
-void WebIntentPickerController::SourceDispatcherReplied(
- webkit_glue::WebIntentReplyType reply_type) {
- source_intents_dispatcher_ = NULL;
- // TODO(gbillock): redraw location bar to kill button
-}
-
-bool WebIntentPickerController::ShowLocationBarPickerButton() {
- return window_disposition_source_ || source_intents_dispatcher_;
-}
-
-void WebIntentPickerController::OnPickerEvent(WebIntentPickerEvent event) {
- switch (event) {
- case kPickerEventHiddenSetupTimeout:
- DCHECK(dialog_state_ == kPickerSetup);
- SetDialogState(kPickerWaiting);
- break;
-
- case kPickerEventMaxWaitTimeExceeded:
- DCHECK(dialog_state_ == kPickerWaiting);
-
- // If registry data is complete, go to main dialog. Otherwise, wait.
- if (pending_registry_calls_count_ == 0)
- SetDialogState(kPickerMain);
- else
- SetDialogState(kPickerWaitLong);
- break;
-
- case kPickerEventRegistryDataComplete:
- DCHECK(dialog_state_ == kPickerSetup ||
- dialog_state_ == kPickerWaiting ||
- dialog_state_ == kPickerWaitLong);
-
- // If minimum wait dialog time is exceeded, display main dialog.
- // Either way, we don't do a thing.
- break;
-
- case kPickerEventAsyncDataComplete:
- DCHECK(dialog_state_ == kPickerSetup ||
- dialog_state_ == kPickerWaiting ||
- dialog_state_ == kPickerWaitLong ||
- dialog_state_ == kPickerInline);
-
- // In setup state, transition to main dialog. In waiting state, let
- // timer expire.
- if (dialog_state_ == kPickerSetup)
- SetDialogState(kPickerMain);
- break;
-
- default:
- NOTREACHED();
- break;
- }
-}
-
-void WebIntentPickerController::LocationBarPickerButtonClicked() {
- DCHECK(web_contents_);
- if (window_disposition_source_ && source_intents_dispatcher_) {
- Browser* service_browser =
- chrome::FindBrowserWithWebContents(web_contents_);
- if (!service_browser) return;
-
- Browser* client_browser =
- chrome::FindBrowserWithWebContents(window_disposition_source_);
- if (!client_browser)
- return;
- int client_index = client_browser->tab_strip_model()->GetIndexOfWebContents(
- window_disposition_source_);
- DCHECK(client_index != TabStripModel::kNoTab);
-
- source_intents_dispatcher_->ResetDispatch();
-
- WebIntentPickerController* client_controller =
- WebIntentPickerController::FromWebContents(window_disposition_source_);
- DCHECK(client_controller);
-
- // This call deletes this object, so anything below here needs to
- // use stack variables.
- chrome::CloseWebContents(service_browser, web_contents_, true);
-
- // Re-open the other tab and activate the picker.
- client_browser->window()->Activate();
- client_browser->tab_strip_model()->ActivateTabAt(client_index, true);
- // The picker has been Reset() when the new tab is created; need to fully
- // reload.
- client_controller->ReshowDialog();
- }
- // TODO(gbillock): figure out what we ought to do in this case. Probably
- // nothing? Refresh the location bar?
-}
-
-void WebIntentPickerController::AsyncOperationFinished() {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- if (--pending_async_count_ == 0) {
- if (picker_)
- picker_->OnPendingAsyncCompleted();
- }
-}
-
-void WebIntentPickerController::InvokeServiceWithSelection(
- const webkit_glue::WebIntentServiceData& service) {
- if (picker_shown_) {
- intents_dispatcher_->SendReply(webkit_glue::WebIntentReply(
- webkit_glue::WEB_INTENT_REPLY_FAILURE,
- ASCIIToUTF16("Simultaneous intent invocation.")));
- return;
- }
-
- // TODO(gbillock): this is a bit hacky and exists because in the inline case,
- // the picker currently assumes it exists.
- AddServiceToModel(service);
- picker_model_->set_show_use_another_service(false);
-
- if (service.disposition ==
- webkit_glue::WebIntentServiceData::DISPOSITION_INLINE) {
- picker_model_->SetInlineDisposition(service.service_url);
- SetDialogState(kPickerInline);
- return;
- }
-
- OnServiceChosen(service.service_url, service.disposition, kSuppressDefaults);
-}
-
-void WebIntentPickerController::InvokeService(
- const WebIntentPickerModel::InstalledService& service) {
- if (service.disposition ==
- webkit_glue::WebIntentServiceData::DISPOSITION_INLINE) {
- // This call will ensure the picker dialog is created and initialized.
- picker_model_->SetInlineDisposition(service.url);
- SetDialogState(kPickerInline);
- return;
- }
- OnServiceChosen(service.url, service.disposition, kEnableDefaults);
-}
-
-void WebIntentPickerController::SetDialogState(WebIntentPickerState state) {
- // Ignore events that don't change state.
- if (state == dialog_state_)
- return;
-
- // Any pending timers are abandoned on state changes.
- timer_factory_.InvalidateWeakPtrs();
-
- switch (state) {
- case kPickerSetup:
- DCHECK_EQ(dialog_state_, kPickerHidden);
- // Post timer CWS pending
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- base::Bind(&WebIntentPickerController::OnPickerEvent,
- timer_factory_.GetWeakPtr(),
- kPickerEventHiddenSetupTimeout),
- base::TimeDelta::FromMilliseconds(kMaxHiddenSetupTimeMs));
- break;
-
- case kPickerWaiting:
- DCHECK_EQ(dialog_state_, kPickerSetup);
- // Waiting dialog can be dismissed after minimum wait time.
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- base::Bind(&WebIntentPickerController::OnPickerEvent,
- timer_factory_.GetWeakPtr(),
- kPickerEventMaxWaitTimeExceeded),
- base::TimeDelta::FromMilliseconds(kMinThrobberDisplayTimeMs));
- break;
-
- case kPickerWaitLong:
- DCHECK_EQ(dialog_state_, kPickerWaiting);
- break;
-
- case kPickerInline:
- // Intentional fall-through.
- case kPickerMain:
- // No DCHECK - main state can be reached from any state.
- // Ready to display data.
- picker_model_->SetWaitingForSuggestions(false);
- break;
-
- case kPickerHidden:
- Reset();
- break;
-
- default:
- NOTREACHED();
- break;
-
- }
-
- dialog_state_ = state;
-
- // Create picker dialog when changing away from hidden state.
- if (dialog_state_ != kPickerHidden && dialog_state_ != kPickerSetup)
- CreatePicker();
-}
-
-void WebIntentPickerController::CreatePicker() {
- // If picker is non-NULL, it was set by a test.
- if (picker_ == NULL)
- picker_ = WebIntentPicker::Create(web_contents_, this, picker_model_.get());
- picker_->SetActionString(WebIntentPicker::GetDisplayStringForIntentAction(
- picker_model_->action()));
- web_intents::RecordPickerShow(
- uma_bucket_, picker_model_->GetInstalledServiceCount());
- picker_shown_ = true;
-}
-
-void WebIntentPickerController::ClosePicker() {
- SetDialogState(kPickerHidden);
- if (picker_)
- picker_->Close();
-}
-
-void WebIntentPickerController::CancelDownload() {
- if (!download_id_.IsValid())
- return;
- Profile* profile =
- Profile::FromBrowserContext(web_contents_->GetBrowserContext());
- content::DownloadManager* download_manager =
- content::BrowserContext::GetDownloadManager(profile);
- if (!download_manager)
- return;
- content::DownloadItem* item =
- download_manager->GetDownload(download_id_.local());
- if (item)
- item->Cancel(true);
- download_id_ = content::DownloadId();
-}

Powered by Google App Engine
This is Rietveld 408576698