OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/intents/web_intent_picker_controller.h" | 5 #include "chrome/browser/ui/intents/web_intent_picker_controller.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
11 #include "chrome/browser/extensions/webstore_installer.h" | 11 #include "chrome/browser/ui/browser.h" |
12 #include "chrome/browser/favicon/favicon_service.h" | 12 #include "chrome/browser/favicon/favicon_service.h" |
13 #include "chrome/browser/intents/default_web_intent_service.h" | 13 #include "chrome/browser/intents/default_web_intent_service.h" |
14 #include "chrome/browser/intents/web_intents_registry_factory.h" | 14 #include "chrome/browser/intents/web_intents_registry_factory.h" |
15 #include "chrome/browser/intents/cws_intents_registry_factory.h" | 15 #include "chrome/browser/intents/cws_intents_registry_factory.h" |
16 #include "chrome/browser/profiles/profile.h" | 16 #include "chrome/browser/profiles/profile.h" |
17 #include "chrome/browser/tab_contents/tab_util.h" | 17 #include "chrome/browser/tab_contents/tab_util.h" |
18 #include "chrome/browser/tabs/tab_strip_model.h" | 18 #include "chrome/browser/tabs/tab_strip_model.h" |
19 #include "chrome/browser/ui/browser.h" | |
20 #include "chrome/browser/ui/browser_list.h" | 19 #include "chrome/browser/ui/browser_list.h" |
21 #include "chrome/browser/ui/browser_navigator.h" | 20 #include "chrome/browser/ui/browser_navigator.h" |
22 #include "chrome/browser/ui/intents/web_intent_picker.h" | 21 #include "chrome/browser/ui/intents/web_intent_picker.h" |
23 #include "chrome/browser/ui/intents/web_intent_picker_model.h" | 22 #include "chrome/browser/ui/intents/web_intent_picker_model.h" |
24 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" | 23 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
25 #include "chrome/browser/webdata/web_data_service.h" | 24 #include "chrome/browser/webdata/web_data_service.h" |
26 #include "chrome/common/chrome_notification_types.h" | 25 #include "chrome/common/chrome_notification_types.h" |
27 #include "content/public/browser/browser_thread.h" | 26 #include "content/public/browser/browser_thread.h" |
28 #include "content/public/browser/navigation_controller.h" | |
29 #include "content/public/browser/notification_source.h" | 27 #include "content/public/browser/notification_source.h" |
30 #include "content/public/browser/web_contents.h" | 28 #include "content/public/browser/web_contents.h" |
31 #include "content/public/browser/web_intents_dispatcher.h" | 29 #include "content/public/browser/web_intents_dispatcher.h" |
32 #include "content/public/common/url_fetcher.h" | 30 #include "content/public/common/url_fetcher.h" |
33 #include "content/public/common/url_fetcher_delegate.h" | 31 #include "content/public/common/url_fetcher_delegate.h" |
34 #include "net/base/load_flags.h" | 32 #include "net/base/load_flags.h" |
35 #include "skia/ext/image_operations.h" | 33 #include "skia/ext/image_operations.h" |
36 #include "ui/gfx/codec/png_codec.h" | 34 #include "ui/gfx/codec/png_codec.h" |
37 #include "ui/gfx/favicon_size.h" | 35 #include "ui/gfx/favicon_size.h" |
38 #include "ui/gfx/image/image.h" | 36 #include "ui/gfx/image/image.h" |
(...skipping 22 matching lines...) Expand all Loading... |
61 case webkit_glue::WebIntentServiceData::DISPOSITION_INLINE: | 59 case webkit_glue::WebIntentServiceData::DISPOSITION_INLINE: |
62 return WebIntentPickerModel::DISPOSITION_INLINE; | 60 return WebIntentPickerModel::DISPOSITION_INLINE; |
63 case webkit_glue::WebIntentServiceData::DISPOSITION_WINDOW: | 61 case webkit_glue::WebIntentServiceData::DISPOSITION_WINDOW: |
64 return WebIntentPickerModel::DISPOSITION_WINDOW; | 62 return WebIntentPickerModel::DISPOSITION_WINDOW; |
65 default: | 63 default: |
66 NOTREACHED(); | 64 NOTREACHED(); |
67 return WebIntentPickerModel::DISPOSITION_WINDOW; | 65 return WebIntentPickerModel::DISPOSITION_WINDOW; |
68 } | 66 } |
69 } | 67 } |
70 | 68 |
71 // Self-deleting trampoline that forwards a WebIntentsRegistry response to a | 69 class URLFetcherTrampoline : public content::URLFetcherDelegate { |
72 // callback. | |
73 class WebIntentsRegistryTrampoline : public WebIntentsRegistry::Consumer { | |
74 public: | 70 public: |
75 typedef std::vector<webkit_glue::WebIntentServiceData> IntentServices; | 71 typedef base::Callback<void(const content::URLFetcher* source)> Callback; |
76 typedef base::Callback<void(const IntentServices&)> ForwardingCallback; | |
77 | 72 |
78 explicit WebIntentsRegistryTrampoline(const ForwardingCallback& callback); | 73 explicit URLFetcherTrampoline(const Callback& callback) |
79 ~WebIntentsRegistryTrampoline(); | 74 : callback_(callback) {} |
| 75 ~URLFetcherTrampoline() {} |
80 | 76 |
81 // WebIntentsRegistry::Consumer implementation. | 77 // content::URLFetcherDelegate implementation. |
82 virtual void OnIntentsQueryDone( | 78 virtual void OnURLFetchComplete(const content::URLFetcher* source) OVERRIDE { |
83 WebIntentsRegistry::QueryID, | 79 callback_.Run(source); |
84 const std::vector<webkit_glue::WebIntentServiceData>& services) OVERRIDE; | 80 delete source; |
85 virtual void OnIntentsDefaultsQueryDone( | 81 delete this; |
86 WebIntentsRegistry::QueryID, | 82 } |
87 const DefaultWebIntentService& default_service) OVERRIDE {} | |
88 | 83 |
89 private: | 84 private: |
90 // Forwarding callback from |OnIntentsQueryDone|. | 85 Callback callback_; |
91 ForwardingCallback callback_; | |
92 }; | 86 }; |
93 | 87 |
94 WebIntentsRegistryTrampoline::WebIntentsRegistryTrampoline( | |
95 const ForwardingCallback& callback) | |
96 : callback_(callback) { | |
97 } | |
98 | |
99 WebIntentsRegistryTrampoline::~WebIntentsRegistryTrampoline() { | |
100 } | |
101 | |
102 void WebIntentsRegistryTrampoline::OnIntentsQueryDone( | |
103 WebIntentsRegistry::QueryID, | |
104 const std::vector<webkit_glue::WebIntentServiceData>& services) { | |
105 DCHECK(!callback_.is_null()); | |
106 callback_.Run(services); | |
107 delete this; | |
108 } | |
109 | |
110 // Self-deleting trampoline that forwards A URLFetcher response to a callback. | |
111 class URLFetcherTrampoline : public content::URLFetcherDelegate { | |
112 public: | |
113 typedef base::Callback<void(const content::URLFetcher* source)> | |
114 ForwardingCallback; | |
115 | |
116 explicit URLFetcherTrampoline(const ForwardingCallback& callback); | |
117 ~URLFetcherTrampoline(); | |
118 | |
119 // content::URLFetcherDelegate implementation. | |
120 virtual void OnURLFetchComplete(const content::URLFetcher* source) OVERRIDE; | |
121 | |
122 private: | |
123 // Fowarding callback from |OnURLFetchComplete|. | |
124 ForwardingCallback callback_; | |
125 }; | |
126 | |
127 URLFetcherTrampoline::URLFetcherTrampoline(const ForwardingCallback& callback) | |
128 : callback_(callback) { | |
129 } | |
130 | |
131 URLFetcherTrampoline::~URLFetcherTrampoline() { | |
132 } | |
133 | |
134 void URLFetcherTrampoline::OnURLFetchComplete( | |
135 const content::URLFetcher* source) { | |
136 DCHECK(!callback_.is_null()); | |
137 callback_.Run(source); | |
138 delete source; | |
139 delete this; | |
140 } | |
141 | |
142 } // namespace | 88 } // namespace |
143 | 89 |
144 WebIntentPickerController::WebIntentPickerController( | 90 WebIntentPickerController::WebIntentPickerController( |
145 TabContentsWrapper* wrapper) | 91 TabContentsWrapper* wrapper) |
146 : wrapper_(wrapper), | 92 : wrapper_(wrapper), |
147 picker_(NULL), | 93 picker_(NULL), |
148 picker_model_(new WebIntentPickerModel()), | 94 picker_model_(new WebIntentPickerModel()), |
149 pending_async_count_(0), | 95 pending_async_count_(0), |
150 picker_shown_(false), | 96 picker_shown_(false), |
151 intents_dispatcher_(NULL), | 97 intents_dispatcher_(NULL), |
(...skipping 24 matching lines...) Expand all Loading... |
176 // Only show a picker once. | 122 // Only show a picker once. |
177 if (picker_shown_) | 123 if (picker_shown_) |
178 return; | 124 return; |
179 | 125 |
180 // TODO(binji): Figure out what to do when intents are invoked from incognito | 126 // TODO(binji): Figure out what to do when intents are invoked from incognito |
181 // mode. | 127 // mode. |
182 if (wrapper_->profile()->IsOffTheRecord()) | 128 if (wrapper_->profile()->IsOffTheRecord()) |
183 return; | 129 return; |
184 | 130 |
185 picker_model_->Clear(); | 131 picker_model_->Clear(); |
186 picker_model_->set_action(action); | |
187 picker_model_->set_mimetype(type); | |
188 | 132 |
189 // If picker is non-NULL, it was set by a test. | 133 // If picker is non-NULL, it was set by a test. |
190 if (picker_ == NULL) { | 134 if (picker_ == NULL) { |
191 picker_ = WebIntentPicker::Create(browser, wrapper_, this, | 135 picker_ = WebIntentPicker::Create(browser, wrapper_, this, |
192 picker_model_.get()); | 136 picker_model_.get()); |
193 } | 137 } |
194 | 138 |
195 picker_shown_ = true; | 139 picker_shown_ = true; |
196 pending_async_count_+= 2; | 140 pending_async_count_+= 2; |
197 GetWebIntentsRegistry(wrapper_)->GetIntentServices( | 141 GetWebIntentsRegistry(wrapper_)->GetIntentServices(action, type, this); |
198 action, type, | 142 GetCWSIntentsRegistry(wrapper_)->GetIntentServices(action, type, |
199 // WebIntentsRegistryTrampoline is self-deleting. | |
200 new WebIntentsRegistryTrampoline( | |
201 base::Bind(&WebIntentPickerController::OnWebIntentServicesAvailable, | |
202 weak_ptr_factory_.GetWeakPtr()))); | |
203 GetCWSIntentsRegistry(wrapper_)->GetIntentServices( | |
204 action, type, | |
205 base::Bind(&WebIntentPickerController::OnCWSIntentServicesAvailable, | 143 base::Bind(&WebIntentPickerController::OnCWSIntentServicesAvailable, |
206 weak_ptr_factory_.GetWeakPtr())); | 144 weak_ptr_factory_.GetWeakPtr())); |
207 } | 145 } |
208 | 146 |
209 void WebIntentPickerController::Observe( | 147 void WebIntentPickerController::Observe( |
210 int type, | 148 int type, |
211 const content::NotificationSource& source, | 149 const content::NotificationSource& source, |
212 const content::NotificationDetails& details) { | 150 const content::NotificationDetails& details) { |
213 DCHECK(type == content::NOTIFICATION_LOAD_START || | 151 DCHECK(type == content::NOTIFICATION_LOAD_START || |
214 type == content::NOTIFICATION_TAB_CLOSING); | 152 type == content::NOTIFICATION_TAB_CLOSING); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 break; | 205 break; |
268 } | 206 } |
269 } | 207 } |
270 | 208 |
271 void WebIntentPickerController::OnInlineDispositionWebContentsCreated( | 209 void WebIntentPickerController::OnInlineDispositionWebContentsCreated( |
272 content::WebContents* web_contents) { | 210 content::WebContents* web_contents) { |
273 if (web_contents) | 211 if (web_contents) |
274 intents_dispatcher_->DispatchIntent(web_contents); | 212 intents_dispatcher_->DispatchIntent(web_contents); |
275 } | 213 } |
276 | 214 |
277 void WebIntentPickerController::OnExtensionInstallRequested( | |
278 const std::string& id) { | |
279 webstore_installer_ = new WebstoreInstaller( | |
280 wrapper_->profile(), this, &wrapper_->web_contents()->GetController(), id, | |
281 WebstoreInstaller::FLAG_INLINE_INSTALL); | |
282 | |
283 pending_async_count_++; | |
284 webstore_installer_->Start(); | |
285 } | |
286 | |
287 void WebIntentPickerController::OnCancelled() { | 215 void WebIntentPickerController::OnCancelled() { |
288 if (!intents_dispatcher_) | 216 if (!intents_dispatcher_) |
289 return; | 217 return; |
290 | 218 |
291 if (service_tab_) { | 219 if (service_tab_) { |
292 intents_dispatcher_->SendReplyMessage( | 220 intents_dispatcher_->SendReplyMessage( |
293 webkit_glue::WEB_INTENT_SERVICE_TAB_CLOSED, string16()); | 221 webkit_glue::WEB_INTENT_SERVICE_TAB_CLOSED, string16()); |
294 } else { | 222 } else { |
295 intents_dispatcher_->SendReplyMessage( | 223 intents_dispatcher_->SendReplyMessage( |
296 webkit_glue::WEB_INTENT_PICKER_CANCELLED, string16()); | 224 webkit_glue::WEB_INTENT_PICKER_CANCELLED, string16()); |
297 } | 225 } |
298 | 226 |
299 ClosePicker(); | 227 ClosePicker(); |
300 } | 228 } |
301 | 229 |
302 void WebIntentPickerController::OnClosing() { | 230 void WebIntentPickerController::OnClosing() { |
303 picker_shown_ = false; | 231 picker_shown_ = false; |
304 picker_ = NULL; | 232 picker_ = NULL; |
305 } | 233 } |
306 | 234 |
307 void WebIntentPickerController::OnExtensionInstallSuccess( | |
308 const std::string& id) { | |
309 picker_->OnExtensionInstallSuccess(id); | |
310 pending_async_count_++; | |
311 GetWebIntentsRegistry(wrapper_)->GetIntentServicesForExtensionFilter( | |
312 picker_model_->action(), | |
313 picker_model_->mimetype(), | |
314 id, | |
315 new WebIntentsRegistryTrampoline( | |
316 base::Bind( | |
317 &WebIntentPickerController::OnExtensionInstallServiceAvailable, | |
318 weak_ptr_factory_.GetWeakPtr()))); | |
319 AsyncOperationFinished(); | |
320 } | |
321 | |
322 void WebIntentPickerController::OnExtensionInstallFailure( | |
323 const std::string& id, | |
324 const std::string& error) { | |
325 picker_->OnExtensionInstallFailure(id); | |
326 AsyncOperationFinished(); | |
327 } | |
328 | |
329 void WebIntentPickerController::OnSendReturnMessage( | 235 void WebIntentPickerController::OnSendReturnMessage( |
330 webkit_glue::WebIntentReplyType reply_type) { | 236 webkit_glue::WebIntentReplyType reply_type) { |
331 ClosePicker(); | 237 ClosePicker(); |
332 | 238 |
333 if (service_tab_ && | 239 if (service_tab_ && |
334 reply_type != webkit_glue::WEB_INTENT_SERVICE_TAB_CLOSED) { | 240 reply_type != webkit_glue::WEB_INTENT_SERVICE_TAB_CLOSED) { |
335 int index = TabStripModel::kNoTab; | 241 int index = TabStripModel::kNoTab; |
336 Browser* browser = Browser::GetBrowserForController( | 242 Browser* browser = Browser::GetBrowserForController( |
337 &service_tab_->GetController(), &index); | 243 &service_tab_->GetController(), &index); |
338 if (browser) { | 244 if (browser) { |
339 browser->tabstrip_model()->CloseTabContentsAt( | 245 browser->tabstrip_model()->CloseTabContentsAt( |
340 index, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB); | 246 index, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB); |
341 | 247 |
342 // Activate source tab. | 248 // Activate source tab. |
343 Browser* source_browser = | 249 Browser* source_browser = |
344 BrowserList::FindBrowserWithWebContents(wrapper_->web_contents()); | 250 BrowserList::FindBrowserWithWebContents(wrapper_->web_contents()); |
345 if (source_browser) { | 251 if (source_browser) { |
346 int source_index = | 252 int source_index = |
347 source_browser->tabstrip_model()->GetIndexOfTabContents(wrapper_); | 253 source_browser->tabstrip_model()->GetIndexOfTabContents(wrapper_); |
348 source_browser->ActivateTabAt(source_index, false); | 254 source_browser->ActivateTabAt(source_index, false); |
349 } | 255 } |
350 } | 256 } |
351 service_tab_ = NULL; | 257 service_tab_ = NULL; |
352 } | 258 } |
353 | 259 |
354 intents_dispatcher_ = NULL; | 260 intents_dispatcher_ = NULL; |
355 } | 261 } |
356 | 262 |
357 void WebIntentPickerController::OnWebIntentServicesAvailable( | 263 void WebIntentPickerController::OnIntentsQueryDone( |
| 264 WebIntentsRegistry::QueryID, |
358 const std::vector<webkit_glue::WebIntentServiceData>& services) { | 265 const std::vector<webkit_glue::WebIntentServiceData>& services) { |
359 FaviconService* favicon_service = GetFaviconService(wrapper_); | 266 FaviconService* favicon_service = GetFaviconService(wrapper_); |
360 for (size_t i = 0; i < services.size(); ++i) { | 267 for (size_t i = 0; i < services.size(); ++i) { |
361 picker_model_->AddInstalledService( | 268 picker_model_->AddInstalledService( |
362 services[i].title, | 269 services[i].title, |
363 services[i].service_url, | 270 services[i].service_url, |
364 ConvertDisposition(services[i].disposition)); | 271 ConvertDisposition(services[i].disposition)); |
365 | 272 |
366 pending_async_count_++; | 273 pending_async_count_++; |
367 FaviconService::Handle handle = favicon_service->GetFaviconForURL( | 274 FaviconService::Handle handle = favicon_service->GetFaviconForURL( |
368 services[i].service_url, | 275 services[i].service_url, |
369 history::FAVICON, | 276 history::FAVICON, |
370 &favicon_consumer_, | 277 &favicon_consumer_, |
371 base::Bind( | 278 base::Bind( |
372 &WebIntentPickerController::OnFaviconDataAvailable, | 279 &WebIntentPickerController::OnFaviconDataAvailable, |
373 weak_ptr_factory_.GetWeakPtr())); | 280 weak_ptr_factory_.GetWeakPtr())); |
374 favicon_consumer_.SetClientData(favicon_service, handle, i); | 281 favicon_consumer_.SetClientData(favicon_service, handle, i); |
375 } | 282 } |
376 | 283 |
377 AsyncOperationFinished(); | 284 AsyncOperationFinished(); |
378 } | 285 } |
379 | 286 |
| 287 void WebIntentPickerController::OnIntentsDefaultsQueryDone( |
| 288 WebIntentsRegistry::QueryID, |
| 289 const DefaultWebIntentService& default_service) { |
| 290 } |
| 291 |
380 void WebIntentPickerController::OnFaviconDataAvailable( | 292 void WebIntentPickerController::OnFaviconDataAvailable( |
381 FaviconService::Handle handle, history::FaviconData favicon_data) { | 293 FaviconService::Handle handle, history::FaviconData favicon_data) { |
382 size_t index = favicon_consumer_.GetClientDataForCurrentRequest(); | 294 size_t index = favicon_consumer_.GetClientDataForCurrentRequest(); |
383 if (favicon_data.is_valid()) { | 295 if (favicon_data.is_valid()) { |
384 SkBitmap icon_bitmap; | 296 SkBitmap icon_bitmap; |
385 | 297 |
386 if (gfx::PNGCodec::Decode(favicon_data.image_data->front(), | 298 if (gfx::PNGCodec::Decode(favicon_data.image_data->front(), |
387 favicon_data.image_data->size(), | 299 favicon_data.image_data->size(), |
388 &icon_bitmap)) { | 300 &icon_bitmap)) { |
389 gfx::Image icon_image(new SkBitmap(icon_bitmap)); | 301 gfx::Image icon_image(new SkBitmap(icon_bitmap)); |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
502 const gfx::Image& icon_image) { | 414 const gfx::Image& icon_image) { |
503 picker_model_->SetSuggestedExtensionIconWithId(extension_id, icon_image); | 415 picker_model_->SetSuggestedExtensionIconWithId(extension_id, icon_image); |
504 AsyncOperationFinished(); | 416 AsyncOperationFinished(); |
505 } | 417 } |
506 | 418 |
507 void WebIntentPickerController::OnExtensionIconUnavailable( | 419 void WebIntentPickerController::OnExtensionIconUnavailable( |
508 const string16& extension_id) { | 420 const string16& extension_id) { |
509 AsyncOperationFinished(); | 421 AsyncOperationFinished(); |
510 } | 422 } |
511 | 423 |
512 void WebIntentPickerController::OnExtensionInstallServiceAvailable( | |
513 const std::vector<webkit_glue::WebIntentServiceData>& services) { | |
514 DCHECK(services.size() > 0); | |
515 | |
516 // TODO(binji): We're going to need to disambiguate if there are multiple | |
517 // services. For now, just choose the first. | |
518 const webkit_glue::WebIntentServiceData& service_data = services[0]; | |
519 OnServiceChosen( | |
520 service_data.service_url, | |
521 ConvertDisposition(service_data.disposition)); | |
522 AsyncOperationFinished(); | |
523 } | |
524 | |
525 void WebIntentPickerController::AsyncOperationFinished() { | 424 void WebIntentPickerController::AsyncOperationFinished() { |
526 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 425 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
527 if (--pending_async_count_ == 0) { | 426 if (--pending_async_count_ == 0) { |
528 picker_->OnPendingAsyncCompleted(); | 427 picker_->OnPendingAsyncCompleted(); |
529 } | 428 } |
530 } | 429 } |
531 | 430 |
532 void WebIntentPickerController::ClosePicker() { | 431 void WebIntentPickerController::ClosePicker() { |
533 if (picker_) { | 432 if (picker_) { |
534 picker_->Close(); | 433 picker_->Close(); |
535 } | 434 } |
536 } | 435 } |
OLD | NEW |