// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/ui/ash/chrome_keyboard_ui.h" #include "ash/shell.h" #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h" #include "chrome/browser/media/media_capture_devices_dispatcher.h" #include "content/public/browser/host_zoom_map.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/site_instance.h" #include "content/public/browser/web_contents.h" #include "extensions/browser/event_router.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/view_type_utils.h" #include "extensions/common/api/virtual_keyboard_private.h" #include "extensions/common/constants.h" #include "extensions/common/extension_messages.h" #include "ipc/ipc_message_macros.h" #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_tree_host.h" #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/keyboard/keyboard_controller.h" #include "ui/keyboard/keyboard_controller_observer.h" namespace virtual_keyboard_private = extensions::api::virtual_keyboard_private; typedef virtual_keyboard_private::OnTextInputBoxFocused::Context Context; namespace { const char* kVirtualKeyboardExtensionID = "mppnpdlheglhdfmldimlhpnegondlapf"; virtual_keyboard_private::OnTextInputBoxFocusedType TextInputTypeToGeneratedInputTypeEnum(ui::TextInputType type) { switch (type) { case ui::TEXT_INPUT_TYPE_NONE: return virtual_keyboard_private::ON_TEXT_INPUT_BOX_FOCUSED_TYPE_NONE; case ui::TEXT_INPUT_TYPE_PASSWORD: return virtual_keyboard_private::ON_TEXT_INPUT_BOX_FOCUSED_TYPE_PASSWORD; case ui::TEXT_INPUT_TYPE_EMAIL: return virtual_keyboard_private::ON_TEXT_INPUT_BOX_FOCUSED_TYPE_EMAIL; case ui::TEXT_INPUT_TYPE_NUMBER: return virtual_keyboard_private::ON_TEXT_INPUT_BOX_FOCUSED_TYPE_NUMBER; case ui::TEXT_INPUT_TYPE_TELEPHONE: return virtual_keyboard_private::ON_TEXT_INPUT_BOX_FOCUSED_TYPE_TEL; case ui::TEXT_INPUT_TYPE_URL: return virtual_keyboard_private::ON_TEXT_INPUT_BOX_FOCUSED_TYPE_URL; case ui::TEXT_INPUT_TYPE_DATE: return virtual_keyboard_private::ON_TEXT_INPUT_BOX_FOCUSED_TYPE_DATE; case ui::TEXT_INPUT_TYPE_TEXT: case ui::TEXT_INPUT_TYPE_SEARCH: case ui::TEXT_INPUT_TYPE_DATE_TIME: case ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL: case ui::TEXT_INPUT_TYPE_MONTH: case ui::TEXT_INPUT_TYPE_TIME: case ui::TEXT_INPUT_TYPE_WEEK: case ui::TEXT_INPUT_TYPE_TEXT_AREA: case ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE: case ui::TEXT_INPUT_TYPE_DATE_TIME_FIELD: return virtual_keyboard_private::ON_TEXT_INPUT_BOX_FOCUSED_TYPE_TEXT; } NOTREACHED(); return virtual_keyboard_private::ON_TEXT_INPUT_BOX_FOCUSED_TYPE_NONE; } class AshKeyboardControllerObserver : public keyboard::KeyboardControllerObserver { public: explicit AshKeyboardControllerObserver(content::BrowserContext* context) : context_(context) {} ~AshKeyboardControllerObserver() override {} // KeyboardControllerObserver overrides: void OnKeyboardBoundsChanging(const gfx::Rect& bounds) override { extensions::EventRouter* router = extensions::EventRouter::Get(context_); if (!router->HasEventListener( virtual_keyboard_private::OnBoundsChanged::kEventName)) { return; } scoped_ptr event_args(new base::ListValue()); scoped_ptr new_bounds(new base::DictionaryValue()); new_bounds->SetInteger("left", bounds.x()); new_bounds->SetInteger("top", bounds.y()); new_bounds->SetInteger("width", bounds.width()); new_bounds->SetInteger("height", bounds.height()); event_args->Append(new_bounds.release()); scoped_ptr event(new extensions::Event( extensions::events::VIRTUAL_KEYBOARD_PRIVATE_ON_BOUNDS_CHANGED, virtual_keyboard_private::OnBoundsChanged::kEventName, event_args.Pass())); event->restrict_to_browser_context = context_; router->BroadcastEvent(event.Pass()); } private: content::BrowserContext* context_; DISALLOW_COPY_AND_ASSIGN(AshKeyboardControllerObserver); }; } // namespace ChromeKeyboardUI::ChromeKeyboardUI(content::BrowserContext* context) : keyboard::KeyboardUIContent(context) {} ChromeKeyboardUI::~ChromeKeyboardUI() { DCHECK(!keyboard_controller()); } ui::InputMethod* ChromeKeyboardUI::GetInputMethod() { aura::Window* root_window = ash::Shell::GetTargetRootWindow(); DCHECK(root_window); return root_window->GetHost()->GetInputMethod(); } void ChromeKeyboardUI::RequestAudioInput( content::WebContents* web_contents, const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback) { const extensions::Extension* extension = NULL; GURL origin(request.security_origin); if (origin.SchemeIs(extensions::kExtensionScheme)) { const extensions::ExtensionRegistry* registry = extensions::ExtensionRegistry::Get(browser_context()); extension = registry->enabled_extensions().GetByID(origin.host()); DCHECK(extension); } MediaCaptureDevicesDispatcher::GetInstance()->ProcessMediaAccessRequest( web_contents, request, callback, extension); } void ChromeKeyboardUI::SetupWebContents(content::WebContents* contents) { extensions::SetViewType(contents, extensions::VIEW_TYPE_VIRTUAL_KEYBOARD); extensions::ChromeExtensionWebContentsObserver::CreateForWebContents( contents); Observe(contents); } void ChromeKeyboardUI::SetController(keyboard::KeyboardController* controller) { // During KeyboardController destruction, controller can be set to null. if (!controller) { DCHECK(keyboard_controller()); keyboard_controller()->RemoveObserver(observer_.get()); KeyboardUIContent::SetController(nullptr); return; } KeyboardUIContent::SetController(controller); observer_.reset(new AshKeyboardControllerObserver(browser_context())); keyboard_controller()->AddObserver(observer_.get()); } void ChromeKeyboardUI::RenderViewCreated( content::RenderViewHost* render_view_host) { content::HostZoomMap* zoom_map = content::HostZoomMap::GetDefaultForBrowserContext(browser_context()); DCHECK(zoom_map); int render_process_id = render_view_host->GetProcess()->GetID(); int render_view_id = render_view_host->GetRoutingID(); zoom_map->SetTemporaryZoomLevel(render_process_id, render_view_id, 0); } void ChromeKeyboardUI::ShowKeyboardContainer(aura::Window* container) { // TODO(bshe): Implement logic to decide which root window should display // virtual keyboard. http://crbug.com/303429 if (container->GetRootWindow() != ash::Shell::GetPrimaryRootWindow()) NOTIMPLEMENTED(); KeyboardUIContent::ShowKeyboardContainer(container); } void ChromeKeyboardUI::SetUpdateInputType(ui::TextInputType type) { // TODO(bshe): Need to check the affected window's profile once multi-profile // is supported. extensions::EventRouter* router = extensions::EventRouter::Get(browser_context()); if (!router->HasEventListener( virtual_keyboard_private::OnTextInputBoxFocused::kEventName)) { return; } scoped_ptr event_args(new base::ListValue()); scoped_ptr input_context(new base::DictionaryValue()); input_context->SetString("type", virtual_keyboard_private::ToString( TextInputTypeToGeneratedInputTypeEnum(type))); event_args->Append(input_context.release()); scoped_ptr event(new extensions::Event( extensions::events::VIRTUAL_KEYBOARD_PRIVATE_ON_TEXT_INPUT_BOX_FOCUSED, virtual_keyboard_private::OnTextInputBoxFocused::kEventName, event_args.Pass())); event->restrict_to_browser_context = browser_context(); router->DispatchEventToExtension(kVirtualKeyboardExtensionID, event.Pass()); }