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 "base/memory/scoped_ptr.h" | 11 #include "base/memory/scoped_ptr.h" |
12 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
13 #include "chrome/browser/extensions/extension_service.h" | 13 #include "chrome/browser/extensions/extension_service.h" |
14 #include "chrome/browser/extensions/platform_app_launcher.h" | 14 #include "chrome/browser/extensions/platform_app_launcher.h" |
15 #include "chrome/browser/extensions/webstore_installer.h" | 15 #include "chrome/browser/extensions/webstore_installer.h" |
16 #include "chrome/browser/favicon/favicon_service.h" | 16 #include "chrome/browser/favicon/favicon_service.h" |
17 #include "chrome/browser/intents/cws_intents_registry_factory.h" | 17 #include "chrome/browser/intents/cws_intents_registry_factory.h" |
18 #include "chrome/browser/intents/default_web_intent_service.h" | 18 #include "chrome/browser/intents/default_web_intent_service.h" |
19 #include "chrome/browser/intents/web_intents_registry_factory.h" | 19 #include "chrome/browser/intents/web_intents_registry_factory.h" |
20 #include "chrome/browser/profiles/profile.h" | 20 #include "chrome/browser/profiles/profile.h" |
21 #include "chrome/browser/tab_contents/tab_util.h" | 21 #include "chrome/browser/tab_contents/tab_util.h" |
22 #include "chrome/browser/ui/browser.h" | 22 #include "chrome/browser/ui/browser.h" |
23 #include "chrome/browser/ui/browser_finder.h" | 23 #include "chrome/browser/ui/browser_finder.h" |
24 #include "chrome/browser/ui/browser_list.h" | 24 #include "chrome/browser/ui/browser_list.h" |
25 #include "chrome/browser/ui/browser_navigator.h" | 25 #include "chrome/browser/ui/browser_navigator.h" |
26 #include "chrome/browser/ui/browser_tabstrip.h" | 26 #include "chrome/browser/ui/browser_tabstrip.h" |
27 #include "chrome/browser/ui/constrained_window_tab_helper.h" | |
27 #include "chrome/browser/ui/intents/web_intent_picker.h" | 28 #include "chrome/browser/ui/intents/web_intent_picker.h" |
28 #include "chrome/browser/ui/intents/web_intent_picker_model.h" | 29 #include "chrome/browser/ui/intents/web_intent_picker_model.h" |
29 #include "chrome/browser/ui/tab_contents/tab_contents.h" | 30 #include "chrome/browser/ui/tab_contents/tab_contents.h" |
30 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 31 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
31 #include "chrome/browser/webdata/web_data_service.h" | 32 #include "chrome/browser/webdata/web_data_service.h" |
32 #include "chrome/common/chrome_notification_types.h" | 33 #include "chrome/common/chrome_notification_types.h" |
33 #include "chrome/common/url_constants.h" | 34 #include "chrome/common/url_constants.h" |
34 #include "content/public/browser/browser_thread.h" | 35 #include "content/public/browser/browser_thread.h" |
35 #include "content/public/browser/navigation_controller.h" | 36 #include "content/public/browser/navigation_controller.h" |
36 #include "content/public/browser/notification_source.h" | 37 #include "content/public/browser/notification_source.h" |
(...skipping 16 matching lines...) Expand all Loading... | |
53 | 54 |
54 namespace { | 55 namespace { |
55 | 56 |
56 const char kShareActionURL[] = "http://webintents.org/share"; | 57 const char kShareActionURL[] = "http://webintents.org/share"; |
57 const char kEditActionURL[] = "http://webintents.org/edit"; | 58 const char kEditActionURL[] = "http://webintents.org/edit"; |
58 const char kViewActionURL[] = "http://webintents.org/view"; | 59 const char kViewActionURL[] = "http://webintents.org/view"; |
59 const char kPickActionURL[] = "http://webintents.org/pick"; | 60 const char kPickActionURL[] = "http://webintents.org/pick"; |
60 const char kSubscribeActionURL[] = "http://webintents.org/subscribe"; | 61 const char kSubscribeActionURL[] = "http://webintents.org/subscribe"; |
61 const char kSaveActionURL[] = "http://webintents.org/save"; | 62 const char kSaveActionURL[] = "http://webintents.org/save"; |
62 | 63 |
64 // Maximum amount of time to delay displaying dialog while waiting for data. | |
65 const int kMaxHiddenSetupTimeMs = 200; | |
66 | |
67 // Minimum amount of time to show waiting dialog, if it is shown. | |
68 const int kMinThrobberDisplayTimeMs = 2000; | |
69 | |
70 | |
63 // Gets the favicon service for the profile in |tab_contents|. | 71 // Gets the favicon service for the profile in |tab_contents|. |
64 FaviconService* GetFaviconService(TabContents* tab_contents) { | 72 FaviconService* GetFaviconService(TabContents* tab_contents) { |
65 return tab_contents->profile()->GetFaviconService(Profile::EXPLICIT_ACCESS); | 73 return tab_contents->profile()->GetFaviconService(Profile::EXPLICIT_ACCESS); |
66 } | 74 } |
67 | 75 |
68 // Gets the web intents registry for the profile in |tab_contents|. | 76 // Gets the web intents registry for the profile in |tab_contents|. |
69 WebIntentsRegistry* GetWebIntentsRegistry(TabContents* tab_contents) { | 77 WebIntentsRegistry* GetWebIntentsRegistry(TabContents* tab_contents) { |
70 return WebIntentsRegistryFactory::GetForProfile(tab_contents->profile()); | 78 return WebIntentsRegistryFactory::GetForProfile(tab_contents->profile()); |
71 } | 79 } |
72 | 80 |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
154 } | 162 } |
155 | 163 |
156 private: | 164 private: |
157 base::WeakPtr<WebIntentPickerController> controller_; | 165 base::WeakPtr<WebIntentPickerController> controller_; |
158 }; | 166 }; |
159 | 167 |
160 } // namespace | 168 } // namespace |
161 | 169 |
162 WebIntentPickerController::WebIntentPickerController( | 170 WebIntentPickerController::WebIntentPickerController( |
163 TabContents* tab_contents) | 171 TabContents* tab_contents) |
164 : tab_contents_(tab_contents), | 172 : dialog_state_(kPickerHidden), |
173 tab_contents_(tab_contents), | |
165 picker_(NULL), | 174 picker_(NULL), |
166 picker_model_(new WebIntentPickerModel()), | 175 picker_model_(new WebIntentPickerModel()), |
167 pending_async_count_(0), | 176 pending_async_count_(0), |
168 pending_registry_calls_count_(0), | 177 pending_registry_calls_count_(0), |
178 pending_cws_request_(false), | |
169 picker_shown_(false), | 179 picker_shown_(false), |
170 window_disposition_source_(NULL), | 180 window_disposition_source_(NULL), |
171 source_intents_dispatcher_(NULL), | 181 source_intents_dispatcher_(NULL), |
172 intents_dispatcher_(NULL), | 182 intents_dispatcher_(NULL), |
173 service_tab_(NULL), | 183 service_tab_(NULL), |
174 weak_ptr_factory_(this) { | 184 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), |
185 ALLOW_THIS_IN_INITIALIZER_LIST(timer_factory_(this)) { | |
175 content::NavigationController* controller = | 186 content::NavigationController* controller = |
176 &tab_contents->web_contents()->GetController(); | 187 &tab_contents->web_contents()->GetController(); |
177 registrar_.Add(this, content::NOTIFICATION_LOAD_START, | 188 registrar_.Add(this, content::NOTIFICATION_LOAD_START, |
178 content::Source<content::NavigationController>(controller)); | 189 content::Source<content::NavigationController>(controller)); |
179 registrar_.Add(this, chrome::NOTIFICATION_TAB_CLOSING, | 190 registrar_.Add(this, chrome::NOTIFICATION_TAB_CLOSING, |
180 content::Source<content::NavigationController>(controller)); | 191 content::Source<content::NavigationController>(controller)); |
181 } | 192 } |
182 | 193 |
183 WebIntentPickerController::~WebIntentPickerController() { | 194 WebIntentPickerController::~WebIntentPickerController() { |
184 } | 195 } |
185 | 196 |
186 // TODO(gbillock): combine this with ShowDialog. | 197 // TODO(gbillock): combine this with ShowDialog. |
187 void WebIntentPickerController::SetIntentsDispatcher( | 198 void WebIntentPickerController::SetIntentsDispatcher( |
188 content::WebIntentsDispatcher* intents_dispatcher) { | 199 content::WebIntentsDispatcher* intents_dispatcher) { |
189 intents_dispatcher_ = intents_dispatcher; | 200 intents_dispatcher_ = intents_dispatcher; |
190 intents_dispatcher_->RegisterReplyNotification( | 201 intents_dispatcher_->RegisterReplyNotification( |
191 base::Bind(&WebIntentPickerController::OnSendReturnMessage, | 202 base::Bind(&WebIntentPickerController::OnSendReturnMessage, |
192 weak_ptr_factory_.GetWeakPtr())); | 203 weak_ptr_factory_.GetWeakPtr())); |
193 } | 204 } |
194 | |
195 void WebIntentPickerController::ShowDialog(const string16& action, | 205 void WebIntentPickerController::ShowDialog(const string16& action, |
196 const string16& type) { | 206 const string16& type) { |
207 | |
208 // As soon as the dialog is requested, block all input events | |
209 // on the original tab. | |
210 tab_contents_->constrained_window_tab_helper()->BlockTabContent(true); | |
211 | |
197 // Only show a picker once. | 212 // Only show a picker once. |
198 // TODO(gbillock): There's a hole potentially admitting multiple | 213 // TODO(gbillock): There's a hole potentially admitting multiple |
199 // in-flight dispatches since we don't create the picker | 214 // in-flight dispatches since we don't create the picker |
200 // in this method, but only after calling the registry. | 215 // in this method, but only after calling the registry. |
201 if (picker_shown_) { | 216 if (picker_shown_) { |
202 if (intents_dispatcher_) { | 217 if (intents_dispatcher_) { |
203 intents_dispatcher_->SendReplyMessage( | 218 intents_dispatcher_->SendReplyMessage( |
204 webkit_glue::WEB_INTENT_REPLY_FAILURE, | 219 webkit_glue::WEB_INTENT_REPLY_FAILURE, |
205 ASCIIToUTF16("Simultaneous intent invocation.")); | 220 ASCIIToUTF16("Simultaneous intent invocation.")); |
206 } | 221 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
240 // required to find disposition set by service.) | 255 // required to find disposition set by service.) |
241 pending_async_count_++; | 256 pending_async_count_++; |
242 GetWebIntentsRegistry(tab_contents_)->GetIntentServices( | 257 GetWebIntentsRegistry(tab_contents_)->GetIntentServices( |
243 action, type, base::Bind( | 258 action, type, base::Bind( |
244 &WebIntentPickerController::WebIntentServicesForExplicitIntent, | 259 &WebIntentPickerController::WebIntentServicesForExplicitIntent, |
245 weak_ptr_factory_.GetWeakPtr())); | 260 weak_ptr_factory_.GetWeakPtr())); |
246 return; | 261 return; |
247 } | 262 } |
248 } | 263 } |
249 | 264 |
265 SetDialogState(kPickerSetup); | |
266 | |
250 pending_async_count_ += 2; | 267 pending_async_count_ += 2; |
251 pending_registry_calls_count_ += 1; | 268 pending_registry_calls_count_ += 1; |
Greg Billock
2012/08/08 23:47:11
There are two of these -- services and defaults. B
groby-ooo-7-16
2012/08/09 21:59:56
See discussion below - tempted to move to bitfield
| |
252 | 269 |
270 pending_cws_request_ = true; | |
271 | |
253 GetWebIntentsRegistry(tab_contents_)->GetIntentServices( | 272 GetWebIntentsRegistry(tab_contents_)->GetIntentServices( |
254 action, type, | 273 action, type, |
255 base::Bind(&WebIntentPickerController::OnWebIntentServicesAvailable, | 274 base::Bind(&WebIntentPickerController::OnWebIntentServicesAvailable, |
256 weak_ptr_factory_.GetWeakPtr())); | 275 weak_ptr_factory_.GetWeakPtr())); |
257 | 276 |
258 GURL invoking_url = tab_contents_->web_contents()->GetURL(); | 277 GURL invoking_url = tab_contents_->web_contents()->GetURL(); |
259 if (invoking_url.is_valid()) { | 278 if (invoking_url.is_valid()) { |
260 pending_async_count_++; | 279 pending_async_count_++; |
261 pending_registry_calls_count_++; | 280 pending_registry_calls_count_++; |
262 GetWebIntentsRegistry(tab_contents_)->GetDefaultIntentService( | 281 GetWebIntentsRegistry(tab_contents_)->GetDefaultIntentService( |
263 action, type, invoking_url, | 282 action, type, invoking_url, |
264 base::Bind(&WebIntentPickerController::OnWebIntentDefaultsAvailable, | 283 base::Bind(&WebIntentPickerController::OnWebIntentDefaultsAvailable, |
265 weak_ptr_factory_.GetWeakPtr())); | 284 weak_ptr_factory_.GetWeakPtr())); |
266 } | 285 } |
267 | 286 |
268 GetCWSIntentsRegistry(tab_contents_)->GetIntentServices( | 287 GetCWSIntentsRegistry(tab_contents_)->GetIntentServices( |
269 action, type, | 288 picker_model_->action(), picker_model_->mimetype(), |
270 base::Bind(&WebIntentPickerController::OnCWSIntentServicesAvailable, | 289 base::Bind(&WebIntentPickerController::OnCWSIntentServicesAvailable, |
271 weak_ptr_factory_.GetWeakPtr())); | 290 weak_ptr_factory_.GetWeakPtr())); |
272 } | 291 } |
273 | 292 |
274 void WebIntentPickerController::Observe( | 293 void WebIntentPickerController::Observe( |
275 int type, | 294 int type, |
276 const content::NotificationSource& source, | 295 const content::NotificationSource& source, |
277 const content::NotificationDetails& details) { | 296 const content::NotificationDetails& details) { |
278 DCHECK(type == content::NOTIFICATION_LOAD_START || | 297 DCHECK(type == content::NOTIFICATION_LOAD_START || |
279 type == chrome::NOTIFICATION_TAB_CLOSING); | 298 type == chrome::NOTIFICATION_TAB_CLOSING); |
280 ClosePicker(); | 299 ClosePicker(); |
281 } | 300 } |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
508 services[i].service_url, | 527 services[i].service_url, |
509 history::FAVICON, | 528 history::FAVICON, |
510 &favicon_consumer_, | 529 &favicon_consumer_, |
511 base::Bind( | 530 base::Bind( |
512 &WebIntentPickerController::OnFaviconDataAvailable, | 531 &WebIntentPickerController::OnFaviconDataAvailable, |
513 weak_ptr_factory_.GetWeakPtr())); | 532 weak_ptr_factory_.GetWeakPtr())); |
514 favicon_consumer_.SetClientData( | 533 favicon_consumer_.SetClientData( |
515 favicon_service, handle, | 534 favicon_service, handle, |
516 picker_model_->GetInstalledServiceCount() - 1); | 535 picker_model_->GetInstalledServiceCount() - 1); |
517 | 536 |
518 if (services[i].disposition == | 537 InvokeService(picker_model_->GetInstalledServiceAt(i)); |
519 webkit_glue::WebIntentServiceData::DISPOSITION_INLINE) | |
520 CreatePicker(); | |
521 OnServiceChosen(services[i].service_url, | |
522 ConvertDisposition(services[i].disposition)); | |
523 AsyncOperationFinished(); | 538 AsyncOperationFinished(); |
524 return; | 539 return; |
525 } | 540 } |
526 | 541 |
527 // No acceptable extension. The intent cannot be dispatched. | 542 // No acceptable extension. The intent cannot be dispatched. |
528 intents_dispatcher_->SendReplyMessage( | 543 intents_dispatcher_->SendReplyMessage( |
529 webkit_glue::WEB_INTENT_REPLY_FAILURE, ASCIIToUTF16( | 544 webkit_glue::WEB_INTENT_REPLY_FAILURE, ASCIIToUTF16( |
530 "Explicit extension URL is not available.")); | 545 "Explicit extension URL is not available.")); |
531 | 546 |
532 AsyncOperationFinished(); | 547 AsyncOperationFinished(); |
(...skipping 15 matching lines...) Expand all Loading... | |
548 if (pending_registry_calls_count_ != 0) return; | 563 if (pending_registry_calls_count_ != 0) return; |
549 | 564 |
550 if (picker_model_->default_service_url().is_valid()) { | 565 if (picker_model_->default_service_url().is_valid()) { |
551 // If there's a default service, dispatch to it immediately | 566 // If there's a default service, dispatch to it immediately |
552 // without showing the picker. | 567 // without showing the picker. |
553 const WebIntentPickerModel::InstalledService* default_service = | 568 const WebIntentPickerModel::InstalledService* default_service = |
554 picker_model_->GetInstalledServiceWithURL( | 569 picker_model_->GetInstalledServiceWithURL( |
555 GURL(picker_model_->default_service_url())); | 570 GURL(picker_model_->default_service_url())); |
556 | 571 |
557 if (default_service != NULL) { | 572 if (default_service != NULL) { |
558 if (default_service->disposition == | 573 InvokeService(*default_service); |
559 WebIntentPickerModel::DISPOSITION_INLINE) | |
560 CreatePicker(); | |
561 | |
562 OnServiceChosen(default_service->url, default_service->disposition); | |
563 return; | 574 return; |
564 } | 575 } |
565 } | 576 } |
566 | 577 |
567 CreatePicker(); | 578 OnPickerEvent(kPickerEventRegistryData); |
568 picker_->SetActionString(GetIntentActionString( | 579 OnIntentDataArrived(); |
569 UTF16ToUTF8(picker_model_->action()))); | |
570 } | 580 } |
571 | 581 |
572 void WebIntentPickerController::OnFaviconDataAvailable( | 582 void WebIntentPickerController::OnFaviconDataAvailable( |
573 FaviconService::Handle handle, history::FaviconData favicon_data) { | 583 FaviconService::Handle handle, history::FaviconData favicon_data) { |
574 size_t index = favicon_consumer_.GetClientDataForCurrentRequest(); | 584 size_t index = favicon_consumer_.GetClientDataForCurrentRequest(); |
575 if (favicon_data.is_valid()) { | 585 if (favicon_data.is_valid()) { |
576 SkBitmap icon_bitmap; | 586 SkBitmap icon_bitmap; |
577 | 587 |
578 if (gfx::PNGCodec::Decode(favicon_data.image_data->front(), | 588 if (gfx::PNGCodec::Decode(favicon_data.image_data->front(), |
579 favicon_data.image_data->size(), | 589 favicon_data.image_data->size(), |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
613 &WebIntentPickerController::OnExtensionIconURLFetchComplete, | 623 &WebIntentPickerController::OnExtensionIconURLFetchComplete, |
614 weak_ptr_factory_.GetWeakPtr(), info.id))); | 624 weak_ptr_factory_.GetWeakPtr(), info.id))); |
615 | 625 |
616 icon_url_fetcher->SetLoadFlags( | 626 icon_url_fetcher->SetLoadFlags( |
617 net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES); | 627 net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES); |
618 icon_url_fetcher->SetRequestContext( | 628 icon_url_fetcher->SetRequestContext( |
619 tab_contents_->profile()->GetRequestContext()); | 629 tab_contents_->profile()->GetRequestContext()); |
620 icon_url_fetcher->Start(); | 630 icon_url_fetcher->Start(); |
621 } | 631 } |
622 | 632 |
623 AsyncOperationFinished(); | 633 AsyncOperationFinished(); |
Greg Billock
2012/08/08 23:47:11
It'd be nice to use the state machine to kill this
groby-ooo-7-16
2012/08/09 21:59:56
I'm trying to have the states correspond to actual
| |
634 pending_cws_request_ = false; | |
635 OnIntentDataArrived(); | |
624 } | 636 } |
625 | 637 |
626 void WebIntentPickerController::OnExtensionIconURLFetchComplete( | 638 void WebIntentPickerController::OnExtensionIconURLFetchComplete( |
627 const string16& extension_id, const net::URLFetcher* source) { | 639 const string16& extension_id, const net::URLFetcher* source) { |
628 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 640 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
629 if (source->GetResponseCode() != 200) { | 641 if (source->GetResponseCode() != 200) { |
630 AsyncOperationFinished(); | 642 AsyncOperationFinished(); |
631 return; | 643 return; |
632 } | 644 } |
633 | 645 |
(...skipping 27 matching lines...) Expand all Loading... | |
661 | 673 |
662 // Decode PNG and resize on worker thread. | 674 // Decode PNG and resize on worker thread. |
663 content::BrowserThread::PostBlockingPoolTask( | 675 content::BrowserThread::PostBlockingPoolTask( |
664 FROM_HERE, | 676 FROM_HERE, |
665 base::Bind(&DecodeExtensionIconAndResize, | 677 base::Bind(&DecodeExtensionIconAndResize, |
666 base::Passed(&response), | 678 base::Passed(&response), |
667 available_callback, | 679 available_callback, |
668 unavailable_callback)); | 680 unavailable_callback)); |
669 } | 681 } |
670 | 682 |
683 void WebIntentPickerController::OnIntentDataArrived() { | |
684 DCHECK(picker_model_.get()); | |
685 | |
686 if (!pending_cws_request_ && | |
687 pending_registry_calls_count_ == 0) | |
Greg Billock
2012/08/08 23:47:11
Merge this into the state machine logic.
groby-ooo-7-16
2012/08/09 21:59:56
See above. I'm treating this as a mini state machi
| |
688 OnPickerEvent(kPickerEventDataComplete); | |
689 } | |
690 | |
671 // static | 691 // static |
672 void WebIntentPickerController::DecodeExtensionIconAndResize( | 692 void WebIntentPickerController::DecodeExtensionIconAndResize( |
673 scoped_ptr<std::string> icon_response, | 693 scoped_ptr<std::string> icon_response, |
674 const ExtensionIconAvailableCallback& callback, | 694 const ExtensionIconAvailableCallback& callback, |
675 const base::Closure& unavailable_callback) { | 695 const base::Closure& unavailable_callback) { |
676 SkBitmap icon_bitmap; | 696 SkBitmap icon_bitmap; |
677 if (gfx::PNGCodec::Decode( | 697 if (gfx::PNGCodec::Decode( |
678 reinterpret_cast<const unsigned char*>(icon_response->data()), | 698 reinterpret_cast<const unsigned char*>(icon_response->data()), |
679 icon_response->length(), | 699 icon_response->length(), |
680 &icon_bitmap)) { | 700 &icon_bitmap)) { |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
749 const webkit_glue::WebIntentServiceData& service_data = services[0]; | 769 const webkit_glue::WebIntentServiceData& service_data = services[0]; |
750 picker_model_->AddInstalledService( | 770 picker_model_->AddInstalledService( |
751 service_data.title, service_data.service_url, | 771 service_data.title, service_data.service_url, |
752 ConvertDisposition(service_data.disposition)); | 772 ConvertDisposition(service_data.disposition)); |
753 OnServiceChosen( | 773 OnServiceChosen( |
754 service_data.service_url, | 774 service_data.service_url, |
755 ConvertDisposition(service_data.disposition)); | 775 ConvertDisposition(service_data.disposition)); |
756 AsyncOperationFinished(); | 776 AsyncOperationFinished(); |
757 } | 777 } |
758 | 778 |
779 void WebIntentPickerController::OnPickerEvent(WebIntentPickerEvent event) { | |
780 switch (event) { | |
781 case kPickerEventHiddenSetupTimeout: | |
782 DCHECK(dialog_state_ == kPickerSetup); | |
783 SetDialogState(kPickerWaiting); | |
784 break; | |
785 | |
786 case kPickerEventMaxWaitTimeExceeded: | |
787 DCHECK(dialog_state_ == kPickerWaiting); | |
788 | |
789 // If registry data is complete, go to main dialog. Otherwise, wait. | |
790 if (pending_registry_calls_count_ == 0) | |
791 SetDialogState(kPickerMain); | |
792 else | |
793 SetDialogState(kPickerWaitLong); | |
794 break; | |
795 | |
796 case kPickerEventRegistryData: | |
797 DCHECK(dialog_state_ == kPickerSetup || | |
798 dialog_state_ == kPickerWaiting || | |
799 dialog_state_ == kPickerWaitLong); | |
800 | |
801 // If minimum wait dialog time is exceeded, display main dialog. | |
802 // Either way, we don't do a thing. | |
803 break; | |
804 | |
805 case kPickerEventDataComplete: | |
806 DCHECK(dialog_state_ == kPickerSetup || | |
807 dialog_state_ == kPickerWaiting); | |
808 | |
809 // In setup state, transition to main dialog. In waiting state, let | |
810 // timer expire. | |
811 if (dialog_state_ == kPickerSetup) | |
812 SetDialogState(kPickerMain); | |
813 break; | |
814 | |
815 default: | |
816 NOTREACHED(); | |
817 break; | |
818 } | |
819 } | |
820 | |
759 void WebIntentPickerController::AsyncOperationFinished() { | 821 void WebIntentPickerController::AsyncOperationFinished() { |
760 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 822 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
761 if (--pending_async_count_ == 0) { | 823 if (--pending_async_count_ == 0) { |
762 if (picker_) | 824 if (picker_) |
763 picker_->OnPendingAsyncCompleted(); | 825 picker_->OnPendingAsyncCompleted(); |
764 } | 826 } |
765 } | 827 } |
766 | 828 |
829 void WebIntentPickerController::InvokeService( | |
830 const WebIntentPickerModel::InstalledService& service) { | |
831 if (service.disposition == WebIntentPickerModel::DISPOSITION_INLINE) { | |
832 SetDialogState(kPickerMain); | |
833 } | |
834 OnServiceChosen(service.url, service.disposition); | |
835 } | |
836 | |
837 void WebIntentPickerController::SetDialogState(WebIntentPickerState state) { | |
838 // Ignore events that don't change state. | |
839 if (state == dialog_state_) | |
840 return; | |
841 | |
842 // Any pending timers are abandoned on state changes. | |
843 timer_factory_.InvalidateWeakPtrs(); | |
844 | |
845 switch (state) { | |
846 case kPickerSetup: | |
847 DCHECK(dialog_state_ == kPickerHidden); | |
848 | |
849 // Post timer CWS pending | |
850 MessageLoop::current()->PostDelayedTask(FROM_HERE, | |
851 base::Bind(&WebIntentPickerController::OnPickerEvent, | |
852 timer_factory_.GetWeakPtr(), | |
853 kPickerEventHiddenSetupTimeout), | |
854 base::TimeDelta::FromMilliseconds(kMaxHiddenSetupTimeMs)); | |
855 break; | |
856 | |
857 case kPickerWaiting: | |
858 DCHECK(dialog_state_ == kPickerSetup); | |
859 // Waiting dialog can be dismissed after minimum wait time. | |
860 MessageLoop::current()->PostDelayedTask(FROM_HERE, | |
861 base::Bind(&WebIntentPickerController::OnPickerEvent, | |
862 timer_factory_.GetWeakPtr(), | |
863 kPickerEventMaxWaitTimeExceeded), | |
864 base::TimeDelta::FromMilliseconds(kMinThrobberDisplayTimeMs)); | |
865 break; | |
866 | |
867 case kPickerWaitLong: | |
868 DCHECK(dialog_state_ == kPickerWaiting); | |
869 break; | |
870 | |
871 case kPickerMain: | |
872 // No DCHECK - main state can be reached from any state. | |
873 // Ready to display data. | |
874 picker_model_->SetWaitingForSuggestions(false); | |
875 break; | |
876 | |
877 case kPickerHidden: | |
878 break; | |
879 | |
880 default: | |
881 NOTREACHED(); | |
882 break; | |
883 | |
884 } | |
885 | |
886 dialog_state_ = state; | |
887 | |
888 // Create picker dialog when changing away from hidden state. | |
889 if (dialog_state_ != kPickerHidden && dialog_state_ != kPickerSetup) | |
890 CreatePicker(); | |
891 } | |
892 | |
893 | |
767 void WebIntentPickerController::CreatePicker() { | 894 void WebIntentPickerController::CreatePicker() { |
768 // If picker is non-NULL, it was set by a test. | 895 // If picker is non-NULL, it was set by a test. |
769 if (picker_ == NULL) | 896 if (picker_ == NULL) |
770 picker_ = WebIntentPicker::Create(tab_contents_, this, picker_model_.get()); | 897 picker_ = WebIntentPicker::Create(tab_contents_, this, picker_model_.get()); |
898 picker_->SetActionString(GetIntentActionString( | |
899 UTF16ToUTF8(picker_model_->action()))); | |
771 picker_shown_ = true; | 900 picker_shown_ = true; |
772 } | 901 } |
773 | 902 |
774 void WebIntentPickerController::ClosePicker() { | 903 void WebIntentPickerController::ClosePicker() { |
904 SetDialogState(kPickerHidden); | |
775 if (picker_) | 905 if (picker_) |
776 picker_->Close(); | 906 picker_->Close(); |
777 } | 907 } |
OLD | NEW |