| Index: ui/keyboard/content/keyboard_ui_content.cc
|
| diff --git a/ui/keyboard/content/keyboard_ui_content.cc b/ui/keyboard/content/keyboard_ui_content.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..010abde98003e88e38fa79fea0f57081605a2f81
|
| --- /dev/null
|
| +++ b/ui/keyboard/content/keyboard_ui_content.cc
|
| @@ -0,0 +1,321 @@
|
| +// 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 "ui/keyboard/content/keyboard_ui_content.h"
|
| +
|
| +#include "base/command_line.h"
|
| +#include "base/values.h"
|
| +#include "content/public/browser/render_widget_host.h"
|
| +#include "content/public/browser/render_widget_host_iterator.h"
|
| +#include "content/public/browser/render_widget_host_view.h"
|
| +#include "content/public/browser/site_instance.h"
|
| +#include "content/public/browser/web_contents.h"
|
| +#include "content/public/browser/web_contents.h"
|
| +#include "content/public/browser/web_contents_delegate.h"
|
| +#include "content/public/browser/web_contents_observer.h"
|
| +#include "content/public/browser/web_ui.h"
|
| +#include "content/public/common/bindings_policy.h"
|
| +#include "ui/aura/layout_manager.h"
|
| +#include "ui/aura/window.h"
|
| +#include "ui/base/ime/input_method.h"
|
| +#include "ui/base/ime/text_input_client.h"
|
| +#include "ui/keyboard/content/keyboard_constants.h"
|
| +#include "ui/keyboard/keyboard_controller.h"
|
| +#include "ui/keyboard/keyboard_switches.h"
|
| +#include "ui/keyboard/keyboard_util.h"
|
| +#include "ui/wm/core/shadow.h"
|
| +
|
| +namespace {
|
| +
|
| +// The WebContentsDelegate for the keyboard.
|
| +// The delegate deletes itself when the keyboard is destroyed.
|
| +class KeyboardContentsDelegate : public content::WebContentsDelegate,
|
| + public content::WebContentsObserver {
|
| + public:
|
| + explicit KeyboardContentsDelegate(keyboard::KeyboardUIContent* ui)
|
| + : ui_(ui) {}
|
| + ~KeyboardContentsDelegate() override {}
|
| +
|
| + private:
|
| + // Overridden from content::WebContentsDelegate:
|
| + content::WebContents* OpenURLFromTab(
|
| + content::WebContents* source,
|
| + const content::OpenURLParams& params) override {
|
| + source->GetController().LoadURL(
|
| + params.url, params.referrer, params.transition, params.extra_headers);
|
| + Observe(source);
|
| + return source;
|
| + }
|
| +
|
| + bool CanDragEnter(content::WebContents* source,
|
| + const content::DropData& data,
|
| + blink::WebDragOperationsMask operations_allowed) override {
|
| + return false;
|
| + }
|
| +
|
| + bool ShouldCreateWebContents(
|
| + content::WebContents* web_contents,
|
| + int route_id,
|
| + int main_frame_route_id,
|
| + WindowContainerType window_container_type,
|
| + const std::string& frame_name,
|
| + const GURL& target_url,
|
| + const std::string& partition_id,
|
| + content::SessionStorageNamespace* session_storage_namespace) override {
|
| + return false;
|
| + }
|
| +
|
| + bool IsPopupOrPanel(const content::WebContents* source) const override {
|
| + return true;
|
| + }
|
| +
|
| + void MoveContents(content::WebContents* source,
|
| + const gfx::Rect& pos) override {
|
| + aura::Window* keyboard = ui_->GetKeyboardWindow();
|
| + // keyboard window must have been added to keyboard container window at this
|
| + // point. Otherwise, wrong keyboard bounds is used and may cause problem as
|
| + // described in crbug.com/367788.
|
| + DCHECK(keyboard->parent());
|
| + // keyboard window bounds may not set to |pos| after this call. If keyboard
|
| + // is in FULL_WIDTH mode, only the height of keyboard window will be
|
| + // changed.
|
| + keyboard->SetBounds(pos);
|
| + }
|
| +
|
| + // Overridden from content::WebContentsDelegate:
|
| + void RequestMediaAccessPermission(
|
| + content::WebContents* web_contents,
|
| + const content::MediaStreamRequest& request,
|
| + const content::MediaResponseCallback& callback) override {
|
| + ui_->RequestAudioInput(web_contents, request, callback);
|
| + }
|
| +
|
| + // Overridden from content::WebContentsObserver:
|
| + void WebContentsDestroyed() override { delete this; }
|
| +
|
| + keyboard::KeyboardUIContent* ui_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(KeyboardContentsDelegate);
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +namespace keyboard {
|
| +
|
| +class WindowBoundsChangeObserver : public aura::WindowObserver {
|
| + public:
|
| + explicit WindowBoundsChangeObserver(KeyboardUIContent* ui) : ui_(ui) {}
|
| + ~WindowBoundsChangeObserver() override {}
|
| +
|
| + void AddObservedWindow(aura::Window* window) {
|
| + if (!window->HasObserver(this)) {
|
| + window->AddObserver(this);
|
| + observed_windows_.insert(window);
|
| + }
|
| + }
|
| + void RemoveAllObservedWindows() {
|
| + for (std::set<aura::Window*>::iterator it = observed_windows_.begin();
|
| + it != observed_windows_.end(); ++it)
|
| + (*it)->RemoveObserver(this);
|
| + observed_windows_.clear();
|
| + }
|
| +
|
| + private:
|
| + void OnWindowBoundsChanged(aura::Window* window,
|
| + const gfx::Rect& old_bounds,
|
| + const gfx::Rect& new_bounds) override {
|
| + ui_->UpdateInsetsForWindow(window);
|
| + }
|
| + void OnWindowDestroyed(aura::Window* window) override {
|
| + if (window->HasObserver(this))
|
| + window->RemoveObserver(this);
|
| + observed_windows_.erase(window);
|
| + }
|
| +
|
| + KeyboardUIContent* ui_;
|
| + std::set<aura::Window*> observed_windows_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(WindowBoundsChangeObserver);
|
| +};
|
| +
|
| +KeyboardUIContent::KeyboardUIContent(content::BrowserContext* context)
|
| + : browser_context_(context),
|
| + default_url_(kKeyboardURL),
|
| + window_bounds_observer_(new WindowBoundsChangeObserver(this)) {
|
| +}
|
| +
|
| +KeyboardUIContent::~KeyboardUIContent() {
|
| + ResetInsets();
|
| +}
|
| +
|
| +void KeyboardUIContent::LoadSystemKeyboard() {
|
| + DCHECK(keyboard_contents_);
|
| + if (keyboard_contents_->GetURL() != default_url_) {
|
| + // TODO(bshe): The height of system virtual keyboard and IME virtual
|
| + // keyboard may different. The height needs to be restored too.
|
| + LoadContents(default_url_);
|
| + }
|
| +}
|
| +
|
| +void KeyboardUIContent::UpdateInsetsForWindow(aura::Window* window) {
|
| + aura::Window* keyboard_window = GetKeyboardWindow();
|
| + scoped_ptr<content::RenderWidgetHostIterator> widgets(
|
| + content::RenderWidgetHost::GetRenderWidgetHosts());
|
| + while (content::RenderWidgetHost* widget = widgets->GetNextHost()) {
|
| + content::RenderWidgetHostView* view = widget->GetView();
|
| + if (view && window->Contains(view->GetNativeView())) {
|
| + gfx::Rect window_bounds = view->GetNativeView()->GetBoundsInScreen();
|
| + gfx::Rect intersect =
|
| + gfx::IntersectRects(window_bounds, keyboard_window->bounds());
|
| + int overlap = ShouldEnableInsets(window) ? intersect.height() : 0;
|
| + if (overlap > 0 && overlap < window_bounds.height())
|
| + view->SetInsets(gfx::Insets(0, 0, overlap, 0));
|
| + else
|
| + view->SetInsets(gfx::Insets());
|
| + return;
|
| + }
|
| + }
|
| +}
|
| +
|
| +aura::Window* KeyboardUIContent::GetKeyboardWindow() {
|
| + if (!keyboard_contents_) {
|
| + content::BrowserContext* context = browser_context();
|
| + keyboard_contents_.reset(content::WebContents::Create(
|
| + content::WebContents::CreateParams(context,
|
| + content::SiteInstance::CreateForURL(context,
|
| + GetVirtualKeyboardUrl()))));
|
| + keyboard_contents_->SetDelegate(new KeyboardContentsDelegate(this));
|
| + SetupWebContents(keyboard_contents_.get());
|
| + LoadContents(GetVirtualKeyboardUrl());
|
| + keyboard_contents_->GetNativeView()->AddObserver(this);
|
| + }
|
| +
|
| + return keyboard_contents_->GetNativeView();
|
| +}
|
| +
|
| +bool KeyboardUIContent::HasKeyboardWindow() const {
|
| + return keyboard_contents_;
|
| +}
|
| +
|
| +void KeyboardUIContent::ReloadKeyboardIfNeeded() {
|
| + DCHECK(keyboard_contents_);
|
| + if (keyboard_contents_->GetURL() != GetVirtualKeyboardUrl()) {
|
| + if (keyboard_contents_->GetURL().GetOrigin() !=
|
| + GetVirtualKeyboardUrl().GetOrigin()) {
|
| + // Sets keyboard window rectangle to 0 and close current page before
|
| + // navigate to a keyboard in a different extension. This keeps the UX the
|
| + // same as Android. Note we need to explicitly close current page as it
|
| + // might try to resize keyboard window in javascript on a resize event.
|
| + GetKeyboardWindow()->SetBounds(gfx::Rect());
|
| + keyboard_contents_->ClosePage();
|
| + keyboard_controller()->SetKeyboardMode(FULL_WIDTH);
|
| + }
|
| + LoadContents(GetVirtualKeyboardUrl());
|
| + }
|
| +}
|
| +
|
| +void KeyboardUIContent::InitInsets(const gfx::Rect& new_bounds) {
|
| + // Adjust the height of the viewport for visible windows on the primary
|
| + // display.
|
| + // TODO(kevers): Add EnvObserver to properly initialize insets if a
|
| + // window is created while the keyboard is visible.
|
| + scoped_ptr<content::RenderWidgetHostIterator> widgets(
|
| + content::RenderWidgetHost::GetRenderWidgetHosts());
|
| + aura::Window* keyboard_window = GetKeyboardWindow();
|
| + aura::Window* root_window = keyboard_window->GetRootWindow();
|
| + while (content::RenderWidgetHost* widget = widgets->GetNextHost()) {
|
| + content::RenderWidgetHostView* view = widget->GetView();
|
| + // Can be NULL, e.g. if the RenderWidget is being destroyed or
|
| + // the render process crashed.
|
| + if (view) {
|
| + aura::Window* window = view->GetNativeView();
|
| + // If virtual keyboard failed to load, a widget that displays error
|
| + // message will be created and adds as a child of the virtual keyboard
|
| + // window. We want to avoid add BoundsChangedObserver to that window.
|
| + if (!keyboard_window->Contains(window) &&
|
| + window->GetRootWindow() == root_window) {
|
| + gfx::Rect window_bounds = window->GetBoundsInScreen();
|
| + gfx::Rect intersect = gfx::IntersectRects(window_bounds,
|
| + new_bounds);
|
| + int overlap = intersect.height();
|
| + if (overlap > 0 && overlap < window_bounds.height())
|
| + view->SetInsets(gfx::Insets(0, 0, overlap, 0));
|
| + else
|
| + view->SetInsets(gfx::Insets());
|
| + AddBoundsChangedObserver(window);
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +void KeyboardUIContent::ResetInsets() {
|
| + const gfx::Insets insets;
|
| + scoped_ptr<content::RenderWidgetHostIterator> widgets(
|
| + content::RenderWidgetHost::GetRenderWidgetHosts());
|
| + while (content::RenderWidgetHost* widget = widgets->GetNextHost()) {
|
| + content::RenderWidgetHostView* view = widget->GetView();
|
| + if (view)
|
| + view->SetInsets(insets);
|
| + }
|
| + window_bounds_observer_->RemoveAllObservedWindows();
|
| +}
|
| +
|
| +void KeyboardUIContent::SetupWebContents(content::WebContents* contents) {
|
| +}
|
| +
|
| +void KeyboardUIContent::OnWindowBoundsChanged(aura::Window* window,
|
| + const gfx::Rect& old_bounds,
|
| + const gfx::Rect& new_bounds) {
|
| + if (!shadow_) {
|
| + shadow_.reset(new wm::Shadow());
|
| + shadow_->Init(wm::Shadow::STYLE_ACTIVE);
|
| + shadow_->layer()->SetVisible(true);
|
| + DCHECK(keyboard_contents_->GetNativeView()->parent());
|
| + keyboard_contents_->GetNativeView()->parent()->layer()->Add(
|
| + shadow_->layer());
|
| + }
|
| +
|
| + shadow_->SetContentBounds(new_bounds);
|
| +}
|
| +
|
| +void KeyboardUIContent::OnWindowDestroyed(aura::Window* window) {
|
| + window->RemoveObserver(this);
|
| +}
|
| +
|
| +void KeyboardUIContent::LoadContents(const GURL& url) {
|
| + if (keyboard_contents_) {
|
| + content::OpenURLParams params(
|
| + url,
|
| + content::Referrer(),
|
| + SINGLETON_TAB,
|
| + ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
|
| + false);
|
| + keyboard_contents_->OpenURL(params);
|
| + }
|
| +}
|
| +
|
| +const GURL& KeyboardUIContent::GetVirtualKeyboardUrl() {
|
| + if (keyboard::IsInputViewEnabled()) {
|
| + const GURL& override_url = GetOverrideContentUrl();
|
| + return override_url.is_valid() ? override_url : default_url_;
|
| + } else {
|
| + return default_url_;
|
| + }
|
| +}
|
| +
|
| +bool KeyboardUIContent::ShouldEnableInsets(aura::Window* window) {
|
| + aura::Window* keyboard_window = GetKeyboardWindow();
|
| + return (keyboard_window->GetRootWindow() == window->GetRootWindow() &&
|
| + keyboard::IsKeyboardOverscrollEnabled() &&
|
| + keyboard_window->IsVisible() &&
|
| + keyboard_controller()->keyboard_visible());
|
| +}
|
| +
|
| +void KeyboardUIContent::AddBoundsChangedObserver(aura::Window* window) {
|
| + aura::Window* target_window = window ? window->GetToplevelWindow() : nullptr;
|
| + if (target_window)
|
| + window_bounds_observer_->AddObservedWindow(target_window);
|
| +}
|
| +
|
| +} // namespace keyboard
|
|
|