| // 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. |
| |
| #ifndef CHROME_BROWSER_UI_INTENTS_WEB_INTENT_PICKER_CONTROLLER_H_ |
| #define CHROME_BROWSER_UI_INTENTS_WEB_INTENT_PICKER_CONTROLLER_H_ |
| |
| #include <vector> |
| |
| #include "base/compiler_specific.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/string16.h" |
| #include "chrome/browser/extensions/webstore_installer.h" |
| #include "chrome/browser/favicon/favicon_service.h" |
| #include "chrome/browser/intents/cws_intents_registry.h" |
| #include "chrome/browser/intents/web_intents_registry.h" |
| #include "chrome/browser/intents/web_intents_reporting.h" |
| #include "chrome/browser/tab_contents/web_contents_user_data.h" |
| #include "chrome/browser/ui/intents/web_intent_picker_delegate.h" |
| #include "content/public/browser/notification_observer.h" |
| #include "content/public/browser/notification_registrar.h" |
| #include "webkit/glue/web_intent_data.h" |
| #include "webkit/glue/web_intent_reply_data.h" |
| #include "webkit/glue/web_intent_service_data.h" |
| |
| class Browser; |
| struct DefaultWebIntentService; |
| class GURL; |
| class Profile; |
| class WebIntentPicker; |
| class WebIntentPickerModel; |
| |
| namespace content { |
| class WebContents; |
| class WebIntentsDispatcher; |
| } |
| |
| namespace webkit_glue { |
| struct WebIntentServiceData; |
| } |
| |
| // Controls the creation of the WebIntentPicker UI and forwards the user's |
| // intent handler choice back to the WebContents object. |
| class WebIntentPickerController |
| : public content::NotificationObserver, |
| public WebIntentPickerDelegate, |
| public extensions::WebstoreInstaller::Delegate, |
| public WebContentsUserData<WebIntentPickerController> { |
| public: |
| |
| // The various states that the UI may be in. Public for testing. |
| enum WebIntentPickerState { |
| kPickerHidden, // Picker not displayed at all. |
| kPickerSetup, // Initial setup. Acquires data, keeps picker hidden. |
| kPickerWaiting, // Displaying "waiting for CWS". |
| kPickerWaitLong, // "waiting" has displayed for longer than min. time. |
| kPickerMain, // Displaying main picker dialog. |
| kPickerInline, // Displaying inline intent handler. |
| }; |
| |
| // Events that happen during picker life time. Drive state machine. |
| enum WebIntentPickerEvent { |
| kPickerEventHiddenSetupTimeout, // Time for hidden setup exired. |
| kPickerEventMaxWaitTimeExceeded, // Exceeded max wait time for CWS results. |
| kPickerEventRegistryDataComplete, // Data from the registry has arrived. |
| kPickerEventAsyncDataComplete, // Data from registry and CWS has arrived. |
| }; |
| |
| virtual ~WebIntentPickerController(); |
| |
| // Sets the intent data and return pathway handler object for which |
| // this picker was created. The picker takes ownership of |
| // |intents_dispatcher|. |intents_dispatcher| must not be NULL. |
| void SetIntentsDispatcher(content::WebIntentsDispatcher* intents_dispatcher); |
| |
| // Shows the web intent picker given the intent |action| and MIME-type |type|. |
| void ShowDialog(const string16& action, |
| const string16& type); |
| |
| // Called by the location bar to see whether the web intents picker button |
| // should be shown. |
| bool ShowLocationBarPickerTool(); |
| |
| // Called by the location bar to notify picker that the button was clicked. |
| // Called in the controller of the tab which is displaying the service. |
| void LocationBarPickerToolClicked(); |
| |
| // Called to notify a controller for a page hosting a web intents service |
| // that the source WebContents has been destroyed. |
| void SourceWebContentsDestroyed(content::WebContents* source); |
| |
| protected: |
| // content::NotificationObserver implementation. |
| virtual void Observe(int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) OVERRIDE; |
| |
| // WebIntentPickerDelegate implementation. |
| virtual void OnServiceChosen( |
| const GURL& url, |
| webkit_glue::WebIntentServiceData::Disposition disposition) OVERRIDE; |
| virtual void OnInlineDispositionWebContentsCreated( |
| content::WebContents* web_contents) OVERRIDE; |
| virtual void OnExtensionInstallRequested(const std::string& id) OVERRIDE; |
| virtual void OnExtensionLinkClicked( |
| const std::string& id, |
| WindowOpenDisposition disposition) OVERRIDE; |
| virtual void OnSuggestionsLinkClicked( |
| WindowOpenDisposition disposition) OVERRIDE; |
| virtual void OnUserCancelledPickerDialog() OVERRIDE; |
| virtual void OnChooseAnotherService() OVERRIDE; |
| virtual void OnClosing() OVERRIDE; |
| |
| // extensions::WebstoreInstaller::Delegate implementation. |
| virtual void OnExtensionInstallSuccess(const std::string& id) OVERRIDE; |
| virtual void OnExtensionInstallFailure(const std::string& id, |
| const std::string& error) OVERRIDE; |
| |
| private: |
| explicit WebIntentPickerController(content::WebContents* web_contents); |
| static int kUserDataKey; |
| friend class WebContentsUserData<WebIntentPickerController>; |
| |
| friend class WebIntentPickerControllerTest; |
| friend class WebIntentPickerControllerBrowserTest; |
| friend class WebIntentPickerControllerIncognitoBrowserTest; |
| friend class WebIntentsButtonDecorationTest; |
| |
| // Forward declaraton of the internal implementation class. |
| class UMAReporter; |
| |
| // Dispatches intent to a just-installed extension with ID |extension_id|. |
| void DispatchToInstalledExtension(const std::string& extension_id); |
| |
| // Adds a service to the data model. |
| void AddServiceToModel(const webkit_glue::WebIntentServiceData& service); |
| |
| // Register the user-selected service (indicated by the passed |url|) as |
| // the default for the combination of action/type/options in the picker. |
| void SetDefaultServiceForSelection(const GURL& url); |
| |
| // Calculate a digest value for the services in the picker. |
| int64 DigestServices(); |
| |
| // Gets a notification when the return message is sent to the source tab, |
| // so we can close the picker dialog or service tab. |
| void OnSendReturnMessage(webkit_glue::WebIntentReplyType reply_type); |
| |
| // Exposed for tests only. |
| void set_picker(WebIntentPicker* picker) { picker_ = picker; } |
| |
| // Exposed for tests only. |
| void set_model_observer(WebIntentPickerModelObserver* observer) { |
| picker_model_->set_observer(observer); |
| } |
| |
| // Notify the controller that its TabContents is hosting a web intents |
| // service. Sets the source and dispatcher for the invoking client. |
| void SetWindowDispositionSource(content::WebContents* source, |
| content::WebIntentsDispatcher* dispatcher); |
| |
| // Called to notify a controller for a page hosting a web intents service |
| // that the source dispatcher has been replied on. |
| void SourceDispatcherReplied(webkit_glue::WebIntentReplyType reply_type); |
| |
| // Called by the WebIntentsRegistry, returning |services|, which is |
| // a list of WebIntentServiceData matching the query. |
| void OnWebIntentServicesAvailable( |
| const std::vector<webkit_glue::WebIntentServiceData>& services); |
| |
| // Called when a default service is returned from the WebIntentsRegistry. |
| // (Still called with default_service.service_url empty if there are no |
| // defaults.) |
| void OnWebIntentDefaultsAvailable( |
| const DefaultWebIntentService& default_service); |
| |
| // Coordination method which is delegated to by the registry calls to get |
| // services and defaults. Checks whether the picker should be shown or if |
| // default choices allow it to be skipped. |
| void RegistryCallsCompleted(); |
| |
| // Called when WebIntentServiceData is ready for checking extensions |
| // when dispatching explicit intents. Gets |services| |
| // from the WebIntentsRegistry to check for known urls/extensions and find |
| // disposition data. |
| void OnWebIntentServicesAvailableForExplicitIntent( |
| const std::vector<webkit_glue::WebIntentServiceData>& services); |
| |
| // Called when a favicon is returned from the FaviconService. |
| void OnFaviconDataAvailable( |
| FaviconService::Handle handle, |
| const history::FaviconImageResult& image_result); |
| |
| // Called when IntentExtensionInfo is returned from the CWSIntentsRegistry. |
| void OnCWSIntentServicesAvailable( |
| const CWSIntentsRegistry::IntentExtensionList& extensions); |
| |
| // Called when a suggested extension's icon is fetched. |
| void OnExtensionIconURLFetchComplete(const string16& extension_id, |
| const net::URLFetcher* source); |
| |
| // Called whenever intent data (both from registry and CWS) arrives. |
| void OnIntentDataArrived(); |
| |
| // Reset internal state to default values. |
| void Reset(); |
| |
| typedef base::Callback<void(const gfx::Image&)> |
| ExtensionIconAvailableCallback; |
| // Called on a worker thread to decode and resize the extension's icon. |
| static void DecodeExtensionIconAndResize( |
| scoped_ptr<std::string> icon_response, |
| const ExtensionIconAvailableCallback& callback, |
| const base::Closure& unavailable_callback); |
| |
| // Called when an extension's icon is successfully decoded and resized. |
| void OnExtensionIconAvailable(const string16& extension_id, |
| const gfx::Image& icon_image); |
| |
| // Called when an extension's icon failed to be decoded or resized. |
| void OnExtensionIconUnavailable(const string16& extension_id); |
| |
| // Signals that a picker event has occurred. |
| void OnPickerEvent(WebIntentPickerEvent event); |
| |
| // Decrements the |pending_async_count_| and notifies the picker if it |
| // reaches zero. |
| void AsyncOperationFinished(); |
| |
| // Invoke the specified service at |service_url| with chosen |disposition|. |
| void InvokeService(const WebIntentPickerModel::InstalledService& service); |
| |
| // Sets current dialog state. |
| void SetDialogState(WebIntentPickerState state); |
| |
| // Helper to create picker dialog UI. |
| void CreatePicker(); |
| |
| // Closes the currently active picker. |
| void ClosePicker(); |
| |
| // Re-starts the process of showing the dialog, suppressing any default |
| // queries. Called on the user clicking Use-Another-Service. |
| void ReshowDialog(); |
| |
| // Delegate for ShowDialog and ReshowDialog. Starts all the data queries for |
| // loading the picker model and showing the dialog. |
| void ShowDialog(bool suppress_defaults); |
| |
| WebIntentPickerState dialog_state_; // Current state of the dialog. |
| |
| // A weak pointer to the web contents that the picker is displayed on. |
| content::WebContents* web_contents_; |
| |
| // A weak pointer to the profile for the web contents. |
| Profile* profile_; |
| |
| // A notification registrar, listening for notifications when the tab closes |
| // to close the picker ui. |
| content::NotificationRegistrar registrar_; |
| |
| // A weak pointer to the picker this controller controls. |
| WebIntentPicker* picker_; |
| |
| // The model for the picker. Owned by this controller. It should not be NULL |
| // while this controller exists, even if the picker is not shown. |
| scoped_ptr<WebIntentPickerModel> picker_model_; |
| |
| // UMA reporting manager. |
| scoped_ptr<UMAReporter> uma_reporter_; |
| |
| // A count of the outstanding asynchronous calls. |
| int pending_async_count_; |
| |
| // A count of outstanding WebIntentsRegistry calls. |
| int pending_registry_calls_count_; |
| |
| // Indicator that there is a pending request for cws data. |
| bool pending_cws_request_; |
| |
| // Is true if the picker is currently visible. |
| // This bool is not equivalent to picker != NULL in a unit test. In that |
| // case, a picker may be non-NULL before it is shown. |
| bool picker_shown_; |
| |
| #if defined(TOOLKIT_VIEWS) |
| // Set to true if user cancelled the picker dialog. Set to false if the picker |
| // dialog is closing for any other reason. |
| // TODO(rouslan): We need to fix DialogDelegate in Views to notify us when the |
| // user closes the picker dialog. This boolean is a mediocre workaround for |
| // lack of that information. |
| bool cancelled_; |
| #endif |
| |
| // Weak pointer to the source WebContents for the intent if the TabContents |
| // with which this controller is associated is hosting a web intents window |
| // disposition service. |
| content::WebContents* window_disposition_source_; |
| |
| // If this tab is hosting a web intents service, a weak pointer to dispatcher |
| // that invoked us. Weak pointer. |
| content::WebIntentsDispatcher* source_intents_dispatcher_; |
| |
| // Weak pointer to the routing object for the renderer which launched the |
| // intent. Contains the intent data and a way to signal back to the |
| // client page. |
| content::WebIntentsDispatcher* intents_dispatcher_; |
| |
| // Weak pointer to the tab servicing the intent. Remembered in order to |
| // close it when a reply is sent. |
| content::WebContents* service_tab_; |
| |
| // Request consumer used when asynchronously loading favicons. |
| CancelableRequestConsumerTSimple<size_t> favicon_consumer_; |
| |
| // Factory for weak pointers used in callbacks for async calls to load the |
| // picker model. |
| base::WeakPtrFactory<WebIntentPickerController> weak_ptr_factory_; |
| |
| // Timer factory for minimum display time of "waiting" dialog. |
| base::WeakPtrFactory<WebIntentPickerController> timer_factory_; |
| |
| // Weak pointers for the dispatcher OnSendReturnMessage will not be |
| // cancelled on picker close. |
| base::WeakPtrFactory<WebIntentPickerController> dispatcher_factory_; |
| |
| // Bucket identifier for UMA reporting. Saved off in a field |
| // to avoid repeated calculation of the bucket across |
| // multiple UMA calls. Should be recalculated each time |
| // |intents_dispatcher_| is set. |
| web_intents::UMABucket uma_bucket_; |
| |
| DISALLOW_COPY_AND_ASSIGN(WebIntentPickerController); |
| }; |
| |
| #endif // CHROME_BROWSER_UI_INTENTS_WEB_INTENT_PICKER_CONTROLLER_H_ |