Chromium Code Reviews| 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/ui/browser.h" |
| 12 #include "chrome/browser/favicon/favicon_service.h" | 12 #include "chrome/browser/favicon/favicon_service.h" |
| 13 #include "chrome/browser/intents/web_intents_registry.h" | 13 #include "chrome/browser/intents/web_intents_registry.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/profiles/profile.h" | 15 #include "chrome/browser/profiles/profile.h" |
| 16 #include "chrome/browser/tabs/tab_strip_model.h" | 16 #include "chrome/browser/tabs/tab_strip_model.h" |
| 17 #include "chrome/browser/ui/browser_navigator.h" | 17 #include "chrome/browser/ui/browser_navigator.h" |
| 18 #include "chrome/browser/ui/intents/web_intent_picker.h" | 18 #include "chrome/browser/ui/intents/web_intent_picker.h" |
| 19 #include "chrome/browser/ui/intents/web_intent_picker_factory.h" | 19 #include "chrome/browser/ui/intents/web_intent_picker_model.h" |
| 20 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" | 20 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| 21 #include "chrome/browser/webdata/web_data_service.h" | 21 #include "chrome/browser/webdata/web_data_service.h" |
| 22 #include "chrome/common/chrome_notification_types.h" | 22 #include "chrome/common/chrome_notification_types.h" |
| 23 #include "content/browser/intents/intent_injector.h" | 23 #include "content/browser/intents/intent_injector.h" |
| 24 #include "content/public/browser/notification_source.h" | 24 #include "content/public/browser/notification_source.h" |
| 25 #include "content/public/browser/web_contents.h" | 25 #include "content/public/browser/web_contents.h" |
| 26 #include "content/public/browser/web_intents_dispatcher.h" | 26 #include "content/public/browser/web_intents_dispatcher.h" |
| 27 #include "ui/gfx/codec/png_codec.h" | 27 #include "ui/gfx/codec/png_codec.h" |
| 28 #include "ui/gfx/image/image.h" | |
| 28 #include "webkit/glue/web_intent_service_data.h" | 29 #include "webkit/glue/web_intent_service_data.h" |
| 29 | 30 |
| 30 using content::NavigationController; | |
| 31 using content::WebContents; | |
| 32 | |
| 33 namespace { | 31 namespace { |
| 34 | 32 |
| 35 // Gets the favicon service for the profile in |tab_contents|. | 33 // Gets the favicon service for the profile in |tab_contents|. |
| 36 FaviconService* GetFaviconService(TabContentsWrapper* wrapper) { | 34 FaviconService* GetFaviconService(TabContentsWrapper* wrapper) { |
| 37 return wrapper->profile()->GetFaviconService(Profile::EXPLICIT_ACCESS); | 35 return wrapper->profile()->GetFaviconService(Profile::EXPLICIT_ACCESS); |
| 38 } | 36 } |
| 39 | 37 |
| 40 // Gets the web intents registry for the profile in |tab_contents|. | 38 // Gets the web intents registry for the profile in |tab_contents|. |
| 41 WebIntentsRegistry* GetWebIntentsRegistry(TabContentsWrapper* wrapper) { | 39 WebIntentsRegistry* GetWebIntentsRegistry(TabContentsWrapper* wrapper) { |
| 42 return WebIntentsRegistryFactory::GetForProfile(wrapper->profile()); | 40 return WebIntentsRegistryFactory::GetForProfile(wrapper->profile()); |
| 43 } | 41 } |
| 44 | 42 |
| 43 WebIntentPickerModel::Disposition ConvertDisposition( | |
| 44 webkit_glue::WebIntentServiceData::Disposition disposition) { | |
| 45 switch (disposition) { | |
| 46 case webkit_glue::WebIntentServiceData::DISPOSITION_INLINE: | |
| 47 return WebIntentPickerModel::DISPOSITION_INLINE; | |
| 48 case webkit_glue::WebIntentServiceData::DISPOSITION_WINDOW: | |
| 49 return WebIntentPickerModel::DISPOSITION_WINDOW; | |
| 50 default: | |
| 51 NOTREACHED(); | |
| 52 return WebIntentPickerModel::DISPOSITION_WINDOW; | |
| 53 } | |
| 54 } | |
| 55 | |
| 45 } // namespace | 56 } // namespace |
| 46 | 57 |
| 47 // A class that asynchronously fetches web intent data from the web intents | 58 // A class that asynchronously fetches web intent data from the web intents |
| 48 // registry. | 59 // registry. |
| 49 class WebIntentPickerController::WebIntentDataFetcher | 60 class WebIntentPickerController::WebIntentDataFetcher |
| 50 : public WebIntentsRegistry::Consumer { | 61 : public WebIntentsRegistry::Consumer { |
| 51 public: | 62 public: |
| 52 WebIntentDataFetcher(WebIntentPickerController* controller, | 63 WebIntentDataFetcher(WebIntentPickerController* controller, |
| 53 WebIntentsRegistry* web_intents_registry); | 64 WebIntentsRegistry* web_intents_registry); |
| 54 ~WebIntentDataFetcher(); | 65 ~WebIntentDataFetcher(); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 101 // A weak pointer to the favicon service. | 112 // A weak pointer to the favicon service. |
| 102 FaviconService* favicon_service_; | 113 FaviconService* favicon_service_; |
| 103 | 114 |
| 104 // The Consumer to handle asynchronous favicon requests. | 115 // The Consumer to handle asynchronous favicon requests. |
| 105 CancelableRequestConsumerTSimple<size_t> load_consumer_; | 116 CancelableRequestConsumerTSimple<size_t> load_consumer_; |
| 106 | 117 |
| 107 DISALLOW_COPY_AND_ASSIGN(FaviconFetcher); | 118 DISALLOW_COPY_AND_ASSIGN(FaviconFetcher); |
| 108 }; | 119 }; |
| 109 | 120 |
| 110 WebIntentPickerController::WebIntentPickerController( | 121 WebIntentPickerController::WebIntentPickerController( |
| 111 TabContentsWrapper* wrapper, | 122 TabContentsWrapper* wrapper) |
| 112 WebIntentPickerFactory* factory) | |
| 113 : wrapper_(wrapper), | 123 : wrapper_(wrapper), |
|
groby-ooo-7-16
2012/01/25 22:03:13
nit: Shouldn't this only be indented 4 spaces?
binji
2012/01/26 00:27:41
Looks like you're right. The line-wrap rules are t
| |
| 114 picker_factory_(factory), | |
| 115 web_intent_data_fetcher_( | 124 web_intent_data_fetcher_( |
| 116 new WebIntentDataFetcher(this, | 125 new WebIntentDataFetcher(this, |
| 117 GetWebIntentsRegistry(wrapper))), | 126 GetWebIntentsRegistry(wrapper))), |
| 118 favicon_fetcher_( | 127 favicon_fetcher_( |
| 119 new FaviconFetcher(this, GetFaviconService(wrapper))), | 128 new FaviconFetcher(this, GetFaviconService(wrapper))), |
| 120 picker_(NULL), | 129 picker_(NULL), |
| 130 picker_model_(new WebIntentPickerModel()), | |
| 121 pending_async_count_(0), | 131 pending_async_count_(0), |
| 132 picker_shown_(false), | |
| 122 service_tab_(NULL) { | 133 service_tab_(NULL) { |
| 123 NavigationController* controller = &wrapper->web_contents()->GetController(); | 134 content::NavigationController* controller = |
| 135 &wrapper->web_contents()->GetController(); | |
| 124 registrar_.Add(this, content::NOTIFICATION_LOAD_START, | 136 registrar_.Add(this, content::NOTIFICATION_LOAD_START, |
| 125 content::Source<NavigationController>(controller)); | 137 content::Source<content::NavigationController>(controller)); |
| 126 registrar_.Add(this, content::NOTIFICATION_TAB_CLOSING, | 138 registrar_.Add(this, content::NOTIFICATION_TAB_CLOSING, |
| 127 content::Source<NavigationController>(controller)); | 139 content::Source<content::NavigationController>(controller)); |
| 128 } | 140 } |
| 129 | 141 |
| 130 WebIntentPickerController::~WebIntentPickerController() { | 142 WebIntentPickerController::~WebIntentPickerController() { |
| 131 } | 143 } |
| 132 | 144 |
| 133 void WebIntentPickerController::SetIntentsDispatcher( | 145 void WebIntentPickerController::SetIntentsDispatcher( |
| 134 content::WebIntentsDispatcher* intents_dispatcher) { | 146 content::WebIntentsDispatcher* intents_dispatcher) { |
| 135 intents_dispatcher_.reset(intents_dispatcher); | 147 intents_dispatcher_.reset(intents_dispatcher); |
| 136 intents_dispatcher_->RegisterReplyNotification( | 148 intents_dispatcher_->RegisterReplyNotification( |
| 137 base::Bind(&WebIntentPickerController::OnSendReturnMessage, | 149 base::Bind(&WebIntentPickerController::OnSendReturnMessage, |
| 138 base::Unretained(this))); | 150 base::Unretained(this))); |
| 139 } | 151 } |
| 140 | 152 |
| 141 void WebIntentPickerController::ShowDialog(Browser* browser, | 153 void WebIntentPickerController::ShowDialog(Browser* browser, |
| 142 const string16& action, | 154 const string16& action, |
| 143 const string16& type) { | 155 const string16& type) { |
| 144 if (picker_ != NULL) | 156 // Only show a picker once. |
| 157 if (picker_shown_) | |
| 145 return; | 158 return; |
| 146 | 159 |
| 147 picker_ = picker_factory_->Create(browser, wrapper_, this); | 160 picker_model_->Clear(); |
| 148 | 161 |
| 149 // TODO(binji) Remove this check when there are implementations of the picker | 162 // If picker is non-NULL, it was set by a test. |
| 150 // for windows and mac. | 163 if (picker_ == NULL) { |
| 151 if (picker_ == NULL) | 164 picker_ = WebIntentPicker::Create(browser, wrapper_, this, |
| 152 return; | 165 picker_model_.get()); |
| 166 } | |
| 153 | 167 |
| 168 picker_shown_ = true; | |
| 154 web_intent_data_fetcher_->Fetch(action, type); | 169 web_intent_data_fetcher_->Fetch(action, type); |
| 155 } | 170 } |
| 156 | 171 |
| 157 void WebIntentPickerController::Observe( | 172 void WebIntentPickerController::Observe( |
| 158 int type, | 173 int type, |
| 159 const content::NotificationSource& source, | 174 const content::NotificationSource& source, |
| 160 const content::NotificationDetails& details) { | 175 const content::NotificationDetails& details) { |
| 161 DCHECK(type == content::NOTIFICATION_LOAD_START || | 176 DCHECK(type == content::NOTIFICATION_LOAD_START || |
| 162 type == content::NOTIFICATION_TAB_CLOSING); | 177 type == content::NOTIFICATION_TAB_CLOSING); |
| 163 ClosePicker(); | 178 ClosePicker(); |
| 164 } | 179 } |
| 165 | 180 |
| 166 void WebIntentPickerController::OnServiceChosen(size_t index) { | 181 void WebIntentPickerController::OnServiceChosen(size_t index, |
| 167 DCHECK(index < urls_.size()); | 182 Disposition disposition) { |
| 183 switch (disposition) { | |
| 184 case WebIntentPickerModel::DISPOSITION_INLINE: | |
| 185 // Set the model to inline disposition. It will notify the picker which | |
| 186 // will respond (via OnInlineDispositionWebContentsCreated) with the | |
| 187 // WebContents to dispatch the intent to. | |
| 188 picker_model_->SetInlineDisposition(index); | |
| 189 break; | |
| 168 | 190 |
| 169 bool inline_disposition = service_data_[index].disposition == | 191 case WebIntentPickerModel::DISPOSITION_WINDOW: { |
| 170 webkit_glue::WebIntentServiceData::DISPOSITION_INLINE; | 192 // TODO(gbillock): This really only handles the 'window' disposition in a |
| 171 WebContents* new_web_contents = NULL; | 193 // quite prototype way. We need to flesh out what happens to the picker |
| 172 if (inline_disposition) | 194 // during the lifetime of the service url context, and that may mean we |
| 173 new_web_contents = picker_->SetInlineDisposition(urls_[index]); | 195 // need to pass more information into the injector to find the picker |
| 196 // again and close it. | |
| 197 const WebIntentPickerModel::Item& item = picker_model_->GetItemAt(index); | |
| 174 | 198 |
| 175 if (new_web_contents == NULL) { | 199 browser::NavigateParams params(NULL, item.url, |
| 176 // TODO(gbillock): This really only handles the 'window' disposition in a | 200 content::PAGE_TRANSITION_AUTO_BOOKMARK); |
| 177 // quite prototype way. We need to flesh out what happens to the picker | 201 params.disposition = NEW_FOREGROUND_TAB; |
| 178 // during the lifetime of the service url context, and that may mean we | 202 params.profile = wrapper_->profile(); |
| 179 // need to pass more information into the injector to find the picker again | 203 browser::Navigate(¶ms); |
| 180 // and close it. Also: the above conditional construction is just because | 204 content::WebContents* web_contents = |
| 181 // there isn't Mac/Win support yet. When that's there, it'll be an else. | 205 params.target_contents->web_contents(); |
| 182 browser::NavigateParams params(NULL, urls_[index], | 206 service_tab_ = web_contents; |
| 183 content::PAGE_TRANSITION_AUTO_BOOKMARK); | |
| 184 params.disposition = NEW_FOREGROUND_TAB; | |
| 185 params.profile = wrapper_->profile(); | |
| 186 browser::Navigate(¶ms); | |
| 187 new_web_contents = params.target_contents->web_contents(); | |
| 188 service_tab_ = new_web_contents; | |
| 189 | 207 |
| 190 ClosePicker(); | 208 ClosePicker(); |
| 209 | |
| 210 intents_dispatcher_->DispatchIntent(web_contents); | |
| 211 break; | |
| 212 } | |
| 213 | |
| 214 default: | |
| 215 NOTREACHED(); | |
| 216 break; | |
| 191 } | 217 } |
| 218 } | |
| 192 | 219 |
| 193 intents_dispatcher_->DispatchIntent(new_web_contents); | 220 void WebIntentPickerController::OnInlineDispositionWebContentsCreated( |
| 221 content::WebContents* web_contents) { | |
| 222 if (web_contents) { | |
| 223 intents_dispatcher_->DispatchIntent(web_contents); | |
| 224 } else { | |
| 225 // TODO(binji): tab_contents should never be NULL; it is in this case | |
|
groby-ooo-7-16
2012/01/25 22:03:13
nit: web_contens
binji
2012/01/26 00:27:41
Done.
| |
| 226 // because views doesn't have an implementation for inline disposition yet. | |
| 227 // Remove this else when it does. In the meantime, just reforward as if it | |
| 228 // were the window disposition. | |
| 229 OnServiceChosen(picker_model_->inline_disposition_index(), | |
| 230 WebIntentPickerModel::DISPOSITION_WINDOW); | |
| 231 } | |
| 194 } | 232 } |
| 195 | 233 |
| 196 void WebIntentPickerController::OnCancelled() { | 234 void WebIntentPickerController::OnCancelled() { |
| 197 if (!intents_dispatcher_.get()) | 235 if (!intents_dispatcher_.get()) |
| 198 return; | 236 return; |
| 199 | 237 |
| 200 if (service_tab_) { | 238 if (service_tab_) { |
| 201 intents_dispatcher_->SendReplyMessage( | 239 intents_dispatcher_->SendReplyMessage( |
| 202 webkit_glue::WEB_INTENT_SERVICE_TAB_CLOSED, string16()); | 240 webkit_glue::WEB_INTENT_SERVICE_TAB_CLOSED, string16()); |
| 203 } else { | 241 } else { |
| 204 intents_dispatcher_->SendReplyMessage( | 242 intents_dispatcher_->SendReplyMessage( |
| 205 webkit_glue::WEB_INTENT_PICKER_CANCELLED, string16()); | 243 webkit_glue::WEB_INTENT_PICKER_CANCELLED, string16()); |
| 206 } | 244 } |
| 207 | 245 |
| 208 ClosePicker(); | 246 ClosePicker(); |
| 209 } | 247 } |
| 210 | 248 |
| 211 void WebIntentPickerController::OnClosing() { | 249 void WebIntentPickerController::OnClosing() { |
| 250 picker_shown_ = false; | |
| 251 picker_ = NULL; | |
| 212 } | 252 } |
| 213 | 253 |
| 214 void WebIntentPickerController::OnSendReturnMessage() { | 254 void WebIntentPickerController::OnSendReturnMessage() { |
| 215 ClosePicker(); | 255 ClosePicker(); |
| 216 | 256 |
| 217 if (service_tab_) { | 257 if (service_tab_) { |
| 218 int index = TabStripModel::kNoTab; | 258 int index = TabStripModel::kNoTab; |
| 219 Browser* browser = Browser::GetBrowserForController( | 259 Browser* browser = Browser::GetBrowserForController( |
| 220 &service_tab_->GetController(), &index); | 260 &service_tab_->GetController(), &index); |
| 221 if (browser) { | 261 if (browser) { |
| 222 browser->tabstrip_model()->CloseTabContentsAt( | 262 browser->tabstrip_model()->CloseTabContentsAt( |
| 223 index, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB); | 263 index, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB); |
| 224 } | 264 } |
| 225 service_tab_ = NULL; | 265 service_tab_ = NULL; |
| 226 } | 266 } |
| 227 } | 267 } |
| 228 | 268 |
| 229 void WebIntentPickerController::OnWebIntentDataAvailable( | 269 void WebIntentPickerController::OnWebIntentDataAvailable( |
| 230 const std::vector<webkit_glue::WebIntentServiceData>& services) { | 270 const std::vector<webkit_glue::WebIntentServiceData>& services) { |
| 231 urls_.clear(); | 271 std::vector<GURL> urls; |
| 232 for (size_t i = 0; i < services.size(); ++i) { | 272 for (size_t i = 0; i < services.size(); ++i) { |
| 233 urls_.push_back(services[i].service_url); | 273 picker_model_->AddItem(services[i].title, services[i].service_url, |
| 274 ConvertDisposition(services[i].disposition)); | |
| 275 urls.push_back(services[i].service_url); | |
| 234 } | 276 } |
| 235 service_data_ = services; | |
| 236 | 277 |
| 237 // Tell the picker to initialize N urls to the default favicon | 278 // Tell the picker to initialize N urls to the default favicon |
| 238 picker_->SetServiceURLs(urls_); | 279 favicon_fetcher_->Fetch(urls); |
| 239 favicon_fetcher_->Fetch(urls_); | |
| 240 pending_async_count_--; | 280 pending_async_count_--; |
| 241 } | 281 } |
| 242 | 282 |
| 243 void WebIntentPickerController::OnFaviconDataAvailable( | 283 void WebIntentPickerController::OnFaviconDataAvailable(size_t index, |
| 244 size_t index, | 284 const gfx::Image& icon) { |
| 245 const SkBitmap& icon_bitmap) { | 285 picker_model_->UpdateFaviconAt(index, icon); |
| 246 picker_->SetServiceIcon(index, icon_bitmap); | |
| 247 pending_async_count_--; | 286 pending_async_count_--; |
| 248 } | 287 } |
| 249 | 288 |
| 250 void WebIntentPickerController::OnFaviconDataUnavailable(size_t index) { | 289 void WebIntentPickerController::OnFaviconDataUnavailable(size_t index) { |
| 251 picker_->SetDefaultServiceIcon(index); | |
| 252 pending_async_count_--; | 290 pending_async_count_--; |
| 253 } | 291 } |
| 254 | 292 |
| 255 void WebIntentPickerController::ClosePicker() { | 293 void WebIntentPickerController::ClosePicker() { |
| 256 if (picker_) { | 294 if (picker_) { |
| 257 picker_factory_->ClosePicker(picker_); | 295 picker_->Close(); |
| 258 picker_ = NULL; | |
| 259 } | 296 } |
| 260 } | 297 } |
| 261 | 298 |
| 262 WebIntentPickerController::WebIntentDataFetcher::WebIntentDataFetcher( | 299 WebIntentPickerController::WebIntentDataFetcher::WebIntentDataFetcher( |
| 263 WebIntentPickerController* controller, | 300 WebIntentPickerController* controller, |
| 264 WebIntentsRegistry* web_intents_registry) | 301 WebIntentsRegistry* web_intents_registry) |
| 265 : controller_(controller), | 302 : controller_(controller), |
| 266 web_intents_registry_(web_intents_registry), | 303 web_intents_registry_(web_intents_registry), |
| 267 query_id_(-1) { | 304 query_id_(-1) { |
| 268 } | 305 } |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 320 void WebIntentPickerController::FaviconFetcher::OnFaviconDataAvailable( | 357 void WebIntentPickerController::FaviconFetcher::OnFaviconDataAvailable( |
| 321 FaviconService::Handle handle, | 358 FaviconService::Handle handle, |
| 322 history::FaviconData favicon_data) { | 359 history::FaviconData favicon_data) { |
| 323 size_t index = load_consumer_.GetClientDataForCurrentRequest(); | 360 size_t index = load_consumer_.GetClientDataForCurrentRequest(); |
| 324 if (favicon_data.is_valid()) { | 361 if (favicon_data.is_valid()) { |
| 325 SkBitmap icon_bitmap; | 362 SkBitmap icon_bitmap; |
| 326 | 363 |
| 327 if (gfx::PNGCodec::Decode(favicon_data.image_data->front(), | 364 if (gfx::PNGCodec::Decode(favicon_data.image_data->front(), |
| 328 favicon_data.image_data->size(), | 365 favicon_data.image_data->size(), |
| 329 &icon_bitmap)) { | 366 &icon_bitmap)) { |
| 330 controller_->OnFaviconDataAvailable(index, icon_bitmap); | 367 gfx::Image icon_image(new SkBitmap(icon_bitmap)); |
| 368 controller_->OnFaviconDataAvailable(index, icon_image); | |
| 331 return; | 369 return; |
| 332 } | 370 } |
| 333 } | 371 } |
| 334 | 372 |
| 335 controller_->OnFaviconDataUnavailable(index); | 373 controller_->OnFaviconDataUnavailable(index); |
| 336 } | 374 } |
| OLD | NEW |