| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "athena/content/web_activity.h" | |
| 6 | |
| 7 #include "athena/activity/public/activity_factory.h" | |
| 8 #include "athena/activity/public/activity_manager.h" | |
| 9 #include "athena/activity/public/activity_view.h" | |
| 10 #include "athena/content/content_proxy.h" | |
| 11 #include "athena/content/media_utils.h" | |
| 12 #include "athena/content/public/dialogs.h" | |
| 13 #include "athena/content/web_activity_helpers.h" | |
| 14 #include "athena/input/public/accelerator_manager.h" | |
| 15 #include "athena/strings/grit/athena_strings.h" | |
| 16 #include "base/bind.h" | |
| 17 #include "base/command_line.h" | |
| 18 #include "base/strings/utf_string_conversions.h" | |
| 19 #include "components/app_modal/javascript_dialog_manager.h" | |
| 20 #include "components/favicon_base/select_favicon_frames.h" | |
| 21 #include "content/public/browser/navigation_controller.h" | |
| 22 #include "content/public/browser/web_contents.h" | |
| 23 #include "content/public/browser/web_contents_delegate.h" | |
| 24 #include "content/public/common/content_switches.h" | |
| 25 #include "content/public/common/favicon_url.h" | |
| 26 #include "ui/aura/window.h" | |
| 27 #include "ui/base/l10n/l10n_util.h" | |
| 28 #include "ui/compositor/closure_animation_observer.h" | |
| 29 #include "ui/compositor/scoped_layer_animation_settings.h" | |
| 30 #include "ui/content_accelerators/accelerator_util.h" | |
| 31 #include "ui/views/background.h" | |
| 32 #include "ui/views/controls/label.h" | |
| 33 #include "ui/views/controls/webview/unhandled_keyboard_event_handler.h" | |
| 34 #include "ui/views/controls/webview/webview.h" | |
| 35 #include "ui/views/focus/focus_manager.h" | |
| 36 #include "ui/views/widget/widget.h" | |
| 37 | |
| 38 namespace athena { | |
| 39 namespace { | |
| 40 | |
| 41 class WebActivityController : public AcceleratorHandler { | |
| 42 public: | |
| 43 enum Command { | |
| 44 CMD_BACK, | |
| 45 CMD_FORWARD, | |
| 46 CMD_RELOAD, | |
| 47 CMD_RELOAD_IGNORE_CACHE, | |
| 48 CMD_CLOSE, | |
| 49 CMD_STOP, | |
| 50 }; | |
| 51 | |
| 52 explicit WebActivityController(WebActivity* owner_activity, | |
| 53 views::WebView* web_view) | |
| 54 : owner_activity_(owner_activity), | |
| 55 web_view_(web_view), | |
| 56 reserved_accelerator_enabled_(true) {} | |
| 57 ~WebActivityController() override {} | |
| 58 | |
| 59 // Installs accelerators for web activity. | |
| 60 void InstallAccelerators() { | |
| 61 accelerator_manager_ = AcceleratorManager::CreateForFocusManager( | |
| 62 web_view_->GetFocusManager()).Pass(); | |
| 63 const AcceleratorData accelerator_data[] = { | |
| 64 {TRIGGER_ON_PRESS, ui::VKEY_R, ui::EF_CONTROL_DOWN, CMD_RELOAD, | |
| 65 AF_NONE}, | |
| 66 {TRIGGER_ON_PRESS, ui::VKEY_BROWSER_REFRESH, ui::EF_NONE, CMD_RELOAD, | |
| 67 AF_NONE}, | |
| 68 {TRIGGER_ON_PRESS, ui::VKEY_BROWSER_REFRESH, ui::EF_CONTROL_DOWN, | |
| 69 CMD_RELOAD_IGNORE_CACHE, AF_NONE}, | |
| 70 {TRIGGER_ON_PRESS, ui::VKEY_BROWSER_FORWARD, ui::EF_NONE, CMD_FORWARD, | |
| 71 AF_NONE}, | |
| 72 {TRIGGER_ON_PRESS, ui::VKEY_BROWSER_BACK, ui::EF_NONE, CMD_BACK, | |
| 73 AF_NONE}, | |
| 74 {TRIGGER_ON_PRESS, ui::VKEY_W, ui::EF_CONTROL_DOWN, CMD_CLOSE, AF_NONE}, | |
| 75 {TRIGGER_ON_PRESS, ui::VKEY_ESCAPE, ui::EF_NONE, CMD_STOP, AF_NONE}, | |
| 76 }; | |
| 77 accelerator_manager_->RegisterAccelerators( | |
| 78 accelerator_data, arraysize(accelerator_data), this); | |
| 79 } | |
| 80 | |
| 81 // Methods that are called before and after key events are consumed by the web | |
| 82 // contents. | |
| 83 // See the documentation in WebContentsDelegate: for more details. | |
| 84 bool PreHandleKeyboardEvent(content::WebContents* source, | |
| 85 const content::NativeWebKeyboardEvent& event, | |
| 86 bool* is_keyboard_shortcut) { | |
| 87 ui::Accelerator accelerator = | |
| 88 ui::GetAcceleratorFromNativeWebKeyboardEvent(event); | |
| 89 | |
| 90 if (reserved_accelerator_enabled_ && | |
| 91 accelerator_manager_->IsRegistered(accelerator, AF_RESERVED)) { | |
| 92 return web_view_->GetFocusManager()->ProcessAccelerator(accelerator); | |
| 93 } | |
| 94 *is_keyboard_shortcut = | |
| 95 accelerator_manager_->IsRegistered(accelerator, AF_NONE); | |
| 96 return false; | |
| 97 } | |
| 98 | |
| 99 void HandleKeyboardEvent(content::WebContents* source, | |
| 100 const content::NativeWebKeyboardEvent& event) { | |
| 101 unhandled_keyboard_event_handler_.HandleKeyboardEvent( | |
| 102 event, web_view_->GetFocusManager()); | |
| 103 } | |
| 104 | |
| 105 private: | |
| 106 // AcceleratorHandler: | |
| 107 bool IsCommandEnabled(int command_id) const override { | |
| 108 switch (command_id) { | |
| 109 case CMD_RELOAD: | |
| 110 case CMD_RELOAD_IGNORE_CACHE: | |
| 111 return true; | |
| 112 case CMD_BACK: | |
| 113 return web_view_->GetWebContents()->GetController().CanGoBack(); | |
| 114 case CMD_FORWARD: | |
| 115 return web_view_->GetWebContents()->GetController().CanGoForward(); | |
| 116 case CMD_CLOSE: | |
| 117 // TODO(oshima): check onbeforeunload handler. | |
| 118 return true; | |
| 119 case CMD_STOP: | |
| 120 return web_view_->GetWebContents()->IsLoading(); | |
| 121 } | |
| 122 return false; | |
| 123 } | |
| 124 | |
| 125 bool OnAcceleratorFired(int command_id, | |
| 126 const ui::Accelerator& accelerator) override { | |
| 127 switch (command_id) { | |
| 128 case CMD_RELOAD: | |
| 129 web_view_->GetWebContents()->GetController().Reload(false); | |
| 130 return true; | |
| 131 case CMD_RELOAD_IGNORE_CACHE: | |
| 132 web_view_->GetWebContents()->GetController().ReloadIgnoringCache(false); | |
| 133 return true; | |
| 134 case CMD_BACK: | |
| 135 web_view_->GetWebContents()->GetController().GoBack(); | |
| 136 return true; | |
| 137 case CMD_FORWARD: | |
| 138 web_view_->GetWebContents()->GetController().GoForward(); | |
| 139 return true; | |
| 140 case CMD_CLOSE: | |
| 141 Activity::Delete(owner_activity_); | |
| 142 return true; | |
| 143 case CMD_STOP: | |
| 144 web_view_->GetWebContents()->Stop(); | |
| 145 return true; | |
| 146 } | |
| 147 return false; | |
| 148 } | |
| 149 | |
| 150 Activity* const owner_activity_; | |
| 151 views::WebView* web_view_; | |
| 152 bool reserved_accelerator_enabled_; | |
| 153 scoped_ptr<AcceleratorManager> accelerator_manager_; | |
| 154 views::UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_; | |
| 155 | |
| 156 DISALLOW_COPY_AND_ASSIGN(WebActivityController); | |
| 157 }; | |
| 158 | |
| 159 const SkColor kDefaultTitleColor = SkColorSetRGB(0xf2, 0xf2, 0xf2); | |
| 160 const int kIconSize = 32; | |
| 161 const float kDistanceShowReloadMessage = 100; | |
| 162 const float kDistanceReload = 150; | |
| 163 | |
| 164 } // namespace | |
| 165 | |
| 166 // A web view for athena's web activity. Note that AthenaWebView will create its | |
| 167 // own content so that it can eject and reload it. | |
| 168 class AthenaWebView : public views::WebView { | |
| 169 public: | |
| 170 explicit AthenaWebView(content::BrowserContext* context, | |
| 171 WebActivity* owner_activity) | |
| 172 : views::WebView(context), | |
| 173 controller_(new WebActivityController(owner_activity, this)), | |
| 174 owner_activity_(owner_activity), | |
| 175 fullscreen_(false), | |
| 176 overscroll_y_(0) { | |
| 177 SetEmbedFullscreenWidgetMode(true); | |
| 178 // TODO(skuhne): Add content observer to detect renderer crash and set | |
| 179 // content status to unloaded if that happens. | |
| 180 } | |
| 181 | |
| 182 AthenaWebView(content::WebContents* web_contents, | |
| 183 WebActivity* owner_activity) | |
| 184 : views::WebView(web_contents->GetBrowserContext()), | |
| 185 controller_(new WebActivityController(owner_activity, this)), | |
| 186 owner_activity_(owner_activity) { | |
| 187 scoped_ptr<content::WebContents> old_contents( | |
| 188 SwapWebContents(scoped_ptr<content::WebContents>(web_contents))); | |
| 189 } | |
| 190 | |
| 191 ~AthenaWebView() override {} | |
| 192 | |
| 193 void InstallAccelerators() { controller_->InstallAccelerators(); } | |
| 194 | |
| 195 void EvictContent() { | |
| 196 scoped_ptr<content::WebContents> old_contents(SwapWebContents( | |
| 197 scoped_ptr<content::WebContents>(content::WebContents::Create( | |
| 198 content::WebContents::CreateParams(browser_context()))))); | |
| 199 // If there is a progress bar, we need to get rid of it now since its | |
| 200 // associated content, parent window and layers will disappear with evicting | |
| 201 // the content. | |
| 202 progress_bar_.reset(); | |
| 203 evicted_web_contents_.reset( | |
| 204 content::WebContents::Create(content::WebContents::CreateParams( | |
| 205 old_contents->GetBrowserContext()))); | |
| 206 evicted_web_contents_->GetController().CopyStateFrom( | |
| 207 old_contents->GetController()); | |
| 208 // As soon as the new contents becomes visible, it should reload. | |
| 209 // TODO(skuhne): This breaks script connections with other activities. | |
| 210 // Even though this is the same technique as used by the TabStripModel, | |
| 211 // we might want to address this cleaner since we are more likely to | |
| 212 // run into this state. by unloading. | |
| 213 } | |
| 214 | |
| 215 void AttachHelpers() { | |
| 216 if (!IsContentEvicted()) | |
| 217 AttachWebActivityHelpers(GetWebContents()); | |
| 218 // Else: The helpers will be attached when the evicted content is reloaded. | |
| 219 } | |
| 220 | |
| 221 void ReloadEvictedContent() { | |
| 222 CHECK(evicted_web_contents_.get()); | |
| 223 | |
| 224 // Order is important. The helpers must be attached prior to the RenderView | |
| 225 // being created. | |
| 226 AttachWebActivityHelpers(evicted_web_contents_.get()); | |
| 227 | |
| 228 SwapWebContents(evicted_web_contents_.Pass()); | |
| 229 } | |
| 230 | |
| 231 // Check if the content got evicted. | |
| 232 const bool IsContentEvicted() { return !!evicted_web_contents_.get(); } | |
| 233 | |
| 234 // content::WebContentsDelegate: | |
| 235 content::WebContents* OpenURLFromTab( | |
| 236 content::WebContents* source, | |
| 237 const content::OpenURLParams& params) override { | |
| 238 switch(params.disposition) { | |
| 239 case CURRENT_TAB: { | |
| 240 DCHECK(source == web_contents()); | |
| 241 content::NavigationController::LoadURLParams load_url_params( | |
| 242 params.url); | |
| 243 load_url_params.referrer = params.referrer; | |
| 244 load_url_params.frame_tree_node_id = params.frame_tree_node_id; | |
| 245 load_url_params.transition_type = params.transition; | |
| 246 load_url_params.extra_headers = params.extra_headers; | |
| 247 load_url_params.should_replace_current_entry = | |
| 248 params.should_replace_current_entry; | |
| 249 load_url_params.is_renderer_initiated = params.is_renderer_initiated; | |
| 250 load_url_params.transferred_global_request_id = | |
| 251 params.transferred_global_request_id; | |
| 252 web_contents()->GetController().LoadURLWithParams(load_url_params); | |
| 253 return web_contents(); | |
| 254 } | |
| 255 case NEW_FOREGROUND_TAB: | |
| 256 case NEW_BACKGROUND_TAB: | |
| 257 case NEW_POPUP: | |
| 258 case NEW_WINDOW: { | |
| 259 Activity* activity = ActivityFactory::Get()->CreateWebActivity( | |
| 260 browser_context(), base::string16(), params.url); | |
| 261 Activity::Show(activity); | |
| 262 break; | |
| 263 } | |
| 264 default: | |
| 265 break; | |
| 266 } | |
| 267 // nullptr is returned if the URL wasn't opened immediately. | |
| 268 return nullptr; | |
| 269 } | |
| 270 | |
| 271 bool CanOverscrollContent() const override { | |
| 272 const std::string value = | |
| 273 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
| 274 switches::kOverscrollHistoryNavigation); | |
| 275 return value != "0"; | |
| 276 } | |
| 277 | |
| 278 void OverscrollUpdate(float delta_y) override { | |
| 279 overscroll_y_ = delta_y; | |
| 280 if (overscroll_y_ > kDistanceShowReloadMessage) { | |
| 281 if (!reload_message_) | |
| 282 CreateReloadMessage(); | |
| 283 reload_message_->Show(); | |
| 284 float opacity = 1.0f; | |
| 285 if (overscroll_y_ < kDistanceReload) { | |
| 286 opacity = (overscroll_y_ - kDistanceShowReloadMessage) / | |
| 287 (kDistanceReload - kDistanceShowReloadMessage); | |
| 288 } | |
| 289 reload_message_->GetLayer()->SetOpacity(opacity); | |
| 290 } else if (reload_message_) { | |
| 291 reload_message_->Hide(); | |
| 292 } | |
| 293 } | |
| 294 | |
| 295 void OverscrollComplete() override { | |
| 296 if (overscroll_y_ >= kDistanceReload) | |
| 297 GetWebContents()->GetController().Reload(false); | |
| 298 if (reload_message_) | |
| 299 reload_message_->Hide(); | |
| 300 overscroll_y_ = 0; | |
| 301 } | |
| 302 | |
| 303 void AddNewContents(content::WebContents* source, | |
| 304 content::WebContents* new_contents, | |
| 305 WindowOpenDisposition disposition, | |
| 306 const gfx::Rect& initial_pos, | |
| 307 bool user_gesture, | |
| 308 bool* was_blocked) override { | |
| 309 Activity* activity = | |
| 310 ActivityFactory::Get()->CreateWebActivity(new_contents); | |
| 311 Activity::Show(activity); | |
| 312 } | |
| 313 | |
| 314 bool PreHandleKeyboardEvent(content::WebContents* source, | |
| 315 const content::NativeWebKeyboardEvent& event, | |
| 316 bool* is_keyboard_shortcut) override { | |
| 317 return controller_->PreHandleKeyboardEvent( | |
| 318 source, event, is_keyboard_shortcut); | |
| 319 } | |
| 320 | |
| 321 void HandleKeyboardEvent( | |
| 322 content::WebContents* source, | |
| 323 const content::NativeWebKeyboardEvent& event) override { | |
| 324 controller_->HandleKeyboardEvent(source, event); | |
| 325 } | |
| 326 | |
| 327 void ToggleFullscreenModeForTab(content::WebContents* web_contents, | |
| 328 bool enter_fullscreen) override { | |
| 329 fullscreen_ = enter_fullscreen; | |
| 330 GetWidget()->SetFullscreen(fullscreen_); | |
| 331 } | |
| 332 | |
| 333 bool IsFullscreenForTabOrPending( | |
| 334 const content::WebContents* web_contents) const override { | |
| 335 return fullscreen_; | |
| 336 } | |
| 337 | |
| 338 void LoadingStateChanged(content::WebContents* source, | |
| 339 bool to_different_document) override { | |
| 340 bool has_stopped = source == nullptr || !source->IsLoading(); | |
| 341 LoadProgressChanged(source, has_stopped ? 1 : 0); | |
| 342 } | |
| 343 | |
| 344 void LoadProgressChanged(content::WebContents* source, | |
| 345 double progress) override { | |
| 346 if (!progress) | |
| 347 return; | |
| 348 | |
| 349 if (!progress_bar_) { | |
| 350 CreateProgressBar(); | |
| 351 source->GetNativeView()->layer()->Add(progress_bar_.get()); | |
| 352 } | |
| 353 progress_bar_->SetBounds(gfx::Rect( | |
| 354 0, 0, progress * progress_bar_->parent()->bounds().width(), 3)); | |
| 355 if (progress < 1) | |
| 356 return; | |
| 357 | |
| 358 ui::ScopedLayerAnimationSettings settings(progress_bar_->GetAnimator()); | |
| 359 settings.SetTweenType(gfx::Tween::EASE_IN); | |
| 360 ui::Layer* layer = progress_bar_.get(); | |
| 361 settings.AddObserver(new ui::ClosureAnimationObserver( | |
| 362 base::Bind(&base::DeletePointer<ui::Layer>, progress_bar_.release()))); | |
| 363 layer->SetOpacity(0.f); | |
| 364 } | |
| 365 | |
| 366 content::JavaScriptDialogManager* GetJavaScriptDialogManager( | |
| 367 content::WebContents* contents) override { | |
| 368 return app_modal::JavaScriptDialogManager::GetInstance(); | |
| 369 } | |
| 370 | |
| 371 content::ColorChooser* OpenColorChooser( | |
| 372 content::WebContents* web_contents, | |
| 373 SkColor color, | |
| 374 const std::vector<content::ColorSuggestion>& suggestions) override { | |
| 375 return athena::OpenColorChooser(web_contents, color, suggestions); | |
| 376 } | |
| 377 | |
| 378 // Called when a file selection is to be done. | |
| 379 void RunFileChooser(content::WebContents* web_contents, | |
| 380 const content::FileChooserParams& params) override { | |
| 381 return athena::OpenFileChooser(web_contents, params); | |
| 382 } | |
| 383 | |
| 384 void CloseContents(content::WebContents* contents) override { | |
| 385 Activity::Delete(owner_activity_); | |
| 386 } | |
| 387 | |
| 388 private: | |
| 389 void CreateProgressBar() { | |
| 390 CHECK(!progress_bar_); | |
| 391 progress_bar_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR)); | |
| 392 progress_bar_->SetColor(SkColorSetRGB(0x17, 0x59, 0xcd)); | |
| 393 } | |
| 394 | |
| 395 void CreateReloadMessage() { | |
| 396 CHECK(!reload_message_); | |
| 397 reload_message_.reset(new views::Widget); | |
| 398 views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL); | |
| 399 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | |
| 400 params.parent = GetWidget()->GetNativeView(); | |
| 401 reload_message_->Init(params); | |
| 402 | |
| 403 views::Label* label = new views::Label( | |
| 404 l10n_util::GetStringUTF16(IDS_ATHENA_PULL_TO_RELOAD_MESSAGE)); | |
| 405 label->SetBackgroundColor(SK_ColorGRAY); | |
| 406 label->set_background( | |
| 407 views::Background::CreateSolidBackground(SK_ColorGRAY)); | |
| 408 | |
| 409 reload_message_->SetContentsView(label); | |
| 410 reload_message_->SetBounds(ConvertRectToWidget( | |
| 411 gfx::Rect(0, 0, width(), label->GetPreferredSize().height()))); | |
| 412 } | |
| 413 | |
| 414 scoped_ptr<WebActivityController> controller_; | |
| 415 | |
| 416 Activity* const owner_activity_; | |
| 417 | |
| 418 // If the activity got evicted, this is the web content which holds the known | |
| 419 // state of the content before eviction. | |
| 420 scoped_ptr<content::WebContents> evicted_web_contents_; | |
| 421 | |
| 422 scoped_ptr<ui::Layer> progress_bar_; | |
| 423 | |
| 424 scoped_ptr<views::Widget> reload_message_; | |
| 425 | |
| 426 // TODO(oshima): Find out if we should support window fullscreen. | |
| 427 // It may still useful when a user is in split mode. | |
| 428 bool fullscreen_; | |
| 429 | |
| 430 // The distance that the user has overscrolled vertically. | |
| 431 float overscroll_y_; | |
| 432 | |
| 433 DISALLOW_COPY_AND_ASSIGN(AthenaWebView); | |
| 434 }; | |
| 435 | |
| 436 WebActivity::WebActivity(content::BrowserContext* browser_context, | |
| 437 const base::string16& title, | |
| 438 const GURL& url) | |
| 439 : browser_context_(browser_context), | |
| 440 web_view_(new AthenaWebView(browser_context, this)), | |
| 441 title_(title), | |
| 442 title_color_(kDefaultTitleColor), | |
| 443 current_state_(ACTIVITY_UNLOADED), | |
| 444 activity_view_(nullptr), | |
| 445 weak_ptr_factory_(this) { | |
| 446 // Order is important. The web activity helpers must be attached prior to the | |
| 447 // RenderView being created. | |
| 448 SetCurrentState(ACTIVITY_INVISIBLE); | |
| 449 web_view_->LoadInitialURL(url); | |
| 450 } | |
| 451 | |
| 452 WebActivity::WebActivity(content::WebContents* contents) | |
| 453 : browser_context_(contents->GetBrowserContext()), | |
| 454 web_view_(new AthenaWebView(contents, this)), | |
| 455 title_color_(kDefaultTitleColor), | |
| 456 current_state_(ACTIVITY_UNLOADED), | |
| 457 activity_view_(nullptr), | |
| 458 weak_ptr_factory_(this) { | |
| 459 // If the activity was created as a result of | |
| 460 // WebContentsDelegate::AddNewContents(), web activity helpers may not be | |
| 461 // created prior to the RenderView being created. Desktop Chrome has a | |
| 462 // similar problem. | |
| 463 SetCurrentState(ACTIVITY_INVISIBLE); | |
| 464 } | |
| 465 | |
| 466 WebActivity::~WebActivity() { | |
| 467 // It is not required to change the activity state to UNLOADED - unless we | |
| 468 // would add state observers. | |
| 469 } | |
| 470 | |
| 471 ActivityViewModel* WebActivity::GetActivityViewModel() { | |
| 472 return this; | |
| 473 } | |
| 474 | |
| 475 void WebActivity::SetCurrentState(Activity::ActivityState state) { | |
| 476 DCHECK_NE(state, current_state_); | |
| 477 if (current_state_ == ACTIVITY_UNLOADED) { | |
| 478 web_view_->AttachHelpers(); | |
| 479 if (web_view_->IsContentEvicted()) | |
| 480 web_view_->ReloadEvictedContent(); | |
| 481 Observe(web_view_->GetWebContents()); | |
| 482 } | |
| 483 | |
| 484 switch (state) { | |
| 485 case ACTIVITY_VISIBLE: | |
| 486 HideContentProxy(); | |
| 487 break; | |
| 488 case ACTIVITY_INVISIBLE: | |
| 489 if (current_state_ == ACTIVITY_VISIBLE) | |
| 490 ShowContentProxy(); | |
| 491 | |
| 492 break; | |
| 493 case ACTIVITY_BACKGROUND_LOW_PRIORITY: | |
| 494 DCHECK(ACTIVITY_VISIBLE == current_state_ || | |
| 495 ACTIVITY_INVISIBLE == current_state_); | |
| 496 // TODO(skuhne): Do this. | |
| 497 break; | |
| 498 case ACTIVITY_PERSISTENT: | |
| 499 DCHECK_EQ(ACTIVITY_BACKGROUND_LOW_PRIORITY, current_state_); | |
| 500 // TODO(skuhne): Do this. As soon as the new resource management is | |
| 501 // agreed upon - or remove otherwise. | |
| 502 break; | |
| 503 case ACTIVITY_UNLOADED: | |
| 504 DCHECK_NE(ACTIVITY_UNLOADED, current_state_); | |
| 505 if (content_proxy_) | |
| 506 content_proxy_->ContentWillUnload(); | |
| 507 Observe(nullptr); | |
| 508 web_view_->EvictContent(); | |
| 509 break; | |
| 510 } | |
| 511 // Remember the last requested state. | |
| 512 current_state_ = state; | |
| 513 } | |
| 514 | |
| 515 Activity::ActivityState WebActivity::GetCurrentState() { | |
| 516 // If the content is evicted, the state has to be UNLOADED. | |
| 517 DCHECK(!web_view_->IsContentEvicted() || | |
| 518 current_state_ == ACTIVITY_UNLOADED); | |
| 519 return current_state_; | |
| 520 } | |
| 521 | |
| 522 bool WebActivity::IsVisible() { | |
| 523 return web_view_->visible() && current_state_ != ACTIVITY_UNLOADED; | |
| 524 } | |
| 525 | |
| 526 Activity::ActivityMediaState WebActivity::GetMediaState() { | |
| 527 return current_state_ == ACTIVITY_UNLOADED ? | |
| 528 Activity::ACTIVITY_MEDIA_STATE_NONE : | |
| 529 GetActivityMediaState(GetWebContents()); | |
| 530 } | |
| 531 | |
| 532 aura::Window* WebActivity::GetWindow() { | |
| 533 return web_view_->GetWidget() ? web_view_->GetWidget()->GetNativeWindow() | |
| 534 : nullptr; | |
| 535 } | |
| 536 | |
| 537 content::WebContents* WebActivity::GetWebContents() { | |
| 538 return web_view_->GetWebContents(); | |
| 539 } | |
| 540 | |
| 541 void WebActivity::Init() { | |
| 542 web_view_->InstallAccelerators(); | |
| 543 } | |
| 544 | |
| 545 SkColor WebActivity::GetRepresentativeColor() const { | |
| 546 return title_color_; | |
| 547 } | |
| 548 | |
| 549 base::string16 WebActivity::GetTitle() const { | |
| 550 if (!title_.empty()) | |
| 551 return title_; | |
| 552 const base::string16& title = web_view_->GetWebContents()->GetTitle(); | |
| 553 if (!title.empty()) | |
| 554 return title; | |
| 555 return base::UTF8ToUTF16(web_view_->GetWebContents()->GetVisibleURL().host()); | |
| 556 } | |
| 557 | |
| 558 gfx::ImageSkia WebActivity::GetIcon() const { | |
| 559 return icon_; | |
| 560 } | |
| 561 | |
| 562 void WebActivity::SetActivityView(ActivityView* view) { | |
| 563 DCHECK(!activity_view_); | |
| 564 activity_view_ = view; | |
| 565 } | |
| 566 | |
| 567 bool WebActivity::UsesFrame() const { | |
| 568 return true; | |
| 569 } | |
| 570 | |
| 571 views::View* WebActivity::GetContentsView() { | |
| 572 return web_view_; | |
| 573 } | |
| 574 | |
| 575 gfx::ImageSkia WebActivity::GetOverviewModeImage() { | |
| 576 if (content_proxy_.get()) | |
| 577 return content_proxy_->GetContentImage(); | |
| 578 return gfx::ImageSkia(); | |
| 579 } | |
| 580 | |
| 581 void WebActivity::PrepareContentsForOverview() { | |
| 582 // Turn on fast resizing to avoid re-laying out the web contents when | |
| 583 // entering / exiting overview mode and the content is visible. | |
| 584 if (!content_proxy_.get()) | |
| 585 web_view_->SetFastResize(true); | |
| 586 } | |
| 587 | |
| 588 void WebActivity::ResetContentsView() { | |
| 589 // Turn on fast resizing to avoid re-laying out the web contents when | |
| 590 // entering / exiting overview mode and the content is visible. | |
| 591 if (!content_proxy_.get()) { | |
| 592 web_view_->SetFastResize(false); | |
| 593 web_view_->Layout(); | |
| 594 } | |
| 595 } | |
| 596 | |
| 597 void WebActivity::TitleWasSet(content::NavigationEntry* entry, | |
| 598 bool explicit_set) { | |
| 599 if (activity_view_) | |
| 600 activity_view_->UpdateTitle(); | |
| 601 } | |
| 602 | |
| 603 void WebActivity::DidNavigateMainFrame( | |
| 604 const content::LoadCommittedDetails& details, | |
| 605 const content::FrameNavigateParams& params) { | |
| 606 // Prevent old image requests from calling back to OnDidDownloadFavicon(). | |
| 607 weak_ptr_factory_.InvalidateWeakPtrs(); | |
| 608 | |
| 609 icon_ = gfx::ImageSkia(); | |
| 610 if (activity_view_) | |
| 611 activity_view_->UpdateIcon(); | |
| 612 } | |
| 613 | |
| 614 void WebActivity::DidUpdateFaviconURL( | |
| 615 const std::vector<content::FaviconURL>& candidates) { | |
| 616 // Pick an arbitrary favicon of type FAVICON to use. | |
| 617 // TODO(pkotwicz): Do something better once the favicon code is componentized. | |
| 618 // (crbug.com/401997) | |
| 619 weak_ptr_factory_.InvalidateWeakPtrs(); | |
| 620 for (size_t i = 0; i < candidates.size(); ++i) { | |
| 621 if (candidates[i].icon_type == content::FaviconURL::FAVICON) { | |
| 622 web_view_->GetWebContents()->DownloadImage( | |
| 623 candidates[i].icon_url, | |
| 624 true, | |
| 625 0, | |
| 626 base::Bind(&WebActivity::OnDidDownloadFavicon, | |
| 627 weak_ptr_factory_.GetWeakPtr())); | |
| 628 break; | |
| 629 } | |
| 630 } | |
| 631 } | |
| 632 | |
| 633 void WebActivity::OnDidDownloadFavicon( | |
| 634 int id, | |
| 635 int http_status_code, | |
| 636 const GURL& url, | |
| 637 const std::vector<SkBitmap>& bitmaps, | |
| 638 const std::vector<gfx::Size>& original_bitmap_sizes) { | |
| 639 icon_ = CreateFaviconImageSkia( | |
| 640 bitmaps, original_bitmap_sizes, kIconSize, nullptr); | |
| 641 if (activity_view_) | |
| 642 activity_view_->UpdateIcon(); | |
| 643 } | |
| 644 | |
| 645 void WebActivity::DidChangeThemeColor(SkColor theme_color) { | |
| 646 title_color_ = theme_color; | |
| 647 if (activity_view_) | |
| 648 activity_view_->UpdateRepresentativeColor(); | |
| 649 } | |
| 650 | |
| 651 void WebActivity::HideContentProxy() { | |
| 652 if (content_proxy_.get()) | |
| 653 content_proxy_.reset(nullptr); | |
| 654 } | |
| 655 | |
| 656 void WebActivity::ShowContentProxy() { | |
| 657 if (!content_proxy_.get()) | |
| 658 content_proxy_.reset(new ContentProxy(web_view_)); | |
| 659 } | |
| 660 | |
| 661 } // namespace athena | |
| OLD | NEW |