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