blob: 5d2657ba5786c5eb5056f57819bee610438696b6 [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 "chrome/browser/ui/ash/chrome_keyboard_controller_client.h"
#include <memory>
#include "ash/public/interfaces/constants.mojom.h"
#include "base/values.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "content/public/browser/browser_context.h"
#include "content/public/common/service_manager_connection.h"
#include "extensions/browser/api/virtual_keyboard_private/virtual_keyboard_delegate.h"
#include "extensions/browser/api/virtual_keyboard_private/virtual_keyboard_private_api.h"
#include "extensions/browser/event_router.h"
#include "extensions/common/api/virtual_keyboard_private.h"
#include "extensions/common/extension_messages.h"
#include "services/service_manager/public/cpp/connector.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/keyboard/keyboard_controller.h"
namespace virtual_keyboard_private = extensions::api::virtual_keyboard_private;
namespace {
static ChromeKeyboardControllerClient* g_chrome_keyboard_controller_client =
nullptr;
Profile* GetProfile() {
// Always use the active profile for generating keyboard events so that any
// virtual keyboard extensions associated with the active user are notified.
// (Note: UI and associated extensions only exist for the active user).
return ProfileManager::GetActiveUserProfile();
}
} // namespace
// static
ChromeKeyboardControllerClient* ChromeKeyboardControllerClient::Get() {
CHECK(g_chrome_keyboard_controller_client)
<< "ChromeKeyboardControllerClient::Get() called before Initialize()";
return g_chrome_keyboard_controller_client;
}
ChromeKeyboardControllerClient::ChromeKeyboardControllerClient() {
CHECK(!g_chrome_keyboard_controller_client);
g_chrome_keyboard_controller_client = this;
content::ServiceManagerConnection::GetForProcess()
->GetConnector()
->BindInterface(ash::mojom::kServiceName, &keyboard_controller_ptr_);
// Request the configuration. This will be queued until the service is ready.
keyboard_controller_ptr_->GetKeyboardConfig(base::BindOnce(
&ChromeKeyboardControllerClient::OnGetInitialKeyboardConfig,
weak_ptr_factory_.GetWeakPtr()));
}
ChromeKeyboardControllerClient::~ChromeKeyboardControllerClient() {
CHECK(g_chrome_keyboard_controller_client);
g_chrome_keyboard_controller_client = nullptr;
}
void ChromeKeyboardControllerClient::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void ChromeKeyboardControllerClient::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
keyboard::mojom::KeyboardConfig
ChromeKeyboardControllerClient::GetKeyboardConfig() {
if (!cached_keyboard_config_) {
// Unlikely edge case (called before the Ash mojo service replies to the
// initial GetKeyboardConfig request). Return the default value.
return keyboard::mojom::KeyboardConfig();
}
return *cached_keyboard_config_.get();
}
void ChromeKeyboardControllerClient::SetKeyboardConfig(
const keyboard::mojom::KeyboardConfig& config) {
// Update the cache immediately.
cached_keyboard_config_ = keyboard::mojom::KeyboardConfig::New(config);
keyboard_controller_ptr_->SetKeyboardConfig(cached_keyboard_config_.Clone());
}
void ChromeKeyboardControllerClient::OnGetInitialKeyboardConfig(
keyboard::mojom::KeyboardConfigPtr config) {
// Only set the cached value if not already set by SetKeyboardConfig (the
// set value will override the initial value once processed).
if (!cached_keyboard_config_)
cached_keyboard_config_ = std::move(config);
// Add this as a KeyboardController observer now that the service is ready.
ash::mojom::KeyboardControllerObserverAssociatedPtrInfo ptr_info;
keyboard_controller_observer_binding_.Bind(mojo::MakeRequest(&ptr_info));
keyboard_controller_ptr_->AddObserver(std::move(ptr_info));
}
void ChromeKeyboardControllerClient::OnKeyboardVisibleBoundsChanged(
const gfx::Rect& bounds) {
Profile* profile = GetProfile();
extensions::EventRouter* router = extensions::EventRouter::Get(profile);
if (!router->HasEventListener(
virtual_keyboard_private::OnBoundsChanged::kEventName)) {
return;
}
auto event_args = std::make_unique<base::ListValue>();
auto new_bounds = std::make_unique<base::DictionaryValue>();
new_bounds->SetInteger("left", bounds.x());
new_bounds->SetInteger("top", bounds.y());
new_bounds->SetInteger("width", bounds.width());
new_bounds->SetInteger("height", bounds.height());
event_args->Append(std::move(new_bounds));
auto event = std::make_unique<extensions::Event>(
extensions::events::VIRTUAL_KEYBOARD_PRIVATE_ON_BOUNDS_CHANGED,
virtual_keyboard_private::OnBoundsChanged::kEventName,
std::move(event_args), profile);
router->BroadcastEvent(std::move(event));
}
void ChromeKeyboardControllerClient::OnKeyboardWindowDestroyed() {
Profile* profile = GetProfile();
extensions::EventRouter* router = extensions::EventRouter::Get(profile);
if (!router->HasEventListener(
virtual_keyboard_private::OnKeyboardClosed::kEventName)) {
return;
}
auto event = std::make_unique<extensions::Event>(
extensions::events::VIRTUAL_KEYBOARD_PRIVATE_ON_KEYBOARD_CLOSED,
virtual_keyboard_private::OnKeyboardClosed::kEventName,
std::make_unique<base::ListValue>(), profile);
router->BroadcastEvent(std::move(event));
}
void ChromeKeyboardControllerClient::OnKeyboardConfigChanged(
keyboard::mojom::KeyboardConfigPtr config) {
cached_keyboard_config_ = std::move(config);
extensions::VirtualKeyboardAPI* api =
extensions::BrowserContextKeyedAPIFactory<
extensions::VirtualKeyboardAPI>::Get(GetProfile());
api->delegate()->OnKeyboardConfigChanged();
}
void ChromeKeyboardControllerClient::OnKeyboardVisibilityChanged(bool visible) {
for (auto& observer : observers_)
observer.OnKeyboardVisibilityChanged(visible);
}