chromium/chrome/browser/ui/ash/keyboard/chrome_keyboard_ui.cc

// Copyright 2013 The Chromium Authors
// 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/keyboard/chrome_keyboard_ui.h"

#include <string>
#include <utility>

#include "ash/keyboard/ui/keyboard_ui_controller.h"
#include "ash/shell.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "chrome/browser/ui/ash/keyboard/chrome_keyboard_bounds_observer.h"
#include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
#include "chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/web_contents.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/ime/ash/ime_bridge.h"
#include "ui/compositor/layer.h"
#include "ui/compositor_extra/shadow.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/wm/core/shadow_types.h"

namespace {

const int kShadowElevationVirtualKeyboard = 2;

}  // namespace

ChromeKeyboardUI::ChromeKeyboardUI(content::BrowserContext* context)
    : browser_context_(context) {
}

ChromeKeyboardUI::~ChromeKeyboardUI() {
  DCHECK(!keyboard_controller());
}

// keyboard::KeyboardUI:

aura::Window* ChromeKeyboardUI::LoadKeyboardWindow(LoadCallback callback) {
  DCHECK(!keyboard_contents_);

  keyboard_contents_ = std::make_unique<ChromeKeyboardWebContents>(
      browser_context_,
      ChromeKeyboardControllerClient::Get()->GetVirtualKeyboardUrl(),
      base::BindOnce(
          [](LoadCallback callback) {
            ChromeKeyboardControllerClient::Get()->NotifyKeyboardLoaded();
            std::move(callback).Run();
          },
          std::move(callback)),
      base::NullCallback());

  aura::Window* keyboard_window =
      keyboard_contents_->web_contents()->GetNativeView();
  keyboard_window->AddObserver(this);

  return keyboard_window;
}

aura::Window* ChromeKeyboardUI::GetKeyboardWindow() const {
  return keyboard_contents_
             ? keyboard_contents_->web_contents()->GetNativeView()
             : nullptr;
}

ui::GestureConsumer* ChromeKeyboardUI::GetGestureConsumer() const {
  return keyboard_contents_
             ? keyboard_contents_->web_contents()->GetContentNativeView()
             : nullptr;
}

ui::InputMethod* ChromeKeyboardUI::GetInputMethod() {
  ash::IMEBridge* bridge = ash::IMEBridge::Get();
  if (!bridge || !bridge->GetInputContextHandler()) {
    // Needed by a handful of browser tests that use MockInputMethod.
    return ash::Shell::GetRootWindowForNewWindows()
        ->GetHost()
        ->GetInputMethod();
  }

  return bridge->GetInputContextHandler()->GetInputMethod();
}

void ChromeKeyboardUI::ReloadKeyboardIfNeeded() {
  VLOG(1) << "ReloadKeyboardIfNeeded";
  DCHECK(keyboard_contents_);
  keyboard_contents_->SetKeyboardUrl(
      ChromeKeyboardControllerClient::Get()->GetVirtualKeyboardUrl());
}

// aura::WindowObserver:

void ChromeKeyboardUI::OnWindowBoundsChanged(aura::Window* window,
                                             const gfx::Rect& old_bounds,
                                             const gfx::Rect& new_bounds,
                                             ui::PropertyChangeReason reason) {
  SetShadowAroundKeyboard();
}

void ChromeKeyboardUI::OnWindowDestroyed(aura::Window* window) {
  window->RemoveObserver(this);
}

void ChromeKeyboardUI::OnWindowParentChanged(aura::Window* window,
                                             aura::Window* parent) {
  SetShadowAroundKeyboard();
}

// private methods:

void ChromeKeyboardUI::SetShadowAroundKeyboard() {
  aura::Window* contents_window = GetKeyboardWindow();
  DCHECK(contents_window);

  if (!shadow_) {
    shadow_ = std::make_unique<ui::Shadow>();
    shadow_->Init(kShadowElevationVirtualKeyboard);
    shadow_->layer()->SetVisible(true);
    contents_window->layer()->Add(shadow_->layer());
  }

  shadow_->SetContentBounds(gfx::Rect(contents_window->bounds().size()));

  // In floating mode, make the shadow layer invisible because the shadows are
  // drawn manually by the IME extension.
  // TODO(https://crbug.com/856195): Remove this when we figure out how ChromeOS
  // can draw custom shaped shadows, or how overscrolling can account for
  // shadows drawn by IME.
  shadow_->layer()->SetVisible(
      keyboard_controller()->GetActiveContainerType() ==
      keyboard::ContainerType::kFullWidth);
}