Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / ash / ash_keyboard_controller_proxy.cc
1 // Copyright (c) 2013 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 "chrome/browser/ui/ash/ash_keyboard_controller_proxy.h"
6
7 #include "ash/display/display_controller.h"
8 #include "ash/shell.h"
9 #include "chrome/browser/extensions/event_names.h"
10 #include "chrome/browser/extensions/extension_function_dispatcher.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/extension_system.h"
13 #include "chrome/browser/extensions/extension_web_contents_observer.h"
14 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/profiles/profile_manager.h"
17 #include "chrome/common/extensions/api/virtual_keyboard_private.h"
18 #include "chrome/common/extensions/extension_messages.h"
19 #include "content/public/browser/site_instance.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/browser/web_contents_view.h"
22 #include "extensions/browser/event_router.h"
23 #include "extensions/browser/view_type_utils.h"
24 #include "extensions/common/constants.h"
25 #include "ipc/ipc_message_macros.h"
26 #include "ui/aura/client/aura_constants.h"
27 #include "ui/aura/root_window.h"
28 #include "ui/aura/window.h"
29 #include "ui/base/ime/input_method.h"
30 #include "ui/base/ime/text_input_client.h"
31 #include "ui/compositor/scoped_layer_animation_settings.h"
32 #include "ui/keyboard/keyboard_controller.h"
33
34 namespace virtual_keyboard_private = extensions::api::virtual_keyboard_private;
35 typedef virtual_keyboard_private::OnTextInputBoxFocused::Context Context;
36
37 namespace {
38
39 const char* kVirtualKeyboardExtensionID = "mppnpdlheglhdfmldimlhpnegondlapf";
40
41 // The virtual keyboard show/hide animation duration.
42 const int kAnimationDurationMs = 200;
43
44 // The opacity of virtual keyboard container when show animation starts or
45 // hide animation finishes.
46 const float kAnimationStartOrAfterHideOpacity = 0.2f;
47
48 Context::Type TextInputTypeToGeneratedInputTypeEnum(ui::TextInputType type) {
49   switch (type) {
50     case ui::TEXT_INPUT_TYPE_NONE:
51       return Context::TYPE_NONE;
52     case ui::TEXT_INPUT_TYPE_PASSWORD:
53       return Context::TYPE_PASSWORD;
54     case ui::TEXT_INPUT_TYPE_EMAIL:
55       return Context::TYPE_EMAIL;
56     case ui::TEXT_INPUT_TYPE_NUMBER:
57       return Context::TYPE_NUMBER;
58     case ui::TEXT_INPUT_TYPE_TELEPHONE:
59       return Context::TYPE_TEL;
60     case ui::TEXT_INPUT_TYPE_URL:
61       return Context::TYPE_URL;
62     case ui::TEXT_INPUT_TYPE_DATE:
63       return Context::TYPE_DATE;
64     case ui::TEXT_INPUT_TYPE_TEXT:
65     case ui::TEXT_INPUT_TYPE_SEARCH:
66     case ui::TEXT_INPUT_TYPE_DATE_TIME:
67     case ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL:
68     case ui::TEXT_INPUT_TYPE_MONTH:
69     case ui::TEXT_INPUT_TYPE_TIME:
70     case ui::TEXT_INPUT_TYPE_WEEK:
71     case ui::TEXT_INPUT_TYPE_TEXT_AREA:
72     case ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE:
73     case ui::TEXT_INPUT_TYPE_DATE_TIME_FIELD:
74       return Context::TYPE_TEXT;
75   }
76   NOTREACHED();
77   return Context::TYPE_NONE;
78 }
79
80 }  // namespace
81
82 AshKeyboardControllerProxy::AshKeyboardControllerProxy()
83   : animation_window_(NULL) {}
84
85 AshKeyboardControllerProxy::~AshKeyboardControllerProxy() {}
86
87 void AshKeyboardControllerProxy::OnRequest(
88     const ExtensionHostMsg_Request_Params& params) {
89   extension_function_dispatcher_->Dispatch(
90       params, web_contents()->GetRenderViewHost());
91 }
92
93 content::BrowserContext* AshKeyboardControllerProxy::GetBrowserContext() {
94   return ProfileManager::GetActiveUserProfile();
95 }
96
97 ui::InputMethod* AshKeyboardControllerProxy::GetInputMethod() {
98   aura::Window* root_window = ash::Shell::GetInstance()->GetPrimaryRootWindow();
99   DCHECK(root_window);
100   return root_window->GetProperty(aura::client::kRootWindowInputMethodKey);
101 }
102
103 void AshKeyboardControllerProxy::RequestAudioInput(
104       content::WebContents* web_contents,
105       const content::MediaStreamRequest& request,
106       const content::MediaResponseCallback& callback) {
107   const extensions::Extension* extension = NULL;
108   GURL origin(request.security_origin);
109   if (origin.SchemeIs(extensions::kExtensionScheme)) {
110     ExtensionService* extensions_service =
111         extensions::ExtensionSystem::GetForBrowserContext(
112             GetBrowserContext())->extension_service();
113     extension = extensions_service->extensions()->GetByID(origin.host());
114     DCHECK(extension);
115   }
116
117   MediaCaptureDevicesDispatcher::GetInstance()->ProcessMediaAccessRequest(
118       web_contents, request, callback, extension);
119 }
120
121 void AshKeyboardControllerProxy::SetupWebContents(
122     content::WebContents* contents) {
123   extension_function_dispatcher_.reset(
124       new ExtensionFunctionDispatcher(GetBrowserContext(), this));
125   extensions::SetViewType(contents, extensions::VIEW_TYPE_VIRTUAL_KEYBOARD);
126   extensions::ExtensionWebContentsObserver::CreateForWebContents(contents);
127   Observe(contents);
128 }
129
130 extensions::WindowController*
131     AshKeyboardControllerProxy::GetExtensionWindowController() const {
132   // The keyboard doesn't have a window controller.
133   return NULL;
134 }
135
136 content::WebContents*
137     AshKeyboardControllerProxy::GetAssociatedWebContents() const {
138   return web_contents();
139 }
140
141 bool AshKeyboardControllerProxy::OnMessageReceived(
142     const IPC::Message& message) {
143   bool handled = true;
144   IPC_BEGIN_MESSAGE_MAP(AshKeyboardControllerProxy, message)
145     IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
146     IPC_MESSAGE_UNHANDLED(handled = false)
147   IPC_END_MESSAGE_MAP()
148   return handled;
149 }
150
151 void AshKeyboardControllerProxy::ShowKeyboardContainer(
152     aura::Window* container) {
153   // TODO(bshe): Implement logic to decide which root window should display
154   // virtual keyboard. http://crbug.com/303429
155   if (container->GetRootWindow() != ash::Shell::GetPrimaryRootWindow())
156     NOTIMPLEMENTED();
157
158   ui::LayerAnimator* container_animator = container->layer()->GetAnimator();
159   // If the container is not animating, makes sure the position and opacity
160   // are at begin states for animation.
161   if (!container_animator->is_animating()) {
162     gfx::Transform transform;
163     transform.Translate(0, GetKeyboardWindow()->bounds().height());
164     container->SetTransform(transform);
165     container->layer()->SetOpacity(kAnimationStartOrAfterHideOpacity);
166   }
167
168   container_animator->set_preemption_strategy(
169       ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
170
171   {
172     // Scope the following animation settings as we don't want to animate
173     // visibility change that triggered by a call to the base class function
174     // ShowKeyboardContainer with these settings. The container should become
175     // visible immediately.
176     ui::ScopedLayerAnimationSettings settings(container_animator);
177     settings.SetTweenType(gfx::Tween::EASE_IN);
178     settings.SetTransitionDuration(
179         base::TimeDelta::FromMilliseconds(kAnimationDurationMs));
180     container->SetTransform(gfx::Transform());
181     container->layer()->SetOpacity(1.0);
182   }
183
184   // TODO(bshe): Add animation observer and do the workspace resizing after
185   // animation finished.
186   KeyboardControllerProxy::ShowKeyboardContainer(container);
187   // GetTextInputClient may return NULL when keyboard-usability-experiment flag
188   // is set.
189   if (GetInputMethod()->GetTextInputClient()) {
190     gfx::Rect showing_area =
191         ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
192     GetInputMethod()->GetTextInputClient()->EnsureCaretInRect(showing_area);
193   }
194 }
195
196 void AshKeyboardControllerProxy::HideKeyboardContainer(
197     aura::Window* container) {
198   // The following animation settings should persist within this function scope.
199   // Otherwise, a call to base class function HideKeyboardContainer will hide
200   // the container immediately.
201   ui::LayerAnimator* container_animator = container->layer()->GetAnimator();
202   container_animator->AddObserver(this);
203   animation_window_ = container;
204   ui::ScopedLayerAnimationSettings settings(container_animator);
205   settings.SetTweenType(gfx::Tween::EASE_OUT);
206   settings.SetTransitionDuration(
207       base::TimeDelta::FromMilliseconds(kAnimationDurationMs));
208   gfx::Transform transform;
209   transform.Translate(0, GetKeyboardWindow()->bounds().height());
210   container->SetTransform(transform);
211   container->layer()->SetOpacity(kAnimationStartOrAfterHideOpacity);
212 }
213
214 void AshKeyboardControllerProxy::OnLayerAnimationEnded(
215     ui::LayerAnimationSequence* sequence) {
216   if (!animation_window_)
217     return;
218   ui::LayerAnimator* animator = animation_window_->layer()->GetAnimator();
219   if (!animator->is_animating()) {
220     KeyboardControllerProxy::HideKeyboardContainer(animation_window_);
221     animator->RemoveObserver(this);
222     animation_window_ = NULL;
223   }
224 };
225
226 void AshKeyboardControllerProxy::OnLayerAnimationAborted(
227     ui::LayerAnimationSequence* sequence) {
228   if (!animation_window_)
229     return;
230   animation_window_->layer()->GetAnimator()->RemoveObserver(this);
231   animation_window_ = NULL;
232 };
233
234 void AshKeyboardControllerProxy::SetUpdateInputType(ui::TextInputType type) {
235   // TODO(bshe): Need to check the affected window's profile once multi-profile
236   // is supported.
237   content::BrowserContext* context = GetBrowserContext();
238   extensions::EventRouter* router =
239       extensions::ExtensionSystem::GetForBrowserContext(context)->
240       event_router();
241
242   if (!router->HasEventListener(
243           virtual_keyboard_private::OnTextInputBoxFocused::kEventName)) {
244     return;
245   }
246
247   scoped_ptr<base::ListValue> event_args(new base::ListValue());
248   scoped_ptr<base::DictionaryValue> input_context(new base::DictionaryValue());
249   input_context->SetString("type",
250       Context::ToString(TextInputTypeToGeneratedInputTypeEnum(type)));
251   event_args->Append(input_context.release());
252
253   scoped_ptr<extensions::Event> event(new extensions::Event(
254       virtual_keyboard_private::OnTextInputBoxFocused::kEventName,
255       event_args.Pass()));
256   event->restrict_to_browser_context = context;
257   router->DispatchEventToExtension(kVirtualKeyboardExtensionID, event.Pass());
258 }