blob: 0fcc82a90c73ce1bba83d7b62378d39c8af6a130 [file] [log] [blame]
// Copyright 2018 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 "ash/keyboard/ash_keyboard_controller.h"
#include "ash/keyboard/ash_keyboard_ui.h"
#include "ash/keyboard/virtual_keyboard_controller.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/session/session_controller.h"
#include "ash/shell.h"
#include "ash/shell_delegate.h"
#include "base/command_line.h"
#include "ui/base/ui_base_features.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/keyboard/keyboard_controller.h"
#include "ui/keyboard/keyboard_ui_factory.h"
#include "ui/keyboard/public/keyboard_switches.h"
#include "ui/wm/core/coordinate_conversion.h"
using keyboard::mojom::KeyboardConfig;
using keyboard::mojom::KeyboardConfigPtr;
using keyboard::mojom::KeyboardEnableFlag;
namespace ash {
namespace {
class AshKeyboardUIFactory : public keyboard::KeyboardUIFactory {
public:
explicit AshKeyboardUIFactory(AshKeyboardController* controller)
: controller_(controller) {}
// keyboard::KeyboardUIFactory:
std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() override {
return std::make_unique<AshKeyboardUI>(controller_);
}
private:
AshKeyboardController* controller_;
DISALLOW_COPY_AND_ASSIGN(AshKeyboardUIFactory);
};
} // namespace
AshKeyboardController::AshKeyboardController(
SessionController* session_controller)
: session_controller_(session_controller),
keyboard_controller_(std::make_unique<keyboard::KeyboardController>()) {
if (session_controller_) // May be null in tests.
session_controller_->AddObserver(this);
keyboard_controller_->AddObserver(this);
}
AshKeyboardController::~AshKeyboardController() {
keyboard_controller_->RemoveObserver(this);
if (session_controller_) // May be null in tests.
session_controller_->RemoveObserver(this);
}
void AshKeyboardController::BindRequest(
mojom::KeyboardControllerRequest request) {
bindings_.AddBinding(this, std::move(request));
}
void AshKeyboardController::CreateVirtualKeyboard(
std::unique_ptr<keyboard::KeyboardUIFactory> keyboard_ui_factory) {
DCHECK(keyboard_ui_factory || features::IsUsingWindowService())
<< "keyboard_ui_factory can be null only when window service is used.";
virtual_keyboard_controller_ = std::make_unique<VirtualKeyboardController>();
keyboard_controller_->Initialize(
keyboard_ui_factory ? std::move(keyboard_ui_factory)
: std::make_unique<AshKeyboardUIFactory>(this),
virtual_keyboard_controller_.get());
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
keyboard::switches::kEnableVirtualKeyboard)) {
keyboard_controller_->SetEnableFlag(
KeyboardEnableFlag::kCommandLineEnabled);
}
}
void AshKeyboardController::DestroyVirtualKeyboard() {
virtual_keyboard_controller_.reset();
keyboard_controller_->Shutdown();
}
void AshKeyboardController::SendOnKeyboardVisibleBoundsChanged(
const gfx::Rect& screen_bounds) {
DVLOG(1) << "OnKeyboardVisibleBoundsChanged: " << screen_bounds.ToString();
// Pass the bounds in screen coordinates over mojo.
observers_.ForAllPtrs(
[&screen_bounds](mojom::KeyboardControllerObserver* observer) {
observer->OnKeyboardVisibleBoundsChanged(screen_bounds);
});
}
void AshKeyboardController::SendOnLoadKeyboardContentsRequested() {
observers_.ForAllPtrs([](mojom::KeyboardControllerObserver* observer) {
observer->OnLoadKeyboardContentsRequested();
});
}
void AshKeyboardController::SendOnKeyboardUIDestroyed() {
observers_.ForAllPtrs([](mojom::KeyboardControllerObserver* observer) {
observer->OnKeyboardUIDestroyed();
});
}
// mojom::KeyboardController
void AshKeyboardController::KeyboardContentsLoaded(
const base::UnguessableToken& token,
const gfx::Size& size) {
keyboard_controller()->KeyboardContentsLoaded(token, size);
}
void AshKeyboardController::GetKeyboardConfig(
GetKeyboardConfigCallback callback) {
std::move(callback).Run(
KeyboardConfig::New(keyboard_controller_->keyboard_config()));
}
void AshKeyboardController::SetKeyboardConfig(
KeyboardConfigPtr keyboard_config) {
keyboard_controller_->UpdateKeyboardConfig(*keyboard_config);
}
void AshKeyboardController::IsKeyboardEnabled(
IsKeyboardEnabledCallback callback) {
std::move(callback).Run(keyboard_controller_->IsEnabled());
}
void AshKeyboardController::SetEnableFlag(KeyboardEnableFlag flag) {
keyboard_controller_->SetEnableFlag(flag);
}
void AshKeyboardController::ClearEnableFlag(KeyboardEnableFlag flag) {
keyboard_controller_->ClearEnableFlag(flag);
}
void AshKeyboardController::GetEnableFlags(GetEnableFlagsCallback callback) {
const std::set<keyboard::mojom::KeyboardEnableFlag>& keyboard_enable_flags =
keyboard_controller_->keyboard_enable_flags();
std::vector<keyboard::mojom::KeyboardEnableFlag> flags(
keyboard_enable_flags.begin(), keyboard_enable_flags.end());
std::move(callback).Run(std::move(flags));
}
void AshKeyboardController::ReloadKeyboardIfNeeded() {
keyboard_controller_->Reload();
}
void AshKeyboardController::RebuildKeyboardIfEnabled() {
// Test IsKeyboardEnableRequested in case of an unlikely edge case where this
// is called while after the enable state changed to disabled (in which case
// we do not want to override the requested state).
keyboard_controller_->RebuildKeyboardIfEnabled();
}
void AshKeyboardController::IsKeyboardVisible(
IsKeyboardVisibleCallback callback) {
std::move(callback).Run(keyboard_controller_->IsKeyboardVisible());
}
void AshKeyboardController::ShowKeyboard() {
if (keyboard_controller_->IsEnabled())
keyboard_controller_->ShowKeyboard(false /* lock */);
}
void AshKeyboardController::HideKeyboard(mojom::HideReason reason) {
if (!keyboard_controller_->IsEnabled())
return;
switch (reason) {
case mojom::HideReason::kUser:
keyboard_controller_->HideKeyboardByUser();
break;
case mojom::HideReason::kSystem:
keyboard_controller_->HideKeyboardExplicitlyBySystem();
break;
}
}
void AshKeyboardController::SetContainerType(
keyboard::mojom::ContainerType container_type,
const base::Optional<gfx::Rect>& target_bounds,
SetContainerTypeCallback callback) {
keyboard_controller_->SetContainerType(container_type, target_bounds,
std::move(callback));
}
void AshKeyboardController::SetKeyboardLocked(bool locked) {
keyboard_controller_->set_keyboard_locked(locked);
}
void AshKeyboardController::SetOccludedBounds(
const std::vector<gfx::Rect>& bounds) {
// TODO(https://crbug.com/826617): Support occluded bounds with multiple
// rectangles.
keyboard_controller_->SetOccludedBounds(bounds.empty() ? gfx::Rect()
: bounds[0]);
}
void AshKeyboardController::SetHitTestBounds(
const std::vector<gfx::Rect>& bounds) {
keyboard_controller_->SetHitTestBounds(bounds);
}
void AshKeyboardController::SetDraggableArea(const gfx::Rect& bounds) {
keyboard_controller_->SetDraggableArea(bounds);
}
void AshKeyboardController::AddObserver(
mojom::KeyboardControllerObserverAssociatedPtrInfo observer) {
mojom::KeyboardControllerObserverAssociatedPtr observer_ptr;
observer_ptr.Bind(std::move(observer));
observers_.AddPtr(std::move(observer_ptr));
}
// SessionObserver
void AshKeyboardController::OnSessionStateChanged(
session_manager::SessionState state) {
if (!keyboard_controller_->IsEnabled())
return;
switch (state) {
case session_manager::SessionState::LOGGED_IN_NOT_ACTIVE:
case session_manager::SessionState::ACTIVE:
// Reload the keyboard on user profile change to refresh keyboard
// extensions with the new profile and ensure the extensions call the
// proper IME. |LOGGED_IN_NOT_ACTIVE| is needed so that the virtual
// keyboard works on supervised user creation, http://crbug.com/712873.
// |ACTIVE| is also needed for guest user workflow.
RebuildKeyboardIfEnabled();
break;
default:
break;
}
}
// private methods
void AshKeyboardController::OnRootWindowClosing(aura::Window* root_window) {
if (keyboard_controller_->GetRootWindow() == root_window) {
aura::Window* new_parent =
virtual_keyboard_controller_->GetContainerForDefaultDisplay();
DCHECK_NE(root_window, new_parent);
keyboard_controller_->MoveToParentContainer(new_parent);
}
}
void AshKeyboardController::OnKeyboardConfigChanged() {
KeyboardConfigPtr config =
KeyboardConfig::New(keyboard_controller_->keyboard_config());
observers_.ForAllPtrs([&config](mojom::KeyboardControllerObserver* observer) {
observer->OnKeyboardConfigChanged(config.Clone());
});
}
void AshKeyboardController::OnKeyboardVisibilityStateChanged(bool is_visible) {
observers_.ForAllPtrs(
[is_visible](mojom::KeyboardControllerObserver* observer) {
observer->OnKeyboardVisibilityChanged(is_visible);
});
}
void AshKeyboardController::OnKeyboardVisibleBoundsChanged(
const gfx::Rect& screen_bounds) {
SendOnKeyboardVisibleBoundsChanged(screen_bounds);
}
void AshKeyboardController::OnKeyboardWorkspaceOccludedBoundsChanged(
const gfx::Rect& screen_bounds) {
DVLOG(1) << "OnKeyboardOccludedBoundsChanged: " << screen_bounds.ToString();
// Pass the bounds in screen coordinates over mojo.
observers_.ForAllPtrs(
[&screen_bounds](mojom::KeyboardControllerObserver* observer) {
observer->OnKeyboardOccludedBoundsChanged(screen_bounds);
});
}
void AshKeyboardController::OnKeyboardEnableFlagsChanged(
std::set<keyboard::mojom::KeyboardEnableFlag>& keyboard_enable_flags) {
std::vector<keyboard::mojom::KeyboardEnableFlag> flags(
keyboard_enable_flags.begin(), keyboard_enable_flags.end());
observers_.ForAllPtrs([&flags](mojom::KeyboardControllerObserver* observer) {
observer->OnKeyboardEnableFlagsChanged(flags);
});
}
void AshKeyboardController::OnKeyboardEnabledChanged(bool is_enabled) {
observers_.ForAllPtrs(
[is_enabled](mojom::KeyboardControllerObserver* observer) {
observer->OnKeyboardEnabledChanged(is_enabled);
});
}
} // namespace ash