Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / chromeos / login / webui_login_view.cc
blob95d87eb7ad5968c11db52e8078f368b09a9ba777
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
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/login/webui_login_view.h"
7 #include "ash/shell.h"
8 #include "ash/system/tray/system_tray.h"
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/debug/trace_event.h"
12 #include "base/i18n/rtl.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/values.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/chromeos/accessibility/accessibility_util.h"
17 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
18 #include "chrome/browser/chromeos/login/proxy_settings_dialog.h"
19 #include "chrome/browser/chromeos/login/webui_login_display.h"
20 #include "chrome/browser/chromeos/profiles/profile_helper.h"
21 #include "chrome/browser/extensions/extension_web_contents_observer.h"
22 #include "chrome/browser/media/media_stream_infobar_delegate.h"
23 #include "chrome/browser/password_manager/password_manager.h"
24 #include "chrome/browser/password_manager/password_manager_delegate_impl.h"
25 #include "chrome/browser/renderer_preferences_util.h"
26 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
27 #include "chrome/common/render_messages.h"
28 #include "chromeos/dbus/dbus_thread_manager.h"
29 #include "chromeos/dbus/session_manager_client.h"
30 #include "chromeos/network/network_state.h"
31 #include "chromeos/network/network_state_handler.h"
32 #include "components/web_modal/web_contents_modal_dialog_manager.h"
33 #include "content/public/browser/notification_service.h"
34 #include "content/public/browser/render_view_host.h"
35 #include "content/public/browser/render_widget_host_view.h"
36 #include "content/public/browser/web_contents.h"
37 #include "content/public/browser/web_contents_view.h"
38 #include "content/public/browser/web_ui.h"
39 #include "ui/gfx/rect.h"
40 #include "ui/gfx/size.h"
41 #include "ui/views/controls/webview/webview.h"
42 #include "ui/views/widget/widget.h"
44 using content::NativeWebKeyboardEvent;
45 using content::RenderViewHost;
46 using content::WebContents;
47 using web_modal::WebContentsModalDialogManager;
49 namespace {
51 // These strings must be kept in sync with handleAccelerator()
52 // in display_manager.js.
53 const char kAccelNameCancel[] = "cancel";
54 const char kAccelNameEnrollment[] = "enrollment";
55 const char kAccelNameKioskEnable[] = "kiosk_enable";
56 const char kAccelNameVersion[] = "version";
57 const char kAccelNameReset[] = "reset";
58 const char kAccelFocusPrev[] = "focus_prev";
59 const char kAccelFocusNext[] = "focus_next";
60 const char kAccelNameDeviceRequisition[] = "device_requisition";
61 const char kAccelNameDeviceRequisitionRemora[] = "device_requisition_remora";
62 const char kAccelNameAppLaunchBailout[] = "app_launch_bailout";
64 // A class to change arrow key traversal behavior when it's alive.
65 class ScopedArrowKeyTraversal {
66 public:
67 explicit ScopedArrowKeyTraversal(bool new_arrow_key_tranversal_enabled)
68 : previous_arrow_key_traversal_enabled_(
69 views::FocusManager::arrow_key_traversal_enabled()) {
70 views::FocusManager::set_arrow_key_traversal_enabled(
71 new_arrow_key_tranversal_enabled);
73 ~ScopedArrowKeyTraversal() {
74 views::FocusManager::set_arrow_key_traversal_enabled(
75 previous_arrow_key_traversal_enabled_);
78 private:
79 const bool previous_arrow_key_traversal_enabled_;
80 DISALLOW_COPY_AND_ASSIGN(ScopedArrowKeyTraversal);
83 } // namespace
85 namespace chromeos {
87 // static
88 const char WebUILoginView::kViewClassName[] =
89 "browser/chromeos/login/WebUILoginView";
91 // WebUILoginView public: ------------------------------------------------------
93 WebUILoginView::WebUILoginView()
94 : webui_login_(NULL),
95 is_hidden_(false),
96 webui_visible_(false),
97 should_emit_login_prompt_visible_(true),
98 forward_keyboard_event_(true) {
99 registrar_.Add(this,
100 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
101 content::NotificationService::AllSources());
102 registrar_.Add(this,
103 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN,
104 content::NotificationService::AllSources());
106 accel_map_[ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)] =
107 kAccelNameCancel;
108 accel_map_[ui::Accelerator(ui::VKEY_E,
109 ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)] =
110 kAccelNameEnrollment;
111 accel_map_[ui::Accelerator(ui::VKEY_K,
112 ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)] =
113 kAccelNameKioskEnable;
114 accel_map_[ui::Accelerator(ui::VKEY_V, ui::EF_ALT_DOWN)] =
115 kAccelNameVersion;
116 accel_map_[ui::Accelerator(ui::VKEY_R,
117 ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN)] =
118 kAccelNameReset;
120 accel_map_[ui::Accelerator(ui::VKEY_LEFT, ui::EF_NONE)] =
121 kAccelFocusPrev;
122 accel_map_[ui::Accelerator(ui::VKEY_RIGHT, ui::EF_NONE)] =
123 kAccelFocusNext;
125 // Use KEY_RELEASED because Gaia consumes KEY_PRESSED for up/down key.
126 ui::Accelerator key_up(ui::VKEY_UP, ui::EF_NONE);
127 key_up.set_type(ui::ET_KEY_RELEASED);
128 ui::Accelerator key_down(ui::VKEY_DOWN, ui::EF_NONE);
129 key_down.set_type(ui::ET_KEY_RELEASED);
130 accel_map_[key_up] = kAccelFocusPrev;
131 accel_map_[key_down] = kAccelFocusNext;
133 accel_map_[ui::Accelerator(
134 ui::VKEY_D, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN)] =
135 kAccelNameDeviceRequisition;
136 accel_map_[
137 ui::Accelerator(ui::VKEY_H, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)] =
138 kAccelNameDeviceRequisitionRemora;
140 accel_map_[ui::Accelerator(ui::VKEY_S,
141 ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)] =
142 kAccelNameAppLaunchBailout;
144 for (AccelMap::iterator i(accel_map_.begin()); i != accel_map_.end(); ++i)
145 AddAccelerator(i->first);
148 WebUILoginView::~WebUILoginView() {
149 FOR_EACH_OBSERVER(web_modal::ModalDialogHostObserver,
150 observer_list_,
151 OnHostDestroying());
153 if (ash::Shell::GetInstance()->HasPrimaryStatusArea()) {
154 ash::Shell::GetInstance()->GetPrimarySystemTray()->
155 SetNextFocusableView(NULL);
159 void WebUILoginView::Init() {
160 Profile* signin_profile = ProfileHelper::GetSigninProfile();
161 auth_extension_.reset(new ScopedGaiaAuthExtension(signin_profile));
162 webui_login_ = new views::WebView(signin_profile);
163 webui_login_->set_allow_accelerators(true);
164 AddChildView(webui_login_);
166 WebContents* web_contents = webui_login_->GetWebContents();
168 // Create the password manager that is needed for the proxy.
169 PasswordManagerDelegateImpl::CreateForWebContents(web_contents);
170 PasswordManager::CreateForWebContentsAndDelegate(
171 web_contents, PasswordManagerDelegateImpl::FromWebContents(web_contents));
173 // LoginHandlerViews uses a constrained window for the password manager view.
174 WebContentsModalDialogManager::CreateForWebContents(web_contents);
175 WebContentsModalDialogManager::FromWebContents(web_contents)->
176 SetDelegate(this);
178 web_contents->SetDelegate(this);
179 extensions::ExtensionWebContentsObserver::CreateForWebContents(web_contents);
180 WebContentsObserver::Observe(web_contents);
181 renderer_preferences_util::UpdateFromSystemSettings(
182 web_contents->GetMutableRendererPrefs(),
183 signin_profile);
186 const char* WebUILoginView::GetClassName() const {
187 return kViewClassName;
190 web_modal::WebContentsModalDialogHost*
191 WebUILoginView::GetWebContentsModalDialogHost() {
192 return this;
195 gfx::NativeView WebUILoginView::GetHostView() const {
196 return GetWidget()->GetNativeView();
199 gfx::Point WebUILoginView::GetDialogPosition(const gfx::Size& size) {
200 // Center the widget.
201 gfx::Size widget_size = GetWidget()->GetWindowBoundsInScreen().size();
202 return gfx::Point(widget_size.width() / 2 - size.width() / 2,
203 widget_size.height() / 2 - size.height() / 2);
206 gfx::Size WebUILoginView::GetMaximumDialogSize() {
207 return GetWidget()->GetWindowBoundsInScreen().size();
210 void WebUILoginView::AddObserver(
211 web_modal::ModalDialogHostObserver* observer) {
212 if (observer && !observer_list_.HasObserver(observer))
213 observer_list_.AddObserver(observer);
216 void WebUILoginView::RemoveObserver(
217 web_modal::ModalDialogHostObserver* observer) {
218 observer_list_.RemoveObserver(observer);
221 bool WebUILoginView::AcceleratorPressed(
222 const ui::Accelerator& accelerator) {
223 AccelMap::const_iterator entry = accel_map_.find(accelerator);
224 if (entry == accel_map_.end())
225 return false;
227 if (!webui_login_)
228 return true;
230 content::WebUI* web_ui = GetWebUI();
231 if (web_ui) {
232 base::StringValue accel_name(entry->second);
233 web_ui->CallJavascriptFunction("cr.ui.Oobe.handleAccelerator",
234 accel_name);
237 return true;
240 gfx::NativeWindow WebUILoginView::GetNativeWindow() const {
241 return GetWidget()->GetNativeWindow();
244 void WebUILoginView::LoadURL(const GURL & url) {
245 webui_login_->LoadInitialURL(url);
246 webui_login_->RequestFocus();
248 // TODO(nkostylev): Use WebContentsObserver::RenderViewCreated to track
249 // when RenderView is created.
250 // Use a background with transparency to trigger transparency in Webkit.
251 SkBitmap background;
252 background.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
253 background.allocPixels();
254 background.eraseARGB(0x00, 0x00, 0x00, 0x00);
255 content::RenderViewHost* host = GetWebContents()->GetRenderViewHost();
256 host->GetView()->SetBackground(background);
259 content::WebUI* WebUILoginView::GetWebUI() {
260 return webui_login_->web_contents()->GetWebUI();
263 content::WebContents* WebUILoginView::GetWebContents() {
264 return webui_login_->web_contents();
267 void WebUILoginView::OpenProxySettings() {
268 const NetworkState* network =
269 NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
270 if (!network) {
271 LOG(ERROR) << "No default network found!";
272 return;
274 ProxySettingsDialog* dialog =
275 new ProxySettingsDialog(*network, NULL, GetNativeWindow());
276 dialog->Show();
279 void WebUILoginView::OnPostponedShow() {
280 set_is_hidden(false);
281 OnLoginPromptVisible();
284 void WebUILoginView::SetStatusAreaVisible(bool visible) {
285 if (ash::Shell::GetInstance()->HasPrimaryStatusArea()) {
286 ash::SystemTray* tray = ash::Shell::GetInstance()->GetPrimarySystemTray();
287 if (visible) {
288 // Tray may have been initialized being hidden.
289 tray->SetVisible(visible);
290 tray->GetWidget()->Show();
291 } else {
292 tray->GetWidget()->Hide();
297 void WebUILoginView::SetUIEnabled(bool enabled) {
298 forward_keyboard_event_ = enabled;
299 ash::Shell::GetInstance()->GetPrimarySystemTray()->SetEnabled(enabled);
302 // WebUILoginView protected: ---------------------------------------------------
304 void WebUILoginView::Layout() {
305 DCHECK(webui_login_);
306 webui_login_->SetBoundsRect(bounds());
308 FOR_EACH_OBSERVER(web_modal::ModalDialogHostObserver,
309 observer_list_,
310 OnPositionRequiresUpdate());
313 void WebUILoginView::OnLocaleChanged() {
316 void WebUILoginView::ChildPreferredSizeChanged(View* child) {
317 Layout();
318 SchedulePaint();
321 void WebUILoginView::AboutToRequestFocusFromTabTraversal(bool reverse) {
322 // Return the focus to the web contents.
323 webui_login_->web_contents()->FocusThroughTabTraversal(reverse);
324 GetWidget()->Activate();
325 webui_login_->web_contents()->GetView()->Focus();
328 void WebUILoginView::Observe(int type,
329 const content::NotificationSource& source,
330 const content::NotificationDetails& details) {
331 switch (type) {
332 case chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE:
333 case chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN: {
334 OnLoginPromptVisible();
335 registrar_.RemoveAll();
336 break;
338 default:
339 NOTREACHED() << "Unexpected notification " << type;
343 // WebUILoginView private: -----------------------------------------------------
345 bool WebUILoginView::HandleContextMenu(
346 const content::ContextMenuParams& params) {
347 // Do not show the context menu.
348 #ifndef NDEBUG
349 return false;
350 #else
351 return true;
352 #endif
355 void WebUILoginView::HandleKeyboardEvent(content::WebContents* source,
356 const NativeWebKeyboardEvent& event) {
357 if (forward_keyboard_event_) {
358 // Disable arrow key traversal because arrow keys are handled via
359 // accelerator when this view has focus.
360 ScopedArrowKeyTraversal arrow_key_traversal(false);
362 unhandled_keyboard_event_handler_.HandleKeyboardEvent(event,
363 GetFocusManager());
366 // Make sure error bubble is cleared on keyboard event. This is needed
367 // when the focus is inside an iframe. Only clear on KeyDown to prevent hiding
368 // an immediate authentication error (See crbug.com/103643).
369 if (event.type == blink::WebInputEvent::KeyDown) {
370 content::WebUI* web_ui = GetWebUI();
371 if (web_ui)
372 web_ui->CallJavascriptFunction("cr.ui.Oobe.clearErrors");
376 bool WebUILoginView::IsPopupOrPanel(const WebContents* source) const {
377 return true;
380 bool WebUILoginView::TakeFocus(content::WebContents* source, bool reverse) {
381 // In case of blocked UI (ex.: sign in is in progress)
382 // we should not process focus change events.
383 if (!forward_keyboard_event_)
384 return false;
386 ash::SystemTray* tray = ash::Shell::GetInstance()->GetPrimarySystemTray();
387 if (tray && tray->GetWidget()->IsVisible()) {
388 tray->SetNextFocusableView(this);
389 ash::Shell::GetInstance()->RotateFocus(reverse ? ash::Shell::BACKWARD :
390 ash::Shell::FORWARD);
393 return true;
396 void WebUILoginView::RequestMediaAccessPermission(
397 WebContents* web_contents,
398 const content::MediaStreamRequest& request,
399 const content::MediaResponseCallback& callback) {
400 if (MediaStreamInfoBarDelegate::Create(web_contents, request, callback))
401 NOTREACHED() << "Media stream not allowed for WebUI";
404 void WebUILoginView::DidFailProvisionalLoad(
405 int64 frame_id,
406 const base::string16& frame_unique_name,
407 bool is_main_frame,
408 const GURL& validated_url,
409 int error_code,
410 const base::string16& error_description,
411 content::RenderViewHost* render_view_host) {
412 if (frame_unique_name != base::UTF8ToUTF16("gaia-frame"))
413 return;
415 base::FundamentalValue error_value(-error_code);
416 GetWebUI()->CallJavascriptFunction("login.GaiaSigninScreen.onFrameError",
417 error_value);
420 void WebUILoginView::OnLoginPromptVisible() {
421 // If we're hidden than will generate this signal once we're shown.
422 if (is_hidden_ || webui_visible_) {
423 LOG(WARNING) << "Login WebUI >> not emitting signal, hidden: "
424 << is_hidden_;
425 return;
427 TRACE_EVENT0("chromeos", "WebUILoginView::OnLoginPromoptVisible");
428 if (should_emit_login_prompt_visible_) {
429 LOG(WARNING) << "Login WebUI >> login-prompt-visible";
430 chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->
431 EmitLoginPromptVisible();
434 webui_visible_ = true;
437 void WebUILoginView::ReturnFocus(bool reverse) {
438 // Return the focus to the web contents.
439 webui_login_->web_contents()->FocusThroughTabTraversal(reverse);
440 GetWidget()->Activate();
443 } // namespace chromeos