Home | History | Annotate | Download | only in keyboard
      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 "ui/keyboard/keyboard_controller_proxy.h"
      6 
      7 #include "base/command_line.h"
      8 #include "base/values.h"
      9 #include "content/public/browser/site_instance.h"
     10 #include "content/public/browser/web_contents.h"
     11 #include "content/public/browser/web_contents.h"
     12 #include "content/public/browser/web_contents_delegate.h"
     13 #include "content/public/browser/web_contents_observer.h"
     14 #include "content/public/browser/web_ui.h"
     15 #include "content/public/common/bindings_policy.h"
     16 #include "ui/aura/layout_manager.h"
     17 #include "ui/aura/window.h"
     18 #include "ui/base/ime/input_method.h"
     19 #include "ui/base/ime/text_input_client.h"
     20 #include "ui/keyboard/keyboard_constants.h"
     21 #include "ui/keyboard/keyboard_switches.h"
     22 #include "ui/keyboard/keyboard_util.h"
     23 #include "ui/wm/core/shadow.h"
     24 
     25 namespace {
     26 
     27 // The WebContentsDelegate for the keyboard.
     28 // The delegate deletes itself when the keyboard is destroyed.
     29 class KeyboardContentsDelegate : public content::WebContentsDelegate,
     30                                  public content::WebContentsObserver {
     31  public:
     32   KeyboardContentsDelegate(keyboard::KeyboardControllerProxy* proxy)
     33       : proxy_(proxy) {}
     34   virtual ~KeyboardContentsDelegate() {}
     35 
     36  private:
     37   // Overridden from content::WebContentsDelegate:
     38   virtual content::WebContents* OpenURLFromTab(
     39       content::WebContents* source,
     40       const content::OpenURLParams& params) OVERRIDE {
     41     source->GetController().LoadURL(
     42         params.url, params.referrer, params.transition, params.extra_headers);
     43     Observe(source);
     44     return source;
     45   }
     46 
     47   virtual bool IsPopupOrPanel(
     48       const content::WebContents* source) const OVERRIDE {
     49     return true;
     50   }
     51 
     52   virtual void MoveContents(content::WebContents* source,
     53                             const gfx::Rect& pos) OVERRIDE {
     54     aura::Window* keyboard = proxy_->GetKeyboardWindow();
     55     // keyboard window must have been added to keyboard container window at this
     56     // point. Otherwise, wrong keyboard bounds is used and may cause problem as
     57     // described in crbug.com/367788.
     58     DCHECK(keyboard->parent());
     59     gfx::Rect bounds = keyboard->bounds();
     60     int new_height = pos.height();
     61     bounds.set_y(bounds.y() + bounds.height() - new_height);
     62     bounds.set_height(new_height);
     63     keyboard->SetBounds(bounds);
     64   }
     65 
     66   // Overridden from content::WebContentsDelegate:
     67   virtual void RequestMediaAccessPermission(content::WebContents* web_contents,
     68       const content::MediaStreamRequest& request,
     69       const content::MediaResponseCallback& callback) OVERRIDE {
     70     proxy_->RequestAudioInput(web_contents, request, callback);
     71   }
     72 
     73   // Overridden from content::WebContentsObserver:
     74   virtual void WebContentsDestroyed() OVERRIDE {
     75     delete this;
     76   }
     77 
     78   keyboard::KeyboardControllerProxy* proxy_;
     79 
     80   DISALLOW_COPY_AND_ASSIGN(KeyboardContentsDelegate);
     81 };
     82 
     83 }  // namespace
     84 
     85 namespace keyboard {
     86 
     87 KeyboardControllerProxy::KeyboardControllerProxy()
     88     : default_url_(kKeyboardURL) {
     89 }
     90 
     91 KeyboardControllerProxy::~KeyboardControllerProxy() {
     92 }
     93 
     94 const GURL& KeyboardControllerProxy::GetVirtualKeyboardUrl() {
     95   if (keyboard::IsInputViewEnabled()) {
     96     const GURL& override_url = GetOverrideContentUrl();
     97     return override_url.is_valid() ? override_url : default_url_;
     98   } else {
     99     return default_url_;
    100   }
    101 }
    102 
    103 void KeyboardControllerProxy::LoadContents(const GURL& url) {
    104   if (keyboard_contents_) {
    105     content::OpenURLParams params(
    106         url,
    107         content::Referrer(),
    108         SINGLETON_TAB,
    109         ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
    110         false);
    111     keyboard_contents_->OpenURL(params);
    112   }
    113 }
    114 
    115 aura::Window* KeyboardControllerProxy::GetKeyboardWindow() {
    116   if (!keyboard_contents_) {
    117     content::BrowserContext* context = GetBrowserContext();
    118     keyboard_contents_.reset(content::WebContents::Create(
    119         content::WebContents::CreateParams(context,
    120             content::SiteInstance::CreateForURL(context,
    121                                                 GetVirtualKeyboardUrl()))));
    122     keyboard_contents_->SetDelegate(new KeyboardContentsDelegate(this));
    123     SetupWebContents(keyboard_contents_.get());
    124     LoadContents(GetVirtualKeyboardUrl());
    125     keyboard_contents_->GetNativeView()->AddObserver(this);
    126   }
    127 
    128   return keyboard_contents_->GetNativeView();
    129 }
    130 
    131 bool KeyboardControllerProxy::HasKeyboardWindow() const {
    132   return keyboard_contents_;
    133 }
    134 
    135 void KeyboardControllerProxy::ShowKeyboardContainer(aura::Window* container) {
    136   GetKeyboardWindow()->Show();
    137   container->Show();
    138 }
    139 
    140 void KeyboardControllerProxy::HideKeyboardContainer(aura::Window* container) {
    141   container->Hide();
    142   GetKeyboardWindow()->Hide();
    143 }
    144 
    145 void KeyboardControllerProxy::SetUpdateInputType(ui::TextInputType type) {
    146 }
    147 
    148 void KeyboardControllerProxy::EnsureCaretInWorkArea() {
    149   if (GetInputMethod()->GetTextInputClient()) {
    150     aura::Window* keyboard_window = GetKeyboardWindow();
    151     aura::Window* root_window = keyboard_window->GetRootWindow();
    152     gfx::Rect available_bounds = root_window->bounds();
    153     gfx::Rect keyboard_bounds = keyboard_window->bounds();
    154     available_bounds.set_height(available_bounds.height() -
    155         keyboard_bounds.height());
    156     GetInputMethod()->GetTextInputClient()->EnsureCaretInRect(available_bounds);
    157   }
    158 }
    159 
    160 void KeyboardControllerProxy::LoadSystemKeyboard() {
    161   DCHECK(keyboard_contents_);
    162   if (keyboard_contents_->GetURL() != default_url_) {
    163     // TODO(bshe): The height of system virtual keyboard and IME virtual
    164     // keyboard may different. The height needs to be restored too.
    165     LoadContents(default_url_);
    166   }
    167 }
    168 
    169 void KeyboardControllerProxy::ReloadKeyboardIfNeeded() {
    170   DCHECK(keyboard_contents_);
    171   if (keyboard_contents_->GetURL() != GetVirtualKeyboardUrl()) {
    172     if (keyboard_contents_->GetURL().GetOrigin() !=
    173         GetVirtualKeyboardUrl().GetOrigin()) {
    174       // Sets keyboard window height to 0 before navigate to a keyboard in a
    175       // different extension. This keeps the UX the same as Android.
    176       gfx::Rect bounds = GetKeyboardWindow()->bounds();
    177       bounds.set_y(bounds.y() + bounds.height());
    178       bounds.set_height(0);
    179       GetKeyboardWindow()->SetBounds(bounds);
    180     }
    181     LoadContents(GetVirtualKeyboardUrl());
    182   }
    183 }
    184 
    185 void KeyboardControllerProxy::SetupWebContents(content::WebContents* contents) {
    186 }
    187 
    188 void KeyboardControllerProxy::OnWindowBoundsChanged(
    189     aura::Window* window,
    190     const gfx::Rect& old_bounds,
    191     const gfx::Rect& new_bounds) {
    192   if (!shadow_) {
    193     shadow_.reset(new wm::Shadow());
    194     shadow_->Init(wm::Shadow::STYLE_ACTIVE);
    195     shadow_->layer()->SetVisible(true);
    196     DCHECK(keyboard_contents_->GetNativeView()->parent());
    197     keyboard_contents_->GetNativeView()->parent()->layer()->Add(
    198         shadow_->layer());
    199   }
    200 
    201   shadow_->SetContentBounds(new_bounds);
    202 }
    203 
    204 void KeyboardControllerProxy::OnWindowDestroyed(aura::Window* window) {
    205   window->RemoveObserver(this);
    206 }
    207 
    208 }  // namespace keyboard
    209