Adding Baseframework of the ResourceManager (all hooks and observers)
[chromium-blink-merge.git] / athena / content / web_activity.cc
blob795c8c3f7bc0257ab101cb43b6d6f696a3493b03
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.
5 #include "athena/content/web_activity.h"
7 #include "athena/activity/public/activity_factory.h"
8 #include "athena/activity/public/activity_manager.h"
9 #include "athena/input/public/accelerator_manager.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "content/public/browser/native_web_keyboard_event.h"
12 #include "content/public/browser/navigation_controller.h"
13 #include "content/public/browser/web_contents.h"
14 #include "content/public/browser/web_contents_delegate.h"
15 #include "ui/aura/window.h"
16 #include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
17 #include "ui/views/controls/webview/webview.h"
18 #include "ui/views/focus/focus_manager.h"
19 #include "ui/views/widget/widget.h"
21 namespace athena {
22 namespace {
24 class WebActivityController : public AcceleratorHandler {
25 public:
26 enum Command {
27 CMD_BACK,
28 CMD_FORWARD,
29 CMD_RELOAD,
30 CMD_RELOAD_IGNORE_CACHE,
31 CMD_CLOSE,
34 explicit WebActivityController(views::WebView* web_view)
35 : web_view_(web_view), reserved_accelerator_enabled_(true) {}
36 virtual ~WebActivityController() {}
38 // Installs accelerators for web activity.
39 void InstallAccelerators() {
40 accelerator_manager_ = AcceleratorManager::CreateForFocusManager(
41 web_view_->GetFocusManager()).Pass();
42 const AcceleratorData accelerator_data[] = {
43 {TRIGGER_ON_PRESS, ui::VKEY_R, ui::EF_CONTROL_DOWN, CMD_RELOAD,
44 AF_NONE},
45 {TRIGGER_ON_PRESS, ui::VKEY_BROWSER_REFRESH, ui::EF_NONE, CMD_RELOAD,
46 AF_NONE},
47 {TRIGGER_ON_PRESS, ui::VKEY_BROWSER_REFRESH, ui::EF_CONTROL_DOWN,
48 CMD_RELOAD_IGNORE_CACHE, AF_NONE},
49 {TRIGGER_ON_PRESS, ui::VKEY_BROWSER_FORWARD, ui::EF_NONE, CMD_FORWARD,
50 AF_NONE},
51 {TRIGGER_ON_PRESS, ui::VKEY_BROWSER_BACK, ui::EF_NONE, CMD_BACK,
52 AF_NONE},
53 {TRIGGER_ON_PRESS, ui::VKEY_W, ui::EF_CONTROL_DOWN, CMD_CLOSE, AF_NONE},
55 accelerator_manager_->RegisterAccelerators(
56 accelerator_data, arraysize(accelerator_data), this);
59 // Methods that are called before and after key events are consumed by the web
60 // contents.
61 // See the documentation in WebContentsDelegate: for more details.
62 bool PreHandleKeyboardEvent(content::WebContents* source,
63 const content::NativeWebKeyboardEvent& event,
64 bool* is_keyboard_shortcut) {
65 ui::Accelerator accelerator(
66 static_cast<ui::KeyboardCode>(event.windowsKeyCode),
67 content::GetModifiersFromNativeWebKeyboardEvent(event));
68 if (event.type == blink::WebInputEvent::KeyUp)
69 accelerator.set_type(ui::ET_KEY_RELEASED);
71 if (reserved_accelerator_enabled_ &&
72 accelerator_manager_->IsRegistered(accelerator, AF_RESERVED)) {
73 return web_view_->GetFocusManager()->ProcessAccelerator(accelerator);
75 *is_keyboard_shortcut =
76 accelerator_manager_->IsRegistered(accelerator, AF_NONE);
77 return false;
80 void HandleKeyboardEvent(content::WebContents* source,
81 const content::NativeWebKeyboardEvent& event) {
82 unhandled_keyboard_event_handler_.HandleKeyboardEvent(
83 event, web_view_->GetFocusManager());
86 private:
87 // AcceleratorHandler:
88 virtual bool IsCommandEnabled(int command_id) const OVERRIDE {
89 switch (command_id) {
90 case CMD_RELOAD:
91 case CMD_RELOAD_IGNORE_CACHE:
92 return true;
93 case CMD_BACK:
94 return web_view_->GetWebContents()->GetController().CanGoBack();
95 case CMD_FORWARD:
96 return web_view_->GetWebContents()->GetController().CanGoForward();
97 case CMD_CLOSE:
98 // TODO(oshima): check onbeforeunload handler.
99 return true;
101 return false;
104 virtual bool OnAcceleratorFired(int command_id,
105 const ui::Accelerator& accelerator) OVERRIDE {
106 switch (command_id) {
107 case CMD_RELOAD:
108 web_view_->GetWebContents()->GetController().Reload(false);
109 return true;
110 case CMD_RELOAD_IGNORE_CACHE:
111 web_view_->GetWebContents()->GetController().ReloadIgnoringCache(false);
112 return true;
113 case CMD_BACK:
114 web_view_->GetWebContents()->GetController().GoBack();
115 return true;
116 case CMD_FORWARD:
117 web_view_->GetWebContents()->GetController().GoForward();
118 return true;
119 case CMD_CLOSE:
120 web_view_->GetWidget()->Close();
121 return true;
123 return false;
126 views::WebView* web_view_;
127 bool reserved_accelerator_enabled_;
128 scoped_ptr<AcceleratorManager> accelerator_manager_;
129 views::UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_;
131 DISALLOW_COPY_AND_ASSIGN(WebActivityController);
134 const SkColor kDefaultTitleColor = SkColorSetRGB(0xf2, 0xf2, 0xf2);
135 const SkColor kDefaultUnavailableColor = SkColorSetRGB(0xbb, 0x77, 0x77);
137 } // namespace
139 // A web view for athena's web activity. Note that AthenaWebView will create its
140 // own content so that it can eject and reload it.
141 class AthenaWebView : public views::WebView {
142 public:
143 AthenaWebView(content::BrowserContext* context)
144 : views::WebView(context), controller_(new WebActivityController(this)),
145 fullscreen_(false) {
146 SetEmbedFullscreenWidgetMode(true);
147 // TODO(skuhne): Add content observer to detect renderer crash and set
148 // content status to unloaded if that happens.
151 AthenaWebView(content::WebContents* web_contents)
152 : views::WebView(web_contents->GetBrowserContext()),
153 controller_(new WebActivityController(this)) {
154 scoped_ptr<content::WebContents> old_contents(
155 SwapWebContents(scoped_ptr<content::WebContents>(web_contents)));
158 virtual ~AthenaWebView() {}
160 void InstallAccelerators() { controller_->InstallAccelerators(); }
162 void EvictContent() {
163 scoped_ptr<content::WebContents> old_contents(SwapWebContents(
164 scoped_ptr<content::WebContents>(content::WebContents::Create(
165 content::WebContents::CreateParams(browser_context())))));
166 evicted_web_contents_.reset(
167 content::WebContents::Create(content::WebContents::CreateParams(
168 old_contents->GetBrowserContext())));
169 evicted_web_contents_->GetController().CopyStateFrom(
170 old_contents->GetController());
171 // As soon as the new contents becomes visible, it should reload.
172 // TODO(skuhne): This breaks script connections with other activities.
173 // Even though this is the same technique as used by the TabStripModel,
174 // we might want to address this cleaner since we are more likely to
175 // run into this state. by unloading.
178 void ReloadContent() {
179 CHECK(evicted_web_contents_.get());
180 scoped_ptr<content::WebContents> replaced_contents(SwapWebContents(
181 evicted_web_contents_.Pass()));
184 // Check if the content got evicted.
185 const bool IsContentEvicted() { return !!evicted_web_contents_.get(); }
187 // content::WebContentsDelegate:
188 virtual content::WebContents* OpenURLFromTab(
189 content::WebContents* source,
190 const content::OpenURLParams& params) OVERRIDE {
191 switch(params.disposition) {
192 case CURRENT_TAB: {
193 DCHECK(source == web_contents());
194 content::NavigationController::LoadURLParams load_url_params(
195 params.url);
196 load_url_params.referrer = params.referrer;
197 load_url_params.frame_tree_node_id = params.frame_tree_node_id;
198 load_url_params.transition_type = params.transition;
199 load_url_params.extra_headers = params.extra_headers;
200 load_url_params.should_replace_current_entry =
201 params.should_replace_current_entry;
202 load_url_params.is_renderer_initiated = params.is_renderer_initiated;
203 load_url_params.transferred_global_request_id =
204 params.transferred_global_request_id;
205 web_contents()->GetController().LoadURLWithParams(load_url_params);
206 return web_contents();
208 case NEW_FOREGROUND_TAB:
209 case NEW_BACKGROUND_TAB:
210 case NEW_POPUP:
211 case NEW_WINDOW: {
212 ActivityManager::Get()->AddActivity(
213 ActivityFactory::Get()->CreateWebActivity(browser_context(),
214 params.url));
215 break;
217 default:
218 break;
220 // NULL is returned if the URL wasn't opened immediately.
221 return NULL;
224 virtual void AddNewContents(content::WebContents* source,
225 content::WebContents* new_contents,
226 WindowOpenDisposition disposition,
227 const gfx::Rect& initial_pos,
228 bool user_gesture,
229 bool* was_blocked) OVERRIDE {
230 ActivityManager::Get()->AddActivity(
231 new WebActivity(new AthenaWebView(new_contents)));
234 virtual bool PreHandleKeyboardEvent(
235 content::WebContents* source,
236 const content::NativeWebKeyboardEvent& event,
237 bool* is_keyboard_shortcut) OVERRIDE {
238 return controller_->PreHandleKeyboardEvent(
239 source, event, is_keyboard_shortcut);
242 virtual void HandleKeyboardEvent(
243 content::WebContents* source,
244 const content::NativeWebKeyboardEvent& event) OVERRIDE {
245 controller_->HandleKeyboardEvent(source, event);
248 virtual void ToggleFullscreenModeForTab(content::WebContents* web_contents,
249 bool enter_fullscreen) OVERRIDE {
250 fullscreen_ = enter_fullscreen;
251 GetWidget()->SetFullscreen(fullscreen_);
254 virtual bool IsFullscreenForTabOrPending(
255 const content::WebContents* web_contents) const OVERRIDE {
256 return fullscreen_;
259 private:
260 scoped_ptr<WebActivityController> controller_;
262 // If the activity got evicted, this is the web content which holds the known
263 // state of the content before eviction.
264 scoped_ptr<content::WebContents> evicted_web_contents_;
266 // TODO(oshima): Find out if we should support window fullscreen.
267 // It may still useful when a user is in split mode.
268 bool fullscreen_;
270 DISALLOW_COPY_AND_ASSIGN(AthenaWebView);
273 WebActivity::WebActivity(content::BrowserContext* browser_context,
274 const GURL& url)
275 : browser_context_(browser_context),
276 url_(url),
277 web_view_(NULL),
278 title_color_(kDefaultTitleColor),
279 current_state_(ACTIVITY_UNLOADED) {
282 WebActivity::WebActivity(AthenaWebView* web_view)
283 : browser_context_(web_view->browser_context()),
284 url_(web_view->GetWebContents()->GetURL()),
285 web_view_(web_view),
286 current_state_(ACTIVITY_UNLOADED) {
287 // Transition to state ACTIVITY_INVISIBLE to perform the same setup steps
288 // as on new activities (namely adding a WebContentsObserver).
289 SetCurrentState(ACTIVITY_INVISIBLE);
292 WebActivity::~WebActivity() {
293 // It is not required to change the activity state to UNLOADED - unless we
294 // would add state observers.
297 ActivityViewModel* WebActivity::GetActivityViewModel() {
298 return this;
301 void WebActivity::SetCurrentState(Activity::ActivityState state) {
302 switch (state) {
303 case ACTIVITY_VISIBLE:
304 // Fall through (for the moment).
305 case ACTIVITY_INVISIBLE:
306 // By clearing the overview mode image we allow the content to be shown.
307 overview_mode_image_ = gfx::ImageSkia();
308 if (web_view_->IsContentEvicted()) {
309 DCHECK_EQ(ACTIVITY_UNLOADED, current_state_);
310 web_view_->ReloadContent();
312 Observe(web_view_->GetWebContents());
313 break;
314 case ACTIVITY_BACKGROUND_LOW_PRIORITY:
315 DCHECK(ACTIVITY_VISIBLE == current_state_ ||
316 ACTIVITY_INVISIBLE == current_state_);
317 // TODO(skuhne): Do this.
318 break;
319 case ACTIVITY_PERSISTENT:
320 DCHECK_EQ(ACTIVITY_BACKGROUND_LOW_PRIORITY, current_state_);
321 // TODO(skuhne): Do this. As soon as the new resource management is
322 // agreed upon - or remove otherwise.
323 break;
324 case ACTIVITY_UNLOADED:
325 DCHECK_NE(ACTIVITY_UNLOADED, current_state_);
326 Observe(NULL);
327 web_view_->EvictContent();
328 break;
330 // Remember the last requested state.
331 current_state_ = state;
334 Activity::ActivityState WebActivity::GetCurrentState() {
335 if (!web_view_ || web_view_->IsContentEvicted()) {
336 DCHECK_EQ(ACTIVITY_UNLOADED, current_state_);
337 return ACTIVITY_UNLOADED;
339 // TODO(skuhne): This should be controlled by an observer and should not
340 // reside here.
341 if (IsVisible() && current_state_ != ACTIVITY_VISIBLE)
342 SetCurrentState(ACTIVITY_VISIBLE);
343 // Note: If the activity is not visible it does not necessarily mean that it
344 // does not have GPU compositor resources (yet).
346 return current_state_;
349 bool WebActivity::IsVisible() {
350 return web_view_ &&
351 web_view_->IsDrawn() &&
352 current_state_ != ACTIVITY_UNLOADED &&
353 GetWindow() &&
354 GetWindow()->IsVisible();
357 Activity::ActivityMediaState WebActivity::GetMediaState() {
358 // TODO(skuhne): The function GetTabMediaStateForContents(WebContents),
359 // and the AudioStreamMonitor needs to be moved from Chrome into contents to
360 // make it more modular and so that we can use it from here.
361 return Activity::ACTIVITY_MEDIA_STATE_NONE;
364 aura::Window* WebActivity::GetWindow() {
365 return !web_view_ ? NULL : web_view_->GetWidget()->GetNativeWindow();
368 void WebActivity::Init() {
369 DCHECK(web_view_);
370 web_view_->InstallAccelerators();
373 SkColor WebActivity::GetRepresentativeColor() const {
374 // TODO(sad): Compute the color from the favicon.
375 return web_view_ ? title_color_ : kDefaultUnavailableColor;
378 base::string16 WebActivity::GetTitle() const {
379 return web_view_ ? base::UTF8ToUTF16(
380 web_view_->GetWebContents()->GetVisibleURL().host())
381 : base::string16();
384 bool WebActivity::UsesFrame() const {
385 return true;
388 views::View* WebActivity::GetContentsView() {
389 if (!web_view_) {
390 web_view_ = new AthenaWebView(browser_context_);
391 web_view_->LoadInitialURL(url_);
392 SetCurrentState(ACTIVITY_INVISIBLE);
393 // Reset the overview mode image.
394 overview_mode_image_ = gfx::ImageSkia();
396 return web_view_;
399 void WebActivity::CreateOverviewModeImage() {
400 // TODO(skuhne): Create an overview.
403 gfx::ImageSkia WebActivity::GetOverviewModeImage() {
404 return overview_mode_image_;
407 void WebActivity::TitleWasSet(content::NavigationEntry* entry,
408 bool explicit_set) {
409 ActivityManager::Get()->UpdateActivity(this);
412 void WebActivity::DidUpdateFaviconURL(
413 const std::vector<content::FaviconURL>& candidates) {
414 ActivityManager::Get()->UpdateActivity(this);
417 void WebActivity::DidChangeThemeColor(SkColor theme_color) {
418 title_color_ = theme_color;
421 } // namespace athena