commit 1344a1aed8dd3d9e34fba3581786e478086475af
Author: Christine Franks <
christ...@google.com>
AuthorDate: Fri Mar 05 05:33:11 2021
Commit: Chromium LUCI CQ <
chromiu...@luci-project-accounts.iam.gserviceaccount.com>
CommitDate: Fri Mar 05 05:33:11 2021
Reland "Add and implement mojo interfaces for EcheApp"
This is a reland of 01ed1abe15c52a837d0ad0ad348a97b415b84b0f
Initialized current_phone_hub_feature_status_ in
eche_feature_status_provider.cc. This was an MSan error.
Original change's description:
> Add and implement mojo interfaces for EcheApp
>
> crbug/1182418
>
> Bug: b/176936453
> Bug: t status
> Test: chromeos_components_unittests
> Change-Id: I65fae9f624c985e722b5af94e48c5918893ac0fb
> Reviewed-on:
https://chromium-review.googlesource.com/c/chromium/src/+/2698709
> Reviewed-by: Scott Violet <
s...@chromium.org>
> Reviewed-by: Kyle Horimoto <
khor...@chromium.org>
> Reviewed-by: Daniel Cheng <
dch...@chromium.org>
> Reviewed-by: Daniel Nishi <
dhn...@chromium.org>
> Commit-Queue: Christine Franks <
christ...@google.com>
> Cr-Commit-Position: refs/heads/master@{#859612}
Bug: b/176936453
Bug: t status
Change-Id: I173e98b3d758484dcdd27e5a8d0880c8ab672625
Reviewed-on:
https://chromium-review.googlesource.com/c/chromium/src/+/2733993
Reviewed-by: Daniel Cheng <
dch...@chromium.org>
Reviewed-by: Daniel Nishi <
dhn...@chromium.org>
Reviewed-by: Scott Violet <
s...@chromium.org>
Reviewed-by: Kyle Horimoto <
khor...@chromium.org>
Commit-Queue: Christine Franks <
christ...@google.com>
Cr-Commit-Position: refs/heads/master@{#860136}
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index eea81ab..73bc5b4 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2396,6 +2396,8 @@
"//chromeos/components/connectivity_diagnostics",
"//chromeos/components/diagnostics_ui",
"//chromeos/components/diagnostics_ui/mojom",
+ "//chromeos/components/eche_app_ui",
+ "//chromeos/components/eche_app_ui/mojom",
"//chromeos/components/help_app_ui",
"//chromeos/components/help_app_ui:mojo_bindings",
"//chromeos/components/local_search_service",
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc
index e0cebaf3..11d1633 100644
--- a/chrome/browser/chrome_browser_interface_binders.cc
+++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -190,6 +190,8 @@
#include "chromeos/components/diagnostics_ui/diagnostics_ui.h"
#include "chromeos/components/diagnostics_ui/mojom/system_data_provider.mojom.h"
#include "chromeos/components/diagnostics_ui/mojom/system_routine_controller.mojom.h"
+#include "chromeos/components/eche_app_ui/eche_app_ui.h"
+#include "chromeos/components/eche_app_ui/mojom/eche_app.mojom.h"
#include "chromeos/components/help_app_ui/help_app_ui.h"
#include "chromeos/components/help_app_ui/help_app_ui.mojom.h"
#include "chromeos/components/local_search_service/public/mojom/index.mojom.h"
@@ -808,6 +810,10 @@
chromeos::local_search_service::mojom::Index, chromeos::HelpAppUI>(map);
RegisterWebUIControllerInterfaceBinder<
+ chromeos::eche_app::mojom::SignalingMessageExchanger,
+ chromeos::eche_app::EcheAppUI>(map);
+
+ RegisterWebUIControllerInterfaceBinder<
media_app_ui::mojom::PageHandlerFactory, chromeos::MediaAppUI>(map);
RegisterWebUIControllerInterfaceBinder<
diff --git a/chrome/browser/chromeos/eche_app/eche_app_manager_factory.cc b/chrome/browser/chromeos/eche_app/eche_app_manager_factory.cc
index 1fce44d..80ce350 100644
--- a/chrome/browser/chromeos/eche_app/eche_app_manager_factory.cc
+++ b/chrome/browser/chromeos/eche_app/eche_app_manager_factory.cc
@@ -8,7 +8,11 @@
#include "ash/constants/ash_features.h"
#include "base/bind.h"
+#include "chrome/browser/chromeos/device_sync/device_sync_client_factory.h"
+#include "chrome/browser/chromeos/multidevice_setup/multidevice_setup_client_factory.h"
#include "chrome/browser/chromeos/phonehub/phone_hub_manager_factory.h"
+#include "chrome/browser/chromeos/secure_channel/nearby_connector_factory.h"
+#include "chrome/browser/chromeos/secure_channel/secure_channel_client_provider.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/web_applications/system_web_app_ui_utils.h"
#include "chromeos/components/eche_app_ui/eche_app_manager.h"
@@ -48,6 +52,9 @@
"EcheAppManager",
BrowserContextDependencyManager::GetInstance()) {
DependsOn(phonehub::PhoneHubManagerFactory::GetInstance());
+ DependsOn(device_sync::DeviceSyncClientFactory::GetInstance());
+ DependsOn(multidevice_setup::MultiDeviceSetupClientFactory::GetInstance());
+ DependsOn(secure_channel::NearbyConnectorFactory::GetInstance());
}
EcheAppManagerFactory::~EcheAppManagerFactory() = default;
@@ -63,7 +70,23 @@
if (!phone_hub_manager)
return nullptr;
- return new EcheAppManager(phone_hub_manager,
+ device_sync::DeviceSyncClient* device_sync_client =
+ device_sync::DeviceSyncClientFactory::GetForProfile(profile);
+ if (!device_sync_client)
+ return nullptr;
+
+ multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client =
+ multidevice_setup::MultiDeviceSetupClientFactory::GetForProfile(profile);
+ if (!multidevice_setup_client)
+ return nullptr;
+
+ secure_channel::SecureChannelClient* secure_channel_client =
+ secure_channel::SecureChannelClientProvider::GetInstance()->GetClient();
+ if (!secure_channel_client)
+ return nullptr;
+
+ return new EcheAppManager(phone_hub_manager, device_sync_client,
+ multidevice_setup_client, secure_channel_client,
base::BindRepeating(&LaunchEcheApp, profile));
}
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index b48a73d..227abc1 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -159,6 +159,7 @@
#include "chrome/browser/ash/web_applications/chrome_media_app_ui_delegate.h"
#include "chrome/browser/chromeos/arc/arc_util.h"
#include "chrome/browser/chromeos/device_sync/device_sync_client_factory.h"
+#include "chrome/browser/chromeos/eche_app/eche_app_manager_factory.h"
#include "chrome/browser/chromeos/file_manager/path_util.h"
#include "chrome/browser/chromeos/login/login_pref_names.h"
#include "chrome/browser/chromeos/multidevice_setup/multidevice_setup_service_factory.h"
@@ -214,6 +215,7 @@
#include "chromeos/components/connectivity_diagnostics/url_constants.h"
#include "chromeos/components/diagnostics_ui/diagnostics_ui.h"
#include "chromeos/components/diagnostics_ui/url_constants.h"
+#include "chromeos/components/eche_app_ui/eche_app_manager.h"
#include "chromeos/components/eche_app_ui/eche_app_ui.h"
#include "chromeos/components/eche_app_ui/url_constants.h"
#include "chromeos/components/help_app_ui/help_app_ui.h"
@@ -378,6 +380,25 @@
base::BindRepeating(&BindPrintManagement, Profile::FromWebUI(web_ui)));
}
+void BindEcheSignalingMessageExchanger(
+ Profile* profile,
+ mojo::PendingReceiver<chromeos::eche_app::mojom::SignalingMessageExchanger>
+ receiver) {
+ chromeos::eche_app::EcheAppManager* manager =
+ chromeos::eche_app::EcheAppManagerFactory::GetForProfile(profile);
+ if (manager) {
+ manager->BindInterface(std::move(receiver));
+ }
+}
+
+template <>
+WebUIController* NewWebUI<chromeos::eche_app::EcheAppUI>(WebUI* web_ui,
+ const GURL& url) {
+ return new chromeos::eche_app::EcheAppUI(
+ web_ui, base::BindRepeating(&BindEcheSignalingMessageExchanger,
+ Profile::FromWebUI(web_ui)));
+}
+
void BindScanService(
Profile* profile,
mojo::PendingReceiver<chromeos::scanning::mojom::ScanService>
diff --git a/chromeos/components/BUILD.gn b/chromeos/components/BUILD.gn
index bbf2c98..82cc1d5 100644
--- a/chromeos/components/BUILD.gn
+++ b/chromeos/components/BUILD.gn
@@ -22,6 +22,7 @@
"//chromeos/components/cdm_factory_daemon:unit_tests",
"//chromeos/components/diagnostics_ui/backend:unit_tests",
"//chromeos/components/drivefs:unit_tests",
+ "//chromeos/components/eche_app_ui:unit_tests",
"//chromeos/components/local_search_service:unit_tests",
"//chromeos/components/local_search_service/public/mojom:unit_tests",
"//chromeos/components/mojo_bootstrap:unit_tests",
diff --git a/chromeos/components/eche_app_ui/BUILD.gn b/chromeos/components/eche_app_ui/BUILD.gn
index 2102499..d9e5504 100644
--- a/chromeos/components/eche_app_ui/BUILD.gn
+++ b/chromeos/components/eche_app_ui/BUILD.gn
@@ -4,10 +4,14 @@
import("//chrome/test/base/js2gtest.gni")
import("//third_party/closure_compiler/compile_js.gni")
+import("//tools/grit/preprocess_if_expr.gni")
import("//ui/webui/resources/tools/generate_grd.gni")
assert(is_chromeos, "Eche App is Chrome OS only")
+preprocess_mojo_manifest = "preprocessed_mojo_manifest.json"
+preprocess_folder = "preprocessed"
+
static_library("eche_app_ui") {
sources = [
"eche_app_manager.cc",
@@ -20,6 +24,8 @@
"eche_feature_status_provider.h",
"eche_notification_click_handler.cc",
"eche_notification_click_handler.h",
+ "eche_signaler.cc",
+ "eche_signaler.h",
"feature_status.cc",
"feature_status.h",
"feature_status_provider.cc",
@@ -30,6 +36,7 @@
deps = [
"//ash/constants",
+ "//chromeos/components/eche_app_ui/mojom",
"//chromeos/components/eche_app_ui/proto",
"//chromeos/components/multidevice:multidevice",
"//chromeos/components/multidevice/logging",
@@ -44,11 +51,34 @@
]
}
+source_set("unit_tests") {
+ testonly = true
+ sources = [ "eche_feature_status_provider_unittest.cc" ]
+ deps = [
+ ":eche_app_ui",
+ "//base",
+ "//base/test:test_support",
+ "//chromeos/components/multidevice",
+ "//chromeos/components/multidevice:test_support",
+ "//chromeos/components/phonehub",
+ "//chromeos/components/phonehub:debug",
+ "//chromeos/services/device_sync/public/cpp",
+ "//chromeos/services/device_sync/public/cpp:test_support",
+ "//chromeos/services/multidevice_setup/public/cpp",
+ "//chromeos/services/multidevice_setup/public/cpp:test_support",
+ "//chromeos/services/secure_channel/public/cpp/client:test_support",
+ "//components/prefs:test_support",
+ "//testing/gtest",
+ ]
+}
+
js_type_check("closure_compile") {
deps = [ ":app" ]
}
js_library("app") {
+ deps =
+ [ "//chromeos/components/eche_app_ui/mojom:mojom_js_library_for_compile" ]
sources = [
"resources/browser_proxy.js",
"resources/mock/js/app_bundle.js",
@@ -69,4 +99,25 @@
manifest_files = []
grd_prefix = "chromeos_eche_app"
out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
+ deps = [ ":build_mojo_grdp" ]
+ grdp_files = [ "$target_gen_dir/chromeos_eche_app_mojo_resources.grdp" ]
+ resource_path_rewrites = [ "chromeos/components/eche_app_ui/mojom/eche_app.mojom-lite.js|mojo/eche_app.mojom-lite.js" ]
+}
+
+generate_grd("build_mojo_grdp") {
+ grd_prefix = "chromeos_eche_app"
+ out_grd = "$target_gen_dir/${grd_prefix}_mojo_resources.grdp"
+ deps = [ ":preprocess_mojo" ]
+ manifest_files = [ "$target_gen_dir/$preprocess_mojo_manifest" ]
+ resource_path_rewrites = [ "chromeos/components/eche_app_ui/mojom/eche_app.mojom-lite.js|mojo/eche_app.mojom-lite.js" ]
+}
+
+# Mojo files, for generating grdp
+preprocess_if_expr("preprocess_mojo") {
+ deps =
+ [ "//chromeos/components/eche_app_ui/mojom:mojom_js_library_for_compile" ]
+ in_folder = "$root_gen_dir"
+ out_folder = "$target_gen_dir/$preprocess_folder"
+ out_manifest = "$target_gen_dir/$preprocess_mojo_manifest"
+ in_files = [ "chromeos/components/eche_app_ui/mojom/eche_app.mojom-lite.js" ]
}
diff --git a/chromeos/components/eche_app_ui/eche_app_manager.cc b/chromeos/components/eche_app_ui/eche_app_manager.cc
index 29ed9d9..3aab2a8 100644
--- a/chromeos/components/eche_app_ui/eche_app_manager.cc
+++ b/chromeos/components/eche_app_ui/eche_app_manager.cc
@@ -5,24 +5,63 @@
#include "chromeos/components/eche_app_ui/eche_app_manager.h"
#include "chromeos/components/eche_app_ui/eche_notification_click_handler.h"
+#include "chromeos/components/eche_app_ui/eche_signaler.h"
#include "chromeos/components/phonehub/notification_interaction_handler.h"
#include "chromeos/components/phonehub/phone_hub_manager.h"
+#include "chromeos/services/secure_channel/public/cpp/client/connection_manager_impl.h"
namespace chromeos {
+namespace {
+const char kSecureChannelFeatureName[] = "eche";
+const char kMetricNameResult[] = "Eche.Connection.Result";
+const char kMetricNameDuration[] = "Eche.Connection.Duration";
+const char kMetricNameLatency[] = "Eche.Connectivity.Latency";
+} // namespace
namespace eche_app {
EcheAppManager::EcheAppManager(
phonehub::PhoneHubManager* phone_hub_manager,
+ device_sync::DeviceSyncClient* device_sync_client,
+ multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client,
+ secure_channel::SecureChannelClient* secure_channel_client,
EcheNotificationClickHandler::LaunchEcheAppFunction
launch_eche_app_function)
: eche_notification_click_handler_(
std::make_unique<EcheNotificationClickHandler>(
phone_hub_manager,
- launch_eche_app_function)) {}
+ launch_eche_app_function)),
+ connection_manager_(
+ std::make_unique<secure_channel::ConnectionManagerImpl>(
+ multidevice_setup_client,
+ device_sync_client,
+ secure_channel_client,
+ kSecureChannelFeatureName,
+ kMetricNameResult,
+ kMetricNameDuration,
+ kMetricNameLatency)),
+ feature_status_provider_(std::make_unique<EcheFeatureStatusProvider>(
+ phone_hub_manager,
+ device_sync_client,
+ multidevice_setup_client,
+ connection_manager_.get())),
+ eche_connector_(
+ std::make_unique<EcheConnector>(feature_status_provider_.get(),
+ connection_manager_.get())),
+ signaler_(std::make_unique<EcheSignaler>(eche_connector_.get(),
+ connection_manager_.get())) {}
EcheAppManager::~EcheAppManager() = default;
+void EcheAppManager::BindInterface(
+ mojo::PendingReceiver<mojom::SignalingMessageExchanger> receiver) {
+ signaler_->Bind(std::move(receiver));
+}
+
void EcheAppManager::Shutdown() {
+ signaler_.reset();
+ eche_connector_.reset();
+ feature_status_provider_.reset();
+ connection_manager_.reset();
eche_notification_click_handler_.reset();
}
diff --git a/chromeos/components/eche_app_ui/eche_app_manager.h b/chromeos/components/eche_app_ui/eche_app_manager.h
index f7b5439..91bf30e 100644
--- a/chromeos/components/eche_app_ui/eche_app_manager.h
+++ b/chromeos/components/eche_app_ui/eche_app_manager.h
@@ -7,31 +7,60 @@
#include <stdint.h>
+#include "chromeos/components/eche_app_ui/eche_connector.h"
+#include "chromeos/components/eche_app_ui/eche_feature_status_provider.h"
#include "chromeos/components/eche_app_ui/eche_notification_click_handler.h"
+#include "chromeos/components/eche_app_ui/mojom/eche_app.mojom.h"
#include "chromeos/components/phonehub/phone_hub_manager.h"
#include "components/keyed_service/core/keyed_service.h"
namespace chromeos {
+
+namespace device_sync {
+class DeviceSyncClient;
+} // namespace device_sync
+
+namespace multidevice_setup {
+class MultiDeviceSetupClient;
+} // namespace multidevice_setup
+
+namespace secure_channel {
+class ConnectionManager;
+class SecureChannelClient;
+} // namespace secure_channel
+
namespace eche_app {
+class EcheSignaler;
+
// Implements the core logic of the EcheApp and exposes interfaces via its
// public API. Implemented as a KeyedService since it depends on other
// KeyedService instances.
class EcheAppManager : public KeyedService {
public:
EcheAppManager(phonehub::PhoneHubManager*,
+ device_sync::DeviceSyncClient*,
+ multidevice_setup::MultiDeviceSetupClient*,
+ secure_channel::SecureChannelClient*,
EcheNotificationClickHandler::LaunchEcheAppFunction);
~EcheAppManager() override;
EcheAppManager(const EcheAppManager&) = delete;
EcheAppManager& operator=(const EcheAppManager&) = delete;
+ void BindInterface(
+ mojo::PendingReceiver<mojom::SignalingMessageExchanger> receiver);
+
// KeyedService:
void Shutdown() override;
private:
std::unique_ptr<EcheNotificationClickHandler>
eche_notification_click_handler_;
+ std::unique_ptr<secure_channel::ConnectionManager> connection_manager_;
+ std::unique_ptr<EcheFeatureStatusProvider> feature_status_provider_;
+ std::unique_ptr<EcheConnector> eche_connector_;
+ std::unique_ptr<EcheSignaler> signaler_;
};
} // namespace eche_app
diff --git a/chromeos/components/eche_app_ui/eche_app_ui.cc b/chromeos/components/eche_app_ui/eche_app_ui.cc
index e690be8..b002774a 100644
--- a/chromeos/components/eche_app_ui/eche_app_ui.cc
+++ b/chromeos/components/eche_app_ui/eche_app_ui.cc
@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chromeos/components/eche_app_ui/eche_app_ui.h"
-
#include <memory>
+#include "chromeos/components/eche_app_ui/eche_app_manager.h"
+#include "chromeos/components/eche_app_ui/eche_app_ui.h"
+#include "chromeos/components/eche_app_ui/mojom/eche_app.mojom.h"
#include "chromeos/components/eche_app_ui/url_constants.h"
#include "chromeos/grit/chromeos_eche_app_resources.h"
#include "chromeos/grit/chromeos_eche_bundle_resources.h"
@@ -16,7 +17,10 @@
namespace chromeos {
namespace eche_app {
-EcheAppUI::EcheAppUI(content::WebUI* web_ui) : ui::MojoWebUIController(web_ui) {
+EcheAppUI::EcheAppUI(content::WebUI* web_ui,
+ BindSignalingMessageExchangerCallback exchanger_callback)
+ : ui::MojoWebUIController(web_ui),
+ bind_exchanger_callback_(std::move(exchanger_callback)) {
auto html_source =
base::WrapUnique(content::WebUIDataSource::Create(kChromeUIEcheAppHost));
@@ -29,6 +33,9 @@
IDR_CHROMEOS_ECHE_APP_BUNDLE_JS);
html_source->AddResourcePath("assets/app_bundle.css",
IDR_CHROMEOS_ECHE_APP_BUNDLE_CSS);
+ html_source->AddResourcePath(
+ "eche_app.mojom-lite.js",
+ IDR_CHROMEOS_ECHE_APP_CHROMEOS_COMPONENTS_ECHE_APP_UI_MOJOM_ECHE_APP_MOJOM_LITE_JS);
html_source->AddResourcePath("browser_proxy.js",
IDR_CHROMEOS_ECHE_APP_BROWSER_PROXY_JS);
@@ -42,5 +49,12 @@
EcheAppUI::~EcheAppUI() = default;
+void EcheAppUI::BindInterface(
+ mojo::PendingReceiver<mojom::SignalingMessageExchanger> receiver) {
+ bind_exchanger_callback_.Run(std::move(receiver));
+}
+
+WEB_UI_CONTROLLER_TYPE_IMPL(EcheAppUI)
+
} // namespace eche_app
} // namespace chromeos
diff --git a/chromeos/components/eche_app_ui/eche_app_ui.h b/chromeos/components/eche_app_ui/eche_app_ui.h
index 5abe498..a22a1be 100644
--- a/chromeos/components/eche_app_ui/eche_app_ui.h
+++ b/chromeos/components/eche_app_ui/eche_app_ui.h
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/macros.h"
+#include "chromeos/components/eche_app_ui/mojom/eche_app.mojom-forward.h"
#include "ui/webui/mojo_web_ui_controller.h"
#ifndef CHROMEOS_COMPONENTS_ECHE_APP_UI_ECHE_APP_UI_H_
@@ -13,10 +15,22 @@
// The WebUI for chrome://eche-app/.
class EcheAppUI : public ui::MojoWebUIController {
public:
- explicit EcheAppUI(content::WebUI* web_ui);
+ using BindSignalingMessageExchangerCallback = base::RepeatingCallback<void(
+ mojo::PendingReceiver<mojom::SignalingMessageExchanger>)>;
+
+ EcheAppUI(content::WebUI* web_ui,
+ BindSignalingMessageExchangerCallback exchanger_callback);
EcheAppUI(const EcheAppUI&) = delete;
EcheAppUI& operator=(const EcheAppUI&) = delete;
~EcheAppUI() override;
+
+ void BindInterface(
+ mojo::PendingReceiver<mojom::SignalingMessageExchanger> receiver);
+
+ private:
+ const BindSignalingMessageExchangerCallback bind_exchanger_callback_;
+
+ WEB_UI_CONTROLLER_TYPE_DECL();
};
} // namespace eche_app
diff --git a/chromeos/components/eche_app_ui/eche_feature_status_provider.cc b/chromeos/components/eche_app_ui/eche_feature_status_provider.cc
index 0455603..90ad08d 100644
--- a/chromeos/components/eche_app_ui/eche_feature_status_provider.cc
+++ b/chromeos/components/eche_app_ui/eche_feature_status_provider.cc
@@ -42,13 +42,13 @@
if (!local_device)
return false;
if (local_device->GetSoftwareFeatureState(SoftwareFeature::kEcheClient) ==
- SoftwareFeatureState::kNotSupported) {
+ SoftwareFeatureState::kNotSupported)
return false;
- }
if (host_status.first == HostStatus::kNoEligibleHosts)
return false;
- if (host_status.second.has_value())
+ if (host_status.second.has_value()) {
return IsEligibleHost(*(host_status.second));
+ }
for (const RemoteDeviceRef& device : remote_devices) {
if (IsEligibleHost(device))
return true;
@@ -73,8 +73,10 @@
phone_hub_manager->GetFeatureStatusProvider()),
device_sync_client_(device_sync_client),
multidevice_setup_client_(multidevice_setup_client),
- connection_manager_(connection_manager) {
- status_ = ComputeStatus();
+ connection_manager_(connection_manager),
+ current_phone_hub_feature_status_(
+ phone_hub_feature_status_provider_->GetStatus()),
+ status_(ComputeStatus()) {
phone_hub_feature_status_provider_->AddObserver(this);
connection_manager_->AddObserver(this);
multidevice_setup_client_->AddObserver(this);
diff --git a/chromeos/components/eche_app_ui/eche_feature_status_provider.h b/chromeos/components/eche_app_ui/eche_feature_status_provider.h
index d6e8b2e..7efc63a7 100644
--- a/chromeos/components/eche_app_ui/eche_feature_status_provider.h
+++ b/chromeos/components/eche_app_ui/eche_feature_status_provider.h
@@ -60,9 +60,8 @@
device_sync::DeviceSyncClient* device_sync_client_;
multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client_;
secure_channel::ConnectionManager* connection_manager_;
-
- base::Optional<FeatureStatus> status_;
phonehub::FeatureStatus current_phone_hub_feature_status_;
+ base::Optional<FeatureStatus> status_;
base::WeakPtrFactory<EcheFeatureStatusProvider> weak_ptr_factory_{this};
};
diff --git a/chromeos/components/eche_app_ui/eche_feature_status_provider_unittest.cc b/chromeos/components/eche_app_ui/eche_feature_status_provider_unittest.cc
new file mode 100644
index 0000000..d20638e
--- /dev/null
+++ b/chromeos/components/eche_app_ui/eche_feature_status_provider_unittest.cc
@@ -0,0 +1,244 @@
+// Copyright 2021 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 "chromeos/components/eche_app_ui/eche_feature_status_provider.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/test/task_environment.h"
+#include "chromeos/components/multidevice/remote_device_test_util.h"
+#include "chromeos/components/phonehub/fake_phone_hub_manager.h"
+#include "chromeos/components/phonehub/phone_hub_manager.h"
+#include "chromeos/services/device_sync/public/cpp/fake_device_sync_client.h"
+#include "chromeos/services/multidevice_setup/public/cpp/fake_multidevice_setup_client.h"
+#include "chromeos/services/secure_channel/public/cpp/client/fake_connection_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+namespace eche_app {
+namespace {
+
+using multidevice_setup::mojom::Feature;
+using multidevice_setup::mojom::FeatureState;
+using multidevice_setup::mojom::HostStatus;
+
+multidevice::RemoteDeviceRef CreateLocalDevice(bool supports_eche_client) {
+ multidevice::RemoteDeviceRefBuilder builder;
+ builder.SetSoftwareFeatureState(
+ multidevice::SoftwareFeature::kEcheClient,
+ supports_eche_client ? multidevice::SoftwareFeatureState::kSupported
+ : multidevice::SoftwareFeatureState::kNotSupported);
+ return builder.Build();
+}
+
+multidevice::RemoteDeviceRef CreatePhoneDevice(bool supports_eche_host) {
+ multidevice::RemoteDeviceRefBuilder builder;
+ builder.SetSoftwareFeatureState(
+ multidevice::SoftwareFeature::kBetterTogetherHost,
+ multidevice::SoftwareFeatureState::kSupported);
+ builder.SetSoftwareFeatureState(
+ multidevice::SoftwareFeature::kEcheHost,
+ supports_eche_host ? multidevice::SoftwareFeatureState::kSupported
+ : multidevice::SoftwareFeatureState::kNotSupported);
+ return builder.Build();
+}
+
+class FakeObserver : public FeatureStatusProvider::Observer {
+ public:
+ FakeObserver() = default;
+ ~FakeObserver() override = default;
+
+ size_t num_calls() const { return num_calls_; }
+
+ // FeatureStatusProvider::Observer:
+ void OnFeatureStatusChanged() override { ++num_calls_; }
+
+ private:
+ size_t num_calls_ = 0;
+};
+
+} // namespace
+
+class EcheFeatureStatusProviderTest : public testing::Test {
+ protected:
+ EcheFeatureStatusProviderTest() = default;
+ EcheFeatureStatusProviderTest(const EcheFeatureStatusProviderTest&) = delete;
+ EcheFeatureStatusProviderTest& operator=(
+ const EcheFeatureStatusProviderTest&) = delete;
+ ~EcheFeatureStatusProviderTest() override = default;
+
+ // testing::Test:
+ void SetUp() override {
+ fake_device_sync_client_.NotifyReady();
+ fake_phone_hub_manager.fake_feature_status_provider()->SetStatus(
+ phonehub::FeatureStatus::kEnabledAndConnected);
+ provider_ = std::make_unique<EcheFeatureStatusProvider>(
+ &fake_phone_hub_manager, &fake_device_sync_client_,
+ &fake_multidevice_setup_client_, &fake_connection_manager_);
+ provider_->AddObserver(&fake_observer_);
+ }
+
+ void SetSyncedDevices(
+ const base::Optional<multidevice::RemoteDeviceRef>& local_device,
+ const std::vector<base::Optional<multidevice::RemoteDeviceRef>>
+ phone_devices) {
+ fake_device_sync_client_.set_local_device_metadata(local_device);
+
+ multidevice::RemoteDeviceRefList synced_devices;
+ if (local_device)
+ synced_devices.push_back(*local_device);
+ for (const auto& phone_device : phone_devices) {
+ if (phone_device)
+ synced_devices.push_back(*phone_device);
+ }
+ fake_device_sync_client_.set_synced_devices(synced_devices);
+
+ fake_device_sync_client_.NotifyNewDevicesSynced();
+ }
+
+ void SetEligibleSyncedDevices() {
+ SetSyncedDevices(CreateLocalDevice(/*supports_eche_client=*/true),
+ {CreatePhoneDevice(/*supports_eche_host=*/true)});
+ }
+
+ void SetMultiDeviceState(HostStatus host_status,
+ FeatureState feature_state,
+ bool supports_eche) {
+ fake_multidevice_setup_client_.SetHostStatusWithDevice(
+ std::make_pair(host_status, CreatePhoneDevice(supports_eche)));
+ fake_multidevice_setup_client_.SetFeatureState(Feature::kEche,
+ feature_state);
+ }
+
+ void SetHostStatusWithDevice(
+ HostStatus host_status,
+ const base::Optional<multidevice::RemoteDeviceRef>& host_device) {
+ fake_multidevice_setup_client_.SetHostStatusWithDevice(
+ std::make_pair(host_status, host_device));
+ }
+
+ void SetConnectionStatus(secure_channel::ConnectionManager::Status status) {
+ fake_connection_manager_.SetStatus(status);
+ }
+
+ void SetFeatureState(FeatureState feature_state) {
+ fake_multidevice_setup_client_.SetFeatureState(Feature::kEche,
+ feature_state);
+ }
+
+ FeatureStatus GetStatus() const { return provider_->GetStatus(); }
+
+ size_t GetNumObserverCalls() const { return fake_observer_.num_calls(); }
+
+ private:
+ base::test::TaskEnvironment task_environment_;
+
+ device_sync::FakeDeviceSyncClient fake_device_sync_client_;
+ multidevice_setup::FakeMultiDeviceSetupClient fake_multidevice_setup_client_;
+ secure_channel::FakeConnectionManager fake_connection_manager_;
+
+ phonehub::FakePhoneHubManager fake_phone_hub_manager;
+ FakeObserver fake_observer_;
+ std::unique_ptr<EcheFeatureStatusProvider> provider_;
+};
+
+// Tests conditions for kIneligible status, including missing local
+// device and/or phone and various missing properties of these devices.
+TEST_F(EcheFeatureStatusProviderTest, IneligibleForFeature) {
+ SetSyncedDevices(/*local_device=*/base::nullopt,
+ /*phone_devices=*/{base::nullopt});
+ EXPECT_EQ(FeatureStatus::kIneligible, GetStatus());
+
+ SetSyncedDevices(CreateLocalDevice(/*supports_eche_client=*/false),
+ /*phone_devices=*/{base::nullopt});
+ EXPECT_EQ(FeatureStatus::kIneligible, GetStatus());
+
+ SetSyncedDevices(CreateLocalDevice(/*supports_eche_client=*/true),
+ /*phone_devices=*/{base::nullopt});
+ EXPECT_EQ(FeatureStatus::kIneligible, GetStatus());
+
+ SetSyncedDevices(CreateLocalDevice(/*supports_eche_client=*/true),
+ {CreatePhoneDevice(/*supports_eche_host=*/false)});
+ EXPECT_EQ(FeatureStatus::kIneligible, GetStatus());
+
+ // Set all properties to true so that there is an eligible phone. Since
+ // |fake_multidevice_setup_client_| defaults to kProhibitedByPolicy, the
+ // status should still be kIneligible.
+ SetSyncedDevices(CreateLocalDevice(/*supports_eche_client=*/true),
+ {CreatePhoneDevice(/*supports_eche_host=*/true)});
+ EXPECT_EQ(FeatureStatus::kIneligible, GetStatus());
+}
+
+TEST_F(EcheFeatureStatusProviderTest, NoEligiblePhones) {
+ SetMultiDeviceState(HostStatus::kNoEligibleHosts,
+ FeatureState::kUnavailableNoVerifiedHost,
+ /*supports_eche_host=*/true);
+ EXPECT_EQ(FeatureStatus::kIneligible, GetStatus());
+}
+
+TEST_F(EcheFeatureStatusProviderTest, Disabled) {
+ SetEligibleSyncedDevices();
+
+ SetMultiDeviceState(HostStatus::kHostVerified, FeatureState::kDisabledByUser,
+ /*supports_eche_host=*/true);
+ EXPECT_EQ(FeatureStatus::kDisabled, GetStatus());
+
+ SetMultiDeviceState(HostStatus::kHostVerified,
+ FeatureState::kUnavailableSuiteDisabled,
+ /*supports_eche_host=*/true);
+ EXPECT_EQ(FeatureStatus::kDisabled, GetStatus());
+
+ SetMultiDeviceState(HostStatus::kHostVerified,
+ FeatureState::kUnavailableTopLevelFeatureDisabled,
+ /*supports_eche_host=*/true);
+ EXPECT_EQ(FeatureStatus::kDisabled, GetStatus());
+}
+
+TEST_F(EcheFeatureStatusProviderTest, TransitionBetweenAllStatuses) {
+ EXPECT_EQ(FeatureStatus::kIneligible, GetStatus());
+
+ SetMultiDeviceState(HostStatus::kNoEligibleHosts,
+ FeatureState::kUnavailableNoVerifiedHost,
+ /*supports_eche_host=*/true);
+ EXPECT_EQ(FeatureStatus::kIneligible, GetStatus());
+ EXPECT_EQ(0u, GetNumObserverCalls());
+
+ SetMultiDeviceState(HostStatus::kEligibleHostExistsButNoHostSet,
+ FeatureState::kUnavailableNoVerifiedHost,
+ /*supports_eche_host=*/true);
+ SetEligibleSyncedDevices();
+ EXPECT_EQ(FeatureStatus::kIneligible, GetStatus());
+ EXPECT_EQ(0u, GetNumObserverCalls());
+
+ SetMultiDeviceState(HostStatus::kHostSetButNotYetVerified,
+ FeatureState::kNotSupportedByPhone,
+ /*supports_eche_host=*/true);
+ EXPECT_EQ(FeatureStatus::kDisconnected, GetStatus());
+ EXPECT_EQ(1u, GetNumObserverCalls());
+
+ SetMultiDeviceState(HostStatus::kHostVerified, FeatureState::kDisabledByUser,
+ /*supports_eche_host=*/true);
+ EXPECT_EQ(FeatureStatus::kDisabled, GetStatus());
+ EXPECT_EQ(2u, GetNumObserverCalls());
+
+ SetMultiDeviceState(HostStatus::kHostVerified, FeatureState::kEnabledByUser,
+ /*supports_eche_host=*/true);
+ EXPECT_EQ(3u, GetNumObserverCalls());
+ SetConnectionStatus(secure_channel::ConnectionManager::Status::kConnecting);
+ EXPECT_EQ(FeatureStatus::kConnecting, GetStatus());
+ EXPECT_EQ(4u, GetNumObserverCalls());
+
+ SetConnectionStatus(secure_channel::ConnectionManager::Status::kConnected);
+ EXPECT_EQ(FeatureStatus::kConnected, GetStatus());
+ EXPECT_EQ(5u, GetNumObserverCalls());
+
+ SetConnectionStatus(secure_channel::ConnectionManager::Status::kDisconnected);
+ EXPECT_EQ(FeatureStatus::kDisconnected, GetStatus());
+ EXPECT_EQ(6u, GetNumObserverCalls());
+}
+
+} // namespace eche_app
+} // namespace chromeos
diff --git a/chromeos/components/eche_app_ui/eche_signaler.cc b/chromeos/components/eche_app_ui/eche_signaler.cc
new file mode 100644
index 0000000..9a3f298
--- /dev/null
+++ b/chromeos/components/eche_app_ui/eche_signaler.cc
@@ -0,0 +1,43 @@
+// Copyright 2021 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 "chromeos/components/eche_app_ui/eche_signaler.h"
+
+namespace chromeos {
+namespace eche_app {
+
+EcheSignaler::EcheSignaler(
+ EcheConnector* eche_connector,
+ secure_channel::ConnectionManager* connection_manager)
+ : eche_connector_(eche_connector), connection_manager_(connection_manager) {
+ connection_manager_->AddObserver(this);
+}
+
+EcheSignaler::~EcheSignaler() {
+ connection_manager_->RemoveObserver(this);
+}
+
+void EcheSignaler::SendSignalingMessage(const std::vector<uint8_t>& signal) {
+ std::string encoded_signal(signal.begin(), signal.end());
+ eche_connector_->SendMessage(encoded_signal);
+}
+
+void EcheSignaler::SetSignalingMessageObserver(
+ mojo::PendingRemote<mojom::SignalingMessageObserver> observer) {
+ observer_.Bind(std::move(observer));
+}
+
+void EcheSignaler::Bind(
+ mojo::PendingReceiver<mojom::SignalingMessageExchanger> receiver) {
+ exchanger_.Bind(std::move(receiver));
+}
+
+void EcheSignaler::OnMessageReceived(const std::string& payload) {
+ std::vector<uint8_t> encoded_payload(payload.begin(), payload.end());
+ if (observer_)
+ std::move(observer_)->OnReceivedSignalingMessage(encoded_payload);
+}
+
+} // namespace eche_app
+} // namespace chromeos
diff --git a/chromeos/components/eche_app_ui/eche_signaler.h b/chromeos/components/eche_app_ui/eche_signaler.h
new file mode 100644
index 0000000..fee852a
--- /dev/null
+++ b/chromeos/components/eche_app_ui/eche_signaler.h
@@ -0,0 +1,50 @@
+// Copyright 2021 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.
+
+#ifndef CHROMEOS_COMPONENTS_ECHE_APP_UI_ECHE_SIGNALER_H_
+#define CHROMEOS_COMPONENTS_ECHE_APP_UI_ECHE_SIGNALER_H_
+
+#include "chromeos/components/eche_app_ui/eche_connector.h"
+#include "chromeos/components/eche_app_ui/mojom/eche_app.mojom.h"
+#include "chromeos/services/secure_channel/public/cpp/client/connection_manager.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/bindings/remote_set.h"
+
+namespace chromeos {
+namespace eche_app {
+
+class EcheSignaler : public mojom::SignalingMessageExchanger,
+ public secure_channel::ConnectionManager::Observer {
+ public:
+ EcheSignaler(EcheConnector* eche_connector,
+ secure_channel::ConnectionManager* connection_manager);
+ ~EcheSignaler() override;
+
+ EcheSignaler(const EcheSignaler&) = delete;
+ EcheSignaler& operator=(const EcheSignaler&) = delete;
+
+ // mojom::SignalingMessageExchanger:
+ void SendSignalingMessage(const std::vector<uint8_t>& signal) override;
+ void SetSignalingMessageObserver(
+ mojo::PendingRemote<mojom::SignalingMessageObserver> observer) override;
+
+ void Bind(mojo::PendingReceiver<mojom::SignalingMessageExchanger> receiver);
+
+ private:
+ // secure_channel::ConnectionManager::Observer:
+ void OnMessageReceived(const std::string& payload) override;
+
+ EcheConnector* eche_connector_;
+ secure_channel::ConnectionManager* connection_manager_;
+ mojo::Remote<mojom::SignalingMessageObserver> observer_;
+ mojo::Receiver<mojom::SignalingMessageExchanger> exchanger_{this};
+};
+
+} // namespace eche_app
+} // namespace chromeos
+
+#endif // CHROMEOS_COMPONENTS_ECHE_APP_UI_ECHE_SIGNALER_H_
diff --git a/chromeos/components/eche_app_ui/mojom/BUILD.gn b/chromeos/components/eche_app_ui/mojom/BUILD.gn
new file mode 100644
index 0000000..3b50430
--- /dev/null
+++ b/chromeos/components/eche_app_ui/mojom/BUILD.gn
@@ -0,0 +1,9 @@
+# Copyright 2021 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.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojom") {
+ sources = [ "eche_app.mojom" ]
+}
diff --git a/chromeos/components/eche_app_ui/mojom/OWNERS b/chromeos/components/eche_app_ui/mojom/OWNERS
new file mode 100644
index 0000000..08850f4
--- /dev/null
+++ b/chromeos/components/eche_app_ui/mojom/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromeos/components/eche_app_ui/mojom/eche_app.mojom b/chromeos/components/eche_app_ui/mojom/eche_app.mojom
new file mode 100644
index 0000000..a85a8d4
--- /dev/null
+++ b/chromeos/components/eche_app_ui/mojom/eche_app.mojom
@@ -0,0 +1,24 @@
+// Copyright 2021 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.
+
+module chromeos.eche_app.mojom;
+
+// Interface for sending signal messages from the SWA to the browser. The
+// signals are used to bootstrap a full WebRTC connection between a Nearby
+// endpoint and the SWA. Any further data exchange happens directly over the
+// WebRTC connection.
+interface SignalingMessageExchanger {
+ // Called when a new signaling message is ready for transmission. The
+ // `signal` is a serialized WebRtcSignal.
+ SendSignalingMessage(array<uint8> signal);
+ // Sets the listener for replies sent from the browser process to the SWA.
+ SetSignalingMessageObserver(
+ pending_remote<SignalingMessageObserver> observer);
+};
+
+// Interface for dispatching response signaling messages as they are received.
+interface SignalingMessageObserver {
+ // Dispatch message to recipient. The `signal` is a serialized WebRtcSignal.
+ OnReceivedSignalingMessage(array<uint8> signal);
+};