Skip to content

Commit

Permalink
[Eche] Create mojo interface and bindings for keyboard layout changes
Browse files Browse the repository at this point in the history
This introduces a mojo interface that allows the EcheSWA to request the
current keyboard layout configuration and creates an observer interface
to route the information back. Additionally, EcheKeyboardLayoutHandler
also observes ImeControllerImpl and sends the same information to the
SWA whenever the keyboard layout changes.

Test: Manually verified app streaming is WAI, unit tests added.
Fixed: b/275816267
Change-Id: I1522789ead32b2c8e009b88d668466c5fdb59fac
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4786991
Reviewed-by: Jon Mann <jonmann@chromium.org>
Reviewed-by: Pu Shi <pushi@google.com>
Reviewed-by: Will Harris <wfh@chromium.org>
Commit-Queue: Crisrael Lucero <crisrael@google.com>
Reviewed-by: Abbas Nayebi <nayebi@google.com>
Cr-Commit-Position: refs/heads/main@{#1187254}
  • Loading branch information
crisrael authored and Chromium LUCI CQ committed Aug 23, 2023
1 parent 80836c0 commit 8fe1a9e
Show file tree
Hide file tree
Showing 14 changed files with 415 additions and 6 deletions.
3 changes: 3 additions & 0 deletions ash/webui/eche_app_ui/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ static_library("eche_app_ui") {
"eche_connector_impl.h",
"eche_feature_status_provider.cc",
"eche_feature_status_provider.h",
"eche_keyboard_layout_handler.cc",
"eche_keyboard_layout_handler.h",
"eche_message_receiver.cc",
"eche_message_receiver.h",
"eche_message_receiver_impl.cc",
Expand Down Expand Up @@ -194,6 +196,7 @@ source_set("unit_tests") {
"eche_connection_status_handler_unittest.cc",
"eche_connector_impl_unittest.cc",
"eche_feature_status_provider_unittest.cc",
"eche_keyboard_layout_handler_unittest.cc",
"eche_message_receiver_impl_unittest.cc",
"eche_notification_click_handler_unittest.cc",
"eche_presence_manager_unittest.cc",
Expand Down
11 changes: 10 additions & 1 deletion ash/webui/eche_app_ui/eche_app_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "ash/webui/eche_app_ui/eche_connection_scheduler_impl.h"
#include "ash/webui/eche_app_ui/eche_connection_status_handler.h"
#include "ash/webui/eche_app_ui/eche_connector_impl.h"
#include "ash/webui/eche_app_ui/eche_keyboard_layout_handler.h"
#include "ash/webui/eche_app_ui/eche_message_receiver_impl.h"
#include "ash/webui/eche_app_ui/eche_presence_manager.h"
#include "ash/webui/eche_app_ui/eche_signaler.h"
Expand Down Expand Up @@ -128,7 +129,9 @@ EcheAppManager::EcheAppManager(
stream_status_change_handler_.get(),
feature_status_provider_.get())),
eche_stream_orientation_observer_(
std::make_unique<EcheStreamOrientationObserver>()) {
std::make_unique<EcheStreamOrientationObserver>()),
eche_keyboard_layout_handler_(
std::make_unique<EcheKeyboardLayoutHandler>()) {
ash::GetNetworkConfigService(
remote_cros_network_config_.BindNewPipeAndPassReceiver());
system_info_provider_ = std::make_unique<SystemInfoProvider>(
Expand Down Expand Up @@ -188,6 +191,11 @@ void EcheAppManager::BindConnectionStatusObserverInterface(
eche_connection_status_handler_->Bind(std::move(receiver));
}

void EcheAppManager::BindKeyboardLayoutHandlerInterface(
mojo::PendingReceiver<mojom::KeyboardLayoutHandler> receiver) {
eche_keyboard_layout_handler_->Bind(std::move(receiver));
}

AppsAccessManager* EcheAppManager::GetAppsAccessManager() {
return apps_access_manager_.get();
}
Expand All @@ -212,6 +220,7 @@ void EcheAppManager::Shutdown() {
phone_hub_manager_->SetSystemInfoProvider(nullptr);
}

eche_keyboard_layout_handler_.reset();
eche_stream_orientation_observer_.reset();
system_info_provider_.reset();
eche_tray_stream_status_observer_.reset();
Expand Down
5 changes: 5 additions & 0 deletions ash/webui/eche_app_ui/eche_app_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class EcheTrayStreamStatusObserver;
class EcheConnectionScheduler;
class EcheStreamOrientationObserver;
class EcheConnectionStatusHandler;
class EcheKeyboardLayoutHandler;

// Implements the core logic of the EcheApp and exposes interfaces via its
// public API. Implemented as a KeyedService since it depends on other
Expand Down Expand Up @@ -106,6 +107,9 @@ class EcheAppManager : public KeyedService {
void BindConnectionStatusObserverInterface(
mojo::PendingReceiver<mojom::ConnectionStatusObserver> receiver);

void BindKeyboardLayoutHandlerInterface(
mojo::PendingReceiver<mojom::KeyboardLayoutHandler> receiver);

AppsAccessManager* GetAppsAccessManager();

EcheConnectionStatusHandler* GetEcheConnectionStatusHandler();
Expand Down Expand Up @@ -146,6 +150,7 @@ class EcheAppManager : public KeyedService {
eche_tray_stream_status_observer_;
std::unique_ptr<EcheStreamOrientationObserver>
eche_stream_orientation_observer_;
std::unique_ptr<EcheKeyboardLayoutHandler> eche_keyboard_layout_handler_;
};

} // namespace eche_app
Expand Down
37 changes: 32 additions & 5 deletions ash/webui/eche_app_ui/eche_app_manager_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

#include "ash/webui/eche_app_ui/eche_app_manager.h"

#include <vector>

#include "ash/test/ash_test_base.h"
#include "ash/test/test_ash_web_view_factory.h"
#include "ash/webui/eche_app_ui/eche_connection_status_handler.h"
#include "ash/webui/eche_app_ui/eche_keyboard_layout_handler.h"
#include "ash/webui/eche_app_ui/eche_stream_orientation_observer.h"
#include "ash/webui/eche_app_ui/eche_stream_status_change_handler.h"
#include "ash/webui/eche_app_ui/launch_app_helper.h"
Expand All @@ -19,6 +20,7 @@
#include "chromeos/ash/components/multidevice/remote_device_test_util.h"
#include "chromeos/ash/components/phonehub/fake_phone_hub_manager.h"
#include "chromeos/ash/components/phonehub/phone_hub_manager.h"
#include "chromeos/ash/components/test/ash_test_suite.h"
#include "chromeos/ash/services/device_sync/public/cpp/fake_device_sync_client.h"
#include "chromeos/ash/services/multidevice_setup/public/cpp/fake_multidevice_setup_client.h"
#include "chromeos/ash/services/secure_channel/public/cpp/client/fake_secure_channel_client.h"
Expand All @@ -29,6 +31,7 @@
#include "device/bluetooth/dbus/fake_bluetooth_debug_manager_client.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/image/image.h"

namespace ash::eche_app {
Expand Down Expand Up @@ -76,7 +79,7 @@ const char kFakeGaiaId[] = "123";
const size_t kNumTestDevices = 3;
const char kFakeDeviceType[] = "Chromebook";

class EcheAppManagerTest : public testing::Test {
class EcheAppManagerTest : public AshTestBase {
public:
EcheAppManagerTest(const EcheAppManagerTest&) = delete;
EcheAppManagerTest& operator=(const EcheAppManagerTest&) = delete;
Expand All @@ -87,7 +90,7 @@ class EcheAppManagerTest : public testing::Test {
multidevice::CreateRemoteDeviceRefListForTest(kNumTestDevices)) {}
~EcheAppManagerTest() override = default;

// testing::Test:
// AshTestBase:
void SetUp() override {
std::unique_ptr<bluez::BluezDBusManagerSetter> dbus_setter =
bluez::BluezDBusManager::GetSetterForTesting();
Expand All @@ -101,6 +104,11 @@ class EcheAppManagerTest : public testing::Test {
std::unique_ptr<bluez::BluetoothDebugManagerClient>(
std::move(fake_bluetooth_debug_manager_client)));

DCHECK(test_web_view_factory_.get());
ui::ResourceBundle::CleanupSharedInstance();
AshTestSuite::LoadTestResources();
AshTestBase::SetUp();

fake_phone_hub_manager_ = std::make_unique<phonehub::FakePhoneHubManager>();
fake_device_sync_client_ =
std::make_unique<device_sync::FakeDeviceSyncClient>();
Expand Down Expand Up @@ -130,6 +138,15 @@ class EcheAppManagerTest : public testing::Test {
base::BindRepeating(&CloseNotificationFunction));
}

void TearDown() override {
manager_.reset();
fake_secure_channel_client_.reset();
fake_multidevice_setup_client_.reset();
fake_device_sync_client_.reset();
fake_phone_hub_manager_.reset();
AshTestBase::TearDown();
}

mojo::Remote<mojom::SignalingMessageExchanger>&
signaling_message_exchanger_remote() {
return signaling_message_exchanger_remote_;
Expand Down Expand Up @@ -161,6 +178,10 @@ class EcheAppManagerTest : public testing::Test {
return connection_status_observer_remote_;
}

mojo::Remote<mojom::KeyboardLayoutHandler>& keyboard_layout_handler_remote() {
return keyboard_layout_handler_remote_;
}

void Bind() {
manager_->BindSignalingMessageExchangerInterface(
signaling_message_exchanger_remote_.BindNewPipeAndPassReceiver());
Expand All @@ -176,10 +197,11 @@ class EcheAppManagerTest : public testing::Test {
stream_orientation_observer_remote_.BindNewPipeAndPassReceiver());
manager_->BindConnectionStatusObserverInterface(
connection_status_observer_remote_.BindNewPipeAndPassReceiver());
manager_->BindKeyboardLayoutHandlerInterface(
keyboard_layout_handler_remote_.BindNewPipeAndPassReceiver());
}

private:
base::test::TaskEnvironment task_environment_;
const multidevice::RemoteDeviceRefList test_devices_;

TestingPrefServiceSimple test_pref_service_;
Expand All @@ -190,6 +212,8 @@ class EcheAppManagerTest : public testing::Test {
std::unique_ptr<secure_channel::FakeSecureChannelClient>
fake_secure_channel_client_;
std::unique_ptr<EcheAppManager> manager_;
std::unique_ptr<TestAshWebViewFactory> test_web_view_factory_ =
std::make_unique<TestAshWebViewFactory>();

mojo::Remote<mojom::SignalingMessageExchanger>
signaling_message_exchanger_remote_;
Expand All @@ -201,6 +225,7 @@ class EcheAppManagerTest : public testing::Test {
stream_orientation_observer_remote_;
mojo::Remote<mojom::ConnectionStatusObserver>
connection_status_observer_remote_;
mojo::Remote<mojom::KeyboardLayoutHandler> keyboard_layout_handler_remote_;
};

TEST_F(EcheAppManagerTest, BindCheck) {
Expand All @@ -211,6 +236,7 @@ TEST_F(EcheAppManagerTest, BindCheck) {
EXPECT_FALSE(display_stream_handler_remote());
EXPECT_FALSE(stream_orientation_observer_remote());
EXPECT_FALSE(connection_status_observer_remote());
EXPECT_FALSE(keyboard_layout_handler_remote());

Bind();

Expand All @@ -221,6 +247,7 @@ TEST_F(EcheAppManagerTest, BindCheck) {
EXPECT_TRUE(display_stream_handler_remote());
EXPECT_TRUE(stream_orientation_observer_remote());
EXPECT_TRUE(connection_status_observer_remote());
EXPECT_TRUE(keyboard_layout_handler_remote());
}

} // namespace ash::eche_app
7 changes: 7 additions & 0 deletions ash/webui/eche_app_ui/eche_app_ui.cc
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,13 @@ void EcheAppUI::BindInterface(
}
}

void EcheAppUI::BindInterface(
mojo::PendingReceiver<mojom::KeyboardLayoutHandler> receiver) {
if (manager_) {
manager_->BindKeyboardLayoutHandlerInterface(std::move(receiver));
}
}

WEB_UI_CONTROLLER_TYPE_IMPL(EcheAppUI)

} // namespace ash::eche_app
3 changes: 3 additions & 0 deletions ash/webui/eche_app_ui/eche_app_ui.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ class EcheAppUI : public ui::MojoWebUIController {
void BindInterface(
mojo::PendingReceiver<mojom::ConnectionStatusObserver> receiver);

void BindInterface(
mojo::PendingReceiver<mojom::KeyboardLayoutHandler> receiver);

private:
raw_ptr<EcheAppManager> manager_;

Expand Down
62 changes: 62 additions & 0 deletions ash/webui/eche_app_ui/eche_keyboard_layout_handler.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/webui/eche_app_ui/eche_keyboard_layout_handler.h"

#include "ash/shell.h"
#include "ash/webui/eche_app_ui/proto/exo_messages.pb.h"
#include "base/strings/utf_string_conversions.h"
#include "chromeos/ash/components/multidevice/logging/logging.h"

namespace ash::eche_app {

EcheKeyboardLayoutHandler::EcheKeyboardLayoutHandler()
: ime_controller_(Shell::Get()->ime_controller()) {
ime_controller_->AddObserver(this);
}

EcheKeyboardLayoutHandler::~EcheKeyboardLayoutHandler() {
ime_controller_->RemoveObserver(this);
}

void EcheKeyboardLayoutHandler::RequestCurrentKeyboardLayout() {
if (!remote_observer_.is_bound() || !ime_controller_) {
return;
}

const ImeInfo& current_ime = ime_controller_->current_ime();
remote_observer_->OnKeyboardLayoutChanged(
current_ime.id, base::UTF16ToUTF8(current_ime.name),
base::UTF16ToUTF8(current_ime.short_name),
ime_controller_->keyboard_layout_name());
}

void EcheKeyboardLayoutHandler::SetKeyboardLayoutObserver(
mojo::PendingRemote<mojom::KeyboardLayoutObserver> observer) {
PA_LOG(INFO) << "echeapi EcheKeyboardLayoutHandler SetKeyboardLayoutObserver";
remote_observer_.reset();
remote_observer_.Bind(std::move(observer));
}

void EcheKeyboardLayoutHandler::OnCapsLockChanged(bool enabled) {}

void EcheKeyboardLayoutHandler::OnKeyboardLayoutNameChanged(
const std::string& layout_name) {
if (!remote_observer_.is_bound()) {
return;
}

const ImeInfo& current_ime = ime_controller_->current_ime();
remote_observer_->OnKeyboardLayoutChanged(
current_ime.id, base::UTF16ToUTF8(current_ime.name),
base::UTF16ToUTF8(current_ime.short_name), layout_name);
}

void EcheKeyboardLayoutHandler::Bind(
mojo::PendingReceiver<mojom::KeyboardLayoutHandler> receiver) {
keyboard_layout_handler_.reset();
keyboard_layout_handler_.Bind(std::move(receiver));
}

} // namespace ash::eche_app
51 changes: 51 additions & 0 deletions ash/webui/eche_app_ui/eche_keyboard_layout_handler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef ASH_WEBUI_ECHE_APP_UI_ECHE_KEYBOARD_LAYOUT_HANDLER_H_
#define ASH_WEBUI_ECHE_APP_UI_ECHE_KEYBOARD_LAYOUT_HANDLER_H_

#include "ash/ime/ime_controller_impl.h"
#include "ash/webui/eche_app_ui/mojom/eche_app.mojom.h"
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"

namespace ash::eche_app {

// Implements the KeyboardLayoutHandler interface and observes ImeControllerImpl
// to relay keyboard layout/configuration information from ChromeOS to the Eche
// SWA. Additionally, provides the current keyboard layout to the SWA upon
// request.
class EcheKeyboardLayoutHandler : public mojom::KeyboardLayoutHandler,
public ImeControllerImpl::Observer {
public:
EcheKeyboardLayoutHandler();
~EcheKeyboardLayoutHandler() override;

// mojom::KeyboardLayoutHandler:
void RequestCurrentKeyboardLayout() override;
void SetKeyboardLayoutObserver(
mojo::PendingRemote<mojom::KeyboardLayoutObserver> observer) override;

// ImeControllerImpl::Observer:
void OnCapsLockChanged(bool enabled) override;
void OnKeyboardLayoutNameChanged(const std::string& layout_name) override;

void Bind(mojo::PendingReceiver<mojom::KeyboardLayoutHandler> receiver);

private:
friend class EcheKeyboardLayoutHandlerTest;

raw_ptr<ImeControllerImpl, ExperimentalAsh> ime_controller_ = nullptr;
mojo::Receiver<mojom::KeyboardLayoutHandler> keyboard_layout_handler_{this};
mojo::Remote<mojom::KeyboardLayoutObserver> remote_observer_;
};

} // namespace ash::eche_app

#endif // ASH_WEBUI_ECHE_APP_UI_ECHE_KEYBOARD_LAYOUT_HANDLER_H_

0 comments on commit 8fe1a9e

Please sign in to comment.