summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui/intents/web_intent_picker_controller.h
blob: 6f479bb1feaeab8f9e25a82b10beefdd9170ff54 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
// 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/common/web_contents_user_data.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/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);
  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_