blob: abfc07aaac6d8d925ca3cd92ba119fba66a1e86c [file] [log] [blame]
dmazzoni94a4f882015-11-13 05:46:521// Copyright 2015 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
James Cook6316a552017-03-05 21:46:215#include "ash/common/accessibility_types.h"
James Cook643b7182017-03-05 22:02:586#include "ash/common/shelf/shelf_layout_manager.h"
7#include "ash/common/shelf/wm_shelf.h"
James Cook6316a552017-03-05 21:46:218#include "ash/common/wm_window.h"
jamescook8800b8232016-10-19 12:46:279#include "ash/public/cpp/shell_window_ids.h"
dmazzonid47388d2016-03-31 16:03:5110#include "ash/root_window_controller.h"
dmazzoni94a4f882015-11-13 05:46:5211#include "ash/shell.h"
avi8a07d53892015-12-24 22:13:5312#include "base/macros.h"
dmazzoni94a4f882015-11-13 05:46:5213#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
14#include "chrome/browser/chromeos/accessibility/chromevox_panel.h"
kundaji14f8baa82016-11-08 18:34:2315#include "chrome/browser/data_use_measurement/data_use_web_contents_observer.h"
dmazzoni5ba638d2016-01-07 22:58:5416#include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
dmazzoni94a4f882015-11-13 05:46:5217#include "chrome/common/extensions/extension_constants.h"
18#include "content/public/browser/web_contents.h"
dmazzoni5ba638d2016-01-07 22:58:5419#include "extensions/browser/view_type_utils.h"
oshimad5c972e2016-04-28 23:17:1420#include "ui/display/screen.h"
dmazzoni94a4f882015-11-13 05:46:5221#include "ui/views/controls/webview/webview.h"
22#include "ui/views/layout/fill_layout.h"
23#include "ui/views/widget/widget.h"
24#include "ui/wm/core/shadow_types.h"
25#include "ui/wm/core/window_animations.h"
26
27namespace {
28
29const int kPanelHeight = 35;
30const char kChromeVoxPanelRelativeUrl[] = "/cvox2/background/panel.html";
31const char kFullscreenURLFragment[] = "fullscreen";
32const char kDisableSpokenFeedbackURLFragment[] = "close";
dtseng8624c9d2016-03-04 16:15:5633const char kFocusURLFragment[] = "focus";
dmazzoni94a4f882015-11-13 05:46:5234
35} // namespace
36
37class ChromeVoxPanelWebContentsObserver : public content::WebContentsObserver {
38 public:
39 ChromeVoxPanelWebContentsObserver(content::WebContents* web_contents,
40 ChromeVoxPanel* panel)
41 : content::WebContentsObserver(web_contents), panel_(panel) {}
42 ~ChromeVoxPanelWebContentsObserver() override {}
43
44 // content::WebContentsObserver overrides.
45 void DidFirstVisuallyNonEmptyPaint() override {
46 panel_->DidFirstVisuallyNonEmptyPaint();
47 }
48
49 void DidFinishNavigation(
50 content::NavigationHandle* navigation_handle) override {
51 // The ChromeVox panel uses the URL fragment to communicate state
52 // to this panel host.
53 std::string fragment = web_contents()->GetLastCommittedURL().ref();
54 if (fragment == kDisableSpokenFeedbackURLFragment)
55 panel_->DisableSpokenFeedback();
56 else if (fragment == kFullscreenURLFragment)
57 panel_->EnterFullscreen();
dtseng8624c9d2016-03-04 16:15:5658 else if (fragment == kFocusURLFragment)
59 panel_->Focus();
dmazzoni94a4f882015-11-13 05:46:5260 else
61 panel_->ExitFullscreen();
62 }
63
64 private:
65 ChromeVoxPanel* panel_;
66
67 DISALLOW_COPY_AND_ASSIGN(ChromeVoxPanelWebContentsObserver);
68};
69
70ChromeVoxPanel::ChromeVoxPanel(content::BrowserContext* browser_context)
dmazzonid47388d2016-03-31 16:03:5171 : widget_(nullptr), web_view_(nullptr), panel_fullscreen_(false) {
dmazzoni94a4f882015-11-13 05:46:5272 std::string url("chrome-extension://");
73 url += extension_misc::kChromeVoxExtensionId;
74 url += kChromeVoxPanelRelativeUrl;
75
76 views::WebView* web_view = new views::WebView(browser_context);
dmazzoni5ba638d2016-01-07 22:58:5477 content::WebContents* contents = web_view->GetWebContents();
dmazzoni94a4f882015-11-13 05:46:5278 web_contents_observer_.reset(
dmazzoni5ba638d2016-01-07 22:58:5479 new ChromeVoxPanelWebContentsObserver(contents, this));
kundaji14f8baa82016-11-08 18:34:2380 data_use_measurement::DataUseWebContentsObserver::CreateForWebContents(
81 contents);
dmazzoni5ba638d2016-01-07 22:58:5482 extensions::SetViewType(contents, extensions::VIEW_TYPE_COMPONENT);
83 extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
84 contents);
dmazzoni94a4f882015-11-13 05:46:5285 web_view->LoadInitialURL(GURL(url));
86 web_view_ = web_view;
87
88 widget_ = new views::Widget();
89 views::Widget::InitParams params(
90 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
91 aura::Window* root_window = ash::Shell::GetPrimaryRootWindow();
92 params.parent = ash::Shell::GetContainer(
93 root_window, ash::kShellWindowId_SettingBubbleContainer);
94 params.delegate = this;
95 params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
96 params.bounds = gfx::Rect(0, 0, root_window->bounds().width(),
97 root_window->bounds().height());
98 widget_->Init(params);
estadeba7b9d72017-01-04 20:06:0699 SetShadowElevation(widget_->GetNativeWindow(), wm::ShadowElevation::MEDIUM);
dmazzoni94a4f882015-11-13 05:46:52100
oshimad5c972e2016-04-28 23:17:14101 display::Screen::GetScreen()->AddObserver(this);
dmazzoni94a4f882015-11-13 05:46:52102}
103
104ChromeVoxPanel::~ChromeVoxPanel() {
oshimad5c972e2016-04-28 23:17:14105 display::Screen::GetScreen()->RemoveObserver(this);
dmazzoni94a4f882015-11-13 05:46:52106}
107
108aura::Window* ChromeVoxPanel::GetRootWindow() {
109 return GetWidget()->GetNativeWindow()->GetRootWindow();
110}
111
112void ChromeVoxPanel::Close() {
113 widget_->Close();
114}
115
116void ChromeVoxPanel::DidFirstVisuallyNonEmptyPaint() {
117 widget_->Show();
dmazzoni39d6d4b2016-03-29 22:18:00118 UpdatePanelHeight();
119}
120
121void ChromeVoxPanel::UpdatePanelHeight() {
jamescook1cad77e92016-08-31 00:02:26122 ash::WmShelf* shelf =
sky5dbc91d52017-01-13 00:26:14123 ash::WmShelf::ForWindow(ash::WmWindow::Get(GetRootWindow()));
jamescook1cad77e92016-08-31 00:02:26124 if (!shelf->IsShelfInitialized())
dmazzoni39d6d4b2016-03-29 22:18:00125 return;
126
127 ash::ShelfLayoutManager* shelf_layout_manager = shelf->shelf_layout_manager();
128 if (shelf_layout_manager)
129 shelf_layout_manager->SetChromeVoxPanelHeight(kPanelHeight);
dmazzoni94a4f882015-11-13 05:46:52130}
131
132void ChromeVoxPanel::EnterFullscreen() {
dtseng8624c9d2016-03-04 16:15:56133 Focus();
dmazzonid47388d2016-03-31 16:03:51134 panel_fullscreen_ = true;
dmazzoni94a4f882015-11-13 05:46:52135 UpdateWidgetBounds();
136}
137
138void ChromeVoxPanel::ExitFullscreen() {
dmazzonid47388d2016-03-31 16:03:51139 widget_->Deactivate();
dmazzoni6915ba262016-02-11 23:47:44140 widget_->widget_delegate()->set_can_activate(false);
dmazzonid47388d2016-03-31 16:03:51141 panel_fullscreen_ = false;
dmazzoni94a4f882015-11-13 05:46:52142 UpdateWidgetBounds();
143}
144
145void ChromeVoxPanel::DisableSpokenFeedback() {
146 chromeos::AccessibilityManager::Get()->EnableSpokenFeedback(
jamescooka7f8dab2016-06-21 01:44:03147 false, ash::A11Y_NOTIFICATION_NONE);
dmazzoni94a4f882015-11-13 05:46:52148}
149
dtseng8624c9d2016-03-04 16:15:56150void ChromeVoxPanel::Focus() {
151 widget_->widget_delegate()->set_can_activate(true);
152 widget_->Activate();
153 web_view_->RequestFocus();
154}
155
dmazzoni94a4f882015-11-13 05:46:52156const views::Widget* ChromeVoxPanel::GetWidget() const {
157 return widget_;
158}
159
160views::Widget* ChromeVoxPanel::GetWidget() {
161 return widget_;
162}
163
164void ChromeVoxPanel::DeleteDelegate() {
165 delete this;
166}
167
168views::View* ChromeVoxPanel::GetContentsView() {
169 return web_view_;
170}
171
oshimad5c972e2016-04-28 23:17:14172void ChromeVoxPanel::OnDisplayMetricsChanged(const display::Display& display,
dmazzoni94a4f882015-11-13 05:46:52173 uint32_t changed_metrics) {
174 UpdateWidgetBounds();
175}
176
177void ChromeVoxPanel::UpdateWidgetBounds() {
178 gfx::Rect bounds(GetRootWindow()->bounds().size());
dmazzonid47388d2016-03-31 16:03:51179 if (!panel_fullscreen_)
dmazzoni94a4f882015-11-13 05:46:52180 bounds.set_height(kPanelHeight);
dmazzonid47388d2016-03-31 16:03:51181
182 // If we're in full-screen mode, give the panel a height of 0 unless
183 // it's active.
184 if (ash::GetRootWindowController(GetRootWindow())
185 ->GetWindowForFullscreenMode() &&
186 !widget_->IsActive()) {
187 bounds.set_height(0);
188 }
189
dmazzoni94a4f882015-11-13 05:46:52190 widget_->SetBounds(bounds);
191}