Commit 1d29be74 authored by Kevin Marshall's avatar Kevin Marshall Committed by Commit Bot

[Fuchsia] Remove touch APIs and stubs from Cast Runner.

Deletes all remaining Cast APIs from the Cast Runner codebase.

Bug: 953958
Change-Id: Ia715e9c972735f11d29978925a2199356e4d1d7f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1793791
Commit-Queue: Kevin Marshall <kmarshall@chromium.org>
Reviewed-by: default avatarSergey Ulanov <sergeyu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#702250}
parent dfc62572
...@@ -16,11 +16,7 @@ table ApplicationConfig { ...@@ -16,11 +16,7 @@ table ApplicationConfig {
/// implementation. /// implementation.
3: string web_url; 3: string web_url;
/// Touch input policy to be applied to the application. 4: reserved;
/// If true, then touch input is forced on.
/// If false, then touch input is disabled.
/// If unset, then the caller is allowed to enable or disable input.
4: bool touch_enabled_policy;
// If true, enable remote debugging for this application. // If true, enable remote debugging for this application.
// if false or unset, remote debugging is disabled for this application. // if false or unset, remote debugging is disabled for this application.
......
...@@ -61,17 +61,10 @@ source_set("cast_runner_core") { ...@@ -61,17 +61,10 @@ source_set("cast_runner_core") {
"cast/application_controller_impl.h", "cast/application_controller_impl.h",
"cast/cast_component.cc", "cast/cast_component.cc",
"cast/cast_component.h", "cast/cast_component.h",
"cast/cast_platform_bindings_ids.h",
"cast/cast_runner.cc", "cast/cast_runner.cc",
"cast/cast_runner.h", "cast/cast_runner.h",
"cast/named_message_port_connector.cc", "cast/named_message_port_connector.cc",
"cast/named_message_port_connector.h", "cast/named_message_port_connector.h",
"cast/touch_input_bindings.cc",
"cast/touch_input_bindings.h",
]
data = [
"cast/not_implemented_api_bindings.js",
"cast/touch_input_bindings.js",
] ]
data_deps = [ data_deps = [
"//chromecast/bindings:named_message_port_connector_resources", "//chromecast/bindings:named_message_port_connector_resources",
...@@ -187,7 +180,6 @@ test("cast_runner_browsertests") { ...@@ -187,7 +180,6 @@ test("cast_runner_browsertests") {
sources = [ sources = [
"cast/api_bindings_client_browsertest.cc", "cast/api_bindings_client_browsertest.cc",
"cast/named_message_port_connector_browsertest.cc", "cast/named_message_port_connector_browsertest.cc",
"cast/not_implemented_api_bindings_browsertest.cc",
] ]
defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
data = [ data = [
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include "base/path_service.h" #include "base/path_service.h"
#include "fuchsia/base/mem_buffer_util.h" #include "fuchsia/base/mem_buffer_util.h"
#include "fuchsia/fidl/chromium/cast/cpp/fidl.h" #include "fuchsia/fidl/chromium/cast/cpp/fidl.h"
#include "fuchsia/runners/cast/cast_platform_bindings_ids.h"
#include "fuchsia/runners/cast/cast_runner.h" #include "fuchsia/runners/cast/cast_runner.h"
#include "fuchsia/runners/common/web_component.h" #include "fuchsia/runners/common/web_component.h"
...@@ -23,20 +22,6 @@ namespace { ...@@ -23,20 +22,6 @@ namespace {
constexpr int kBindingsFailureExitCode = 129; constexpr int kBindingsFailureExitCode = 129;
constexpr int kRewriteRulesProviderDisconnectExitCode = 130; constexpr int kRewriteRulesProviderDisconnectExitCode = 130;
constexpr char kStubBindingsPath[] =
FILE_PATH_LITERAL("fuchsia/runners/cast/not_implemented_api_bindings.js");
TouchInputPolicy TouchInputPolicyFromApplicationConfig(
const chromium::cast::ApplicationConfig& application_config) {
if (!application_config.has_touch_enabled_policy())
return TouchInputPolicy::UNSPECIFIED;
if (application_config.touch_enabled_policy())
return TouchInputPolicy::FORCE_ENABLE;
return TouchInputPolicy::FORCE_DISABLE;
}
} // namespace } // namespace
CastComponent::CastComponentParams::CastComponentParams() = default; CastComponent::CastComponentParams::CastComponentParams() = default;
...@@ -52,8 +37,6 @@ CastComponent::CastComponent(CastRunner* runner, ...@@ -52,8 +37,6 @@ CastComponent::CastComponent(CastRunner* runner,
agent_manager_(std::move(params.agent_manager)), agent_manager_(std::move(params.agent_manager)),
application_config_(std::move(params.app_config)), application_config_(std::move(params.app_config)),
rewrite_rules_provider_(std::move(params.rewrite_rules_provider)), rewrite_rules_provider_(std::move(params.rewrite_rules_provider)),
touch_input_policy_(
TouchInputPolicyFromApplicationConfig(application_config_)),
connector_(frame()), connector_(frame()),
api_bindings_client_(std::move(params.api_bindings_client)), api_bindings_client_(std::move(params.api_bindings_client)),
navigation_listener_binding_(this) { navigation_listener_binding_(this) {
...@@ -81,8 +64,6 @@ CastComponent::CastComponent(CastRunner* runner, ...@@ -81,8 +64,6 @@ CastComponent::CastComponent(CastRunner* runner,
frame(), agent_manager_->ConnectToAgentService< frame(), agent_manager_->ConnectToAgentService<
chromium::cast::ApplicationControllerReceiver>( chromium::cast::ApplicationControllerReceiver>(
CastRunner::kAgentComponentUrl)); CastRunner::kAgentComponentUrl));
InitializeCastPlatformBindings();
} }
CastComponent::~CastComponent() = default; CastComponent::~CastComponent() = default;
...@@ -109,22 +90,3 @@ void CastComponent::OnNavigationStateChanged( ...@@ -109,22 +90,3 @@ void CastComponent::OnNavigationStateChanged(
connector_.OnPageLoad(); connector_.OnPageLoad();
callback(); callback();
} }
void CastComponent::InitializeCastPlatformBindings() {
base::FilePath stub_path;
CHECK(base::PathService::Get(base::DIR_ASSETS, &stub_path));
stub_path = stub_path.AppendASCII(kStubBindingsPath);
DCHECK(base::PathExists(stub_path));
fuchsia::mem::Buffer stub_buf = cr_fuchsia::MemBufferFromFile(
base::File(stub_path, base::File::FLAG_OPEN | base::File::FLAG_READ));
CHECK(stub_buf.vmo);
frame()->AddBeforeLoadJavaScript(
static_cast<uint64_t>(CastPlatformBindingsId::NOT_IMPLEMENTED_API), {"*"},
std::move(stub_buf),
[](fuchsia::web::Frame_AddBeforeLoadJavaScript_Result result) {
CHECK(result.is_response()) << "Couldn't inject stub bindings.";
});
touch_input_ = std::make_unique<TouchInputBindings>(touch_input_policy_,
frame(), &connector_);
}
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include "fuchsia/runners/cast/api_bindings_client.h" #include "fuchsia/runners/cast/api_bindings_client.h"
#include "fuchsia/runners/cast/application_controller_impl.h" #include "fuchsia/runners/cast/application_controller_impl.h"
#include "fuchsia/runners/cast/named_message_port_connector.h" #include "fuchsia/runners/cast/named_message_port_connector.h"
#include "fuchsia/runners/cast/touch_input_bindings.h"
#include "fuchsia/runners/common/web_component.h" #include "fuchsia/runners/common/web_component.h"
class CastRunner; class CastRunner;
...@@ -66,9 +65,7 @@ class CastComponent : public WebComponent, ...@@ -66,9 +65,7 @@ class CastComponent : public WebComponent,
chromium::cast::UrlRequestRewriteRulesProviderPtr rewrite_rules_provider_; chromium::cast::UrlRequestRewriteRulesProviderPtr rewrite_rules_provider_;
bool constructor_active_ = false; bool constructor_active_ = false;
TouchInputPolicy touch_input_policy_;
NamedMessagePortConnector connector_; NamedMessagePortConnector connector_;
std::unique_ptr<TouchInputBindings> touch_input_;
std::unique_ptr<ApiBindingsClient> api_bindings_client_; std::unique_ptr<ApiBindingsClient> api_bindings_client_;
std::unique_ptr<ApplicationControllerImpl> application_controller_; std::unique_ptr<ApplicationControllerImpl> application_controller_;
......
// Copyright 2019 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.
// Stub definitions of Cast Platform API functions.
if (!cast)
var cast = {};
if (!cast.__platform__)
cast.__platform__ = {};
// Don't clobber the API stubs if they were previously injected.
if (!cast.__platform__._notImplemented) {
// Determines how a value is returned to the caller of a stub function.
cast.__platform__.ReturnType = {
// The value is returned immediately by the function.
RETURN_VALUE: 0,
// The value is returned as a resolved Promise.
PROMISE_RESOLVED: 1,
// The value is returned as a rejected Promise.
PROMISE_REJECTED: 2,
// The value is passed as an argument list to the callback provided by the
// caller.
CALLBACK: 3
};
// Returns a stub function that logs messages to the console when called, and
// optionally returns a dummy value to the caller.
//
// |returnType|: specifies the mechanism for how |returnValue| is passed back
// to the caller.
cast.__platform__._notImplemented = function(functionName, returnValue,
returnType) {
return function(...args) {
console.log('Unimplemented stub function called: cast.__platform__.' +
functionName + '(' + args.map(JSON.stringify).join(', ') + ')');
if (!returnType ||
returnType == cast.__platform__.ReturnType.RETURN_VALUE) {
console.log('Returning ' + JSON.stringify(returnValue));
return returnValue;
} else if (returnType == cast.__platform__.ReturnType.PROMISE_RESOLVED) {
console.log('Returning promise ' + JSON.stringify(returnValue));
return Promise.resolve(returnValue);
} else if (returnType == cast.__platform__.ReturnType.PROMISE_REJECTED) {
console.log('Returning rejected promise ' +
JSON.stringify(returnValue));
return Promise.reject(returnValue);
} else if (returnType == cast.__platform__.ReturnType.CALLBACK) {
console.log('Returning via callback ' + JSON.stringify(returnValue));
args[0].apply(window, returnValue);
}
}
};
// TODO(b/139230885)
if (!cast.__platform__.canDisplayType) {
cast.__platform__.canDisplayType =
cast.__platform__._notImplemented('canDisplayType', true);
}
// TODO(b/139229713)
if (!cast.__platform__.setAssistantMessageHandler) {
cast.__platform__.setAssistantMessageHandler =
cast.__platform__._notImplemented('setAssistantMessageHandler');
}
if (!cast.__platform__.sendAssistantRequest) {
cast.__platform__.sendAssistantRequest =
cast.__platform__._notImplemented('sendAssistantRequest');
}
// TODO(b/139228475)
if (!cast.__platform__.setWindowRequestHandler) {
cast.__platform__.setWindowRequestHandler =
cast.__platform__._notImplemented('setWindowRequestHandler');
}
if (!cast.__platform__.takeScreenshot) {
cast.__platform__.takeScreenshot =
cast.__platform__._notImplemented('takeScreenshot');
}
// TODO(b/139232520)
if (!cast.__platform__.crypto) {
cast.__platform__.crypto = {};
cast.__platform__.crypto.encrypt =
cast.__platform__._notImplemented(
'crypto.encrypt',
new ArrayBuffer(0),
cast.__platform__.ReturnType.PROMISE_RESOLVED);
cast.__platform__.crypto.decrypt =
cast.__platform__._notImplemented(
'crypto.decrypt',
new ArrayBuffer(0),
cast.__platform__.ReturnType.PROMISE_RESOLVED);
cast.__platform__.crypto.sign =
cast.__platform__._notImplemented(
'crypto.sign',
new ArrayBuffer(0),
cast.__platform__.ReturnType.PROMISE_RESOLVED);
cast.__platform__.crypto.unwrapKey =
cast.__platform__._notImplemented(
'crypto.unwrapKey',
undefined,
cast.__platform__.ReturnType.PROMISE_REJECTED);
cast.__platform__.crypto.verify =
cast.__platform__._notImplemented(
'crypto.verify',
true,
cast.__platform__.ReturnType.PROMISE_RESOLVED);
cast.__platform__.crypto.wrapKey =
cast.__platform__._notImplemented(
'crypto.wrapKey',
undefined,
cast.__platform__.ReturnType.PROMISE_REJECTED);
}
if (!cast.__platform__.cryptokeys) {
cast.__platform__.cryptokeys = {};
cast.__platform__.cryptokeys.getKeyByName =
cast.__platform__._notImplemented(
'cryptokeys.getKeyByName',
'',
cast.__platform__.ReturnType.PROMISE_REJECTED);
}
// TODO(b/139232101)
if (!cast.__platform__.display) {
cast.__platform__.display = {};
cast.__platform__.display.updateOutputMode =
cast.__platform__._notImplemented(
'display.updateOutputMode',
Promise.resolve(),
cast.__platform__.ReturnType.PROMISE_RESOLVED);
cast.__platform__.display.getHdcpVersion =
cast.__platform__._notImplemented(
'display.getHdcpVersion',
'0',
cast.__platform__.ReturnType.PROMISE_RESOLVED);
}
// TODO(b/139232160)
if (!cast.__platform__.accessibility) {
cast.__platform__.accessibility = {};
cast.__platform__.accessibility.getAccessibilitySettings =
cast.__platform__._notImplemented(
'accessibility.getAccessibilitySettings',
{isColorInversionEnabled: false, isScreenReaderEnabled: false},
cast.__platform__.ReturnType.PROMISE_RESOLVED);
cast.__platform__.accessibility.setColorInversion =
cast.__platform__._notImplemented(
'accessibility.setColorInversion');
cast.__platform__.accessibility.setMagnificationGesture =
cast.__platform__._notImplemented(
'accessibility.setMagnificationGesture');
}
// TODO(b/139229752)
if (!cast.__platform__.windowManager) {
cast.__platform__.windowManager = {};
cast.__platform__.windowManager.onBackGesture =
cast.__platform__._notImplemented('windowManager.onBackGesture',
undefined,
cast.__platform__.ReturnType.CALLBACK);
cast.__platform__.windowManager.onBackGestureProgress =
cast.__platform__._notImplemented('windowManager.onBackGestureProgress',
[0],
cast.__platform__.ReturnType.CALLBACK);
cast.__platform__.windowManager.onBackGestureCancel =
cast.__platform__._notImplemented('windowManager.onBackGestureCancel',
undefined,
cast.__platform__.ReturnType.CALLBACK);
cast.__platform__.windowManager.onTopDragGestureDone =
cast.__platform__._notImplemented('windowManager.onTopDragGestureDone',
undefined,
cast.__platform__.ReturnType.CALLBACK);
cast.__platform__.windowManager.onTopDragGestureProgress =
cast.__platform__._notImplemented(
'windowManager.onTopDragGestureProgress',
[0],
cast.__platform__.ReturnType.CALLBACK);
cast.__platform__.windowManager.onTapGesture =
cast.__platform__._notImplemented('windowManager.onTapGesture',
undefined,
cast.__platform__.ReturnType.CALLBACK);
cast.__platform__.windowManager.onTapDownGesture =
cast.__platform__._notImplemented('windowManager.onTapDownGesture',
undefined,
cast.__platform__.ReturnType.CALLBACK);
cast.__platform__.windowManager.canTopDrag =
cast.__platform__._notImplemented('windowManager.canTopDrag', false);
cast.__platform__.windowManager.canGoBack =
cast.__platform__._notImplemented('windowManager.canGoBack', false);
cast.__platform__.windowManager.onRightDragGestureDone =
cast.__platform__._notImplemented(
'windowManager.onRightDragGestureDone',
undefined,
cast.__platform__.ReturnType.CALLBACK);
cast.__platform__.windowManager.onRightDragGestureProgress =
cast.__platform__._notImplemented(
'windowManager.onRightDragGestureProgress',
[0, 0],
cast.__platform__.ReturnType.CALLBACK);
cast.__platform__.windowManager.canRightDrag =
cast.__platform__._notImplemented(
'windowManager.canRightDrag', false);
}
}
// Copyright 2019 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 <lib/fidl/cpp/binding.h>
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/macros.h"
#include "base/path_service.h"
#include "base/test/bind_test_util.h"
#include "base/test/test_timeouts.h"
#include "base/threading/thread_restrictions.h"
#include "fuchsia/base/fit_adapter.h"
#include "fuchsia/base/frame_test_util.h"
#include "fuchsia/base/mem_buffer_util.h"
#include "fuchsia/base/result_receiver.h"
#include "fuchsia/base/test_navigation_listener.h"
#include "fuchsia/engine/browser/frame_impl.h"
#include "fuchsia/engine/test/web_engine_browser_test.h"
#include "fuchsia/runners/cast/cast_platform_bindings_ids.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
constexpr char kUnimplementedLogMessage[] =
"Unimplemented stub function called: cast.__platform__.";
constexpr char kStubBindingsPath[] =
FILE_PATH_LITERAL("fuchsia/runners/cast/not_implemented_api_bindings.js");
class StubBindingsTest : public cr_fuchsia::WebEngineBrowserTest {
public:
StubBindingsTest()
: run_timeout_(TestTimeouts::action_timeout(),
base::MakeExpectedNotRunClosure(FROM_HERE)) {
set_test_server_root(base::FilePath("fuchsia/runners/cast/testdata"));
navigation_listener_.SetBeforeAckHook(base::BindRepeating(
&StubBindingsTest::OnBeforeAckHook, base::Unretained(this)));
}
~StubBindingsTest() override = default;
protected:
void SetUpOnMainThread() override {
cr_fuchsia::WebEngineBrowserTest::SetUpOnMainThread();
base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(embedded_test_server()->Start());
frame_ = WebEngineBrowserTest::CreateFrame(&navigation_listener_);
FrameImpl* frame_impl = context_impl()->GetFrameImplForTest(&frame_);
frame_impl->set_javascript_console_message_hook_for_test(
base::BindRepeating(&StubBindingsTest::OnLogMessage,
base::Unretained(this)));
frame_->SetJavaScriptLogLevel(fuchsia::web::ConsoleLogLevel::INFO);
base::FilePath stub_path;
CHECK(base::PathService::Get(base::DIR_ASSETS, &stub_path));
stub_path = stub_path.AppendASCII(kStubBindingsPath);
DCHECK(base::PathExists(stub_path));
fuchsia::mem::Buffer stub_buf = cr_fuchsia::MemBufferFromFile(
base::File(stub_path, base::File::FLAG_OPEN | base::File::FLAG_READ));
CHECK(stub_buf.vmo);
frame_->AddBeforeLoadJavaScript(
static_cast<uint64_t>(CastPlatformBindingsId::NOT_IMPLEMENTED_API),
{"*"}, std::move(stub_buf),
[](fuchsia::web::Frame_AddBeforeLoadJavaScript_Result result) {
ASSERT_TRUE(result.is_response());
});
fuchsia::web::NavigationControllerPtr controller;
frame_->GetNavigationController(controller.NewRequest());
const GURL page_url(embedded_test_server()->GetURL("/defaultresponse"));
EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
controller.get(), fuchsia::web::LoadUrlParams(), page_url.spec()));
navigation_listener_.RunUntilUrlEquals(page_url);
}
void OnLogMessage(base::StringPiece message) {
captured_logs_.push_back(message.as_string());
if (on_log_message_received_cb_)
std::move(on_log_message_received_cb_).Run();
}
// Processes tasks from the the message loop until the captured JavaScript log
// contains |message|.
void WaitForLogMessage(base::StringPiece expected_message) {
while (true) {
base::RunLoop run_loop;
on_log_message_received_cb_ = run_loop.QuitClosure();
run_loop.Run();
if (std::find_if(captured_logs_.begin(), captured_logs_.end(),
[expected_message = expected_message.as_string()](
const std::string& cur_string) {
return cur_string.find(expected_message) !=
std::string::npos;
}) != captured_logs_.end()) {
captured_logs_.clear();
return;
}
}
}
void OnBeforeAckHook(
const fuchsia::web::NavigationState& change,
fuchsia::web::NavigationEventListener::OnNavigationStateChangedCallback
callback) {
if (navigate_run_loop_)
navigate_run_loop_->Quit();
callback();
}
std::unique_ptr<base::RunLoop> navigate_run_loop_;
fuchsia::web::FramePtr frame_;
base::OnceClosure on_log_message_received_cb_;
cr_fuchsia::TestNavigationListener navigation_listener_;
// Stores accumulated log messages.
std::vector<std::string> captured_logs_;
private:
const base::RunLoop::ScopedRunTimeoutForTest run_timeout_;
DISALLOW_COPY_AND_ASSIGN(StubBindingsTest);
};
struct StubExpectation {
std::string function_name;
std::string result = "undefined";
};
IN_PROC_BROWSER_TEST_F(StubBindingsTest, ApiCoverage) {
// A list of APIs to exercise, along with the JSON representation of their
// expected output.
const std::vector<StubExpectation> kExpectations = {
{"canDisplayType", "true"},
{"setAssistantMessageHandler"},
{"sendAssistantRequest"},
{"setWindowRequestHandler"},
{"takeScreenshot"},
{"crypto.encrypt", "promise {}"},
{"crypto.decrypt", "promise {}"},
{"crypto.sign", "promise {}"},
{"crypto.unwrapKey", "rejected promise undefined"},
{"crypto.verify", "promise true"},
{"crypto.wrapKey", "rejected promise undefined"},
{"cryptokeys.getKeyByName", "rejected promise \"\""},
{"display.updateOutputMode", "promise {}"},
{"display.getHdcpVersion", "promise \"0\""},
{"accessibility.getAccessibilitySettings",
"promise {\"isColorInversionEnabled\":false,"
"\"isScreenReaderEnabled\":false}"},
{"accessibility.setColorInversion"},
{"accessibility.setMagnificationGesture"},
{"windowManager.onBackGesture", "via callback undefined"},
{"windowManager.onBackGestureProgress", "via callback [0]"},
{"windowManager.onBackGestureCancel", "via callback undefined"},
{"windowManager.onTopDragGestureDone", "via callback undefined"},
{"windowManager.onTopDragGestureProgress", "via callback [0]"},
{"windowManager.onTapGesture", "via callback undefined"},
{"windowManager.onTapDownGesture", "via callback undefined"},
{"windowManager.canTopDrag", "false"},
{"windowManager.canGoBack", "false"},
{"windowManager.onRightDragGestureDone", "via callback undefined"},
{"windowManager.onRightDragGestureProgress", "via callback [0,0]"},
{"windowManager.canRightDrag", "false"},
};
for (const auto& expectation : kExpectations) {
frame_->ExecuteJavaScriptNoResult(
{"*"},
cr_fuchsia::MemBufferFromString(
base::StringPrintf("try { cast.__platform__.%s(); } catch {}",
expectation.function_name.c_str()),
"test"),
[](fuchsia::web::Frame_ExecuteJavaScriptNoResult_Result result) {
ASSERT_TRUE(result.is_response());
});
WaitForLogMessage(base::StringPrintf("%s%s(", kUnimplementedLogMessage,
expectation.function_name.c_str()));
WaitForLogMessage(
base::StringPrintf("Returning %s", expectation.result.c_str()));
}
}
IN_PROC_BROWSER_TEST_F(StubBindingsTest, FunctionArgumentsInLogMessage) {
frame_->ExecuteJavaScriptNoResult(
{"*"},
cr_fuchsia::MemBufferFromString(
"cast.__platform__.sendAssistantRequest(1,2,'foo');", "test"),
[](fuchsia::web::Frame_ExecuteJavaScriptNoResult_Result result) {
ASSERT_TRUE(result.is_response());
});
WaitForLogMessage(base::StringPrintf("%ssendAssistantRequest(1, 2, \"foo\")",
kUnimplementedLogMessage));
}
} // namespace
// Copyright 2019 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 "fuchsia/runners/cast/touch_input_bindings.h"
#include <string>
#include <utility>
#include "base/base_paths_fuchsia.h"
#include "base/bind.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/path_service.h"
#include "fuchsia/base/mem_buffer_util.h"
#include "fuchsia/runners/cast/cast_platform_bindings_ids.h"
namespace {
constexpr char kMessagePortName[] = "cast.__platform__.__touchInput__";
constexpr char kRequestId[] = "requestId";
constexpr char kTouchEnabled[] = "touchEnabled";
constexpr char kDisplayControls[] = "displayControls";
} // namespace
TouchInputBindings::TouchInputBindings(TouchInputPolicy policy,
fuchsia::web::Frame* frame,
NamedMessagePortConnector* connector)
: policy_(policy), frame_(frame), connector_(connector) {
constexpr uint64_t kBindingsId =
static_cast<uint64_t>(CastPlatformBindingsId::TOUCH_INPUT);
DCHECK(frame_);
DCHECK(connector_);
connector_->Register(kMessagePortName,
base::BindRepeating(&TouchInputBindings::OnPortReceived,
base::Unretained(this)));
base::FilePath bindings_js_path;
CHECK(base::PathService::Get(base::DIR_ASSETS, &bindings_js_path));
bindings_js_path = bindings_js_path.AppendASCII(
"fuchsia/runners/cast/touch_input_bindings.js");
frame_->AddBeforeLoadJavaScript(
kBindingsId, {"*"},
cr_fuchsia::MemBufferFromFile(base::File(
bindings_js_path, base::File::FLAG_OPEN | base::File::FLAG_READ)),
[](fuchsia::web::Frame_AddBeforeLoadJavaScript_Result result) {
CHECK(result.is_response()) << "JavaScript injection error.";
});
}
TouchInputBindings::~TouchInputBindings() {
connector_->Unregister(kMessagePortName);
}
void TouchInputBindings::OnPortReceived(
fidl::InterfaceHandle<fuchsia::web::MessagePort> port) {
port_ = port.Bind();
ReadNextMessage();
}
void TouchInputBindings::ReadNextMessage() {
port_->ReceiveMessage(
fit::bind_member(this, &TouchInputBindings::OnControlMessageReceived));
}
void TouchInputBindings::OnControlMessageReceived(
fuchsia::web::WebMessage message) {
// Parse and validate the contents of |message|.
std::string message_data;
if (!cr_fuchsia::StringFromMemBuffer(message.data(), &message_data)) {
LOG(ERROR) << "Couldn't read payload from control message.";
port_.Unbind();
return;
}
base::Optional<base::Value> message_parsed;
message_parsed = base::JSONReader::Read(message_data);
if (!message_parsed || !message_parsed->is_dict()) {
LOG(ERROR) << "Invalid control message payload.";
port_.Unbind();
return;
}
base::Value* request_id_value = message_parsed->FindPath(kRequestId);
const base::Value* should_enable_touch_value =
message_parsed->FindPath(kTouchEnabled);
if (!request_id_value || !should_enable_touch_value) {
LOG(ERROR) << "Parameter dictionary missing required field(s).";
port_.Unbind();
return;
}
if (!request_id_value->is_int()) {
LOG(ERROR) << "requestId is not a number.";
port_.Unbind();
return;
}
if (!should_enable_touch_value->is_bool()) {
LOG(ERROR) << "touchEnabled is not a boolean.";
port_.Unbind();
return;
}
bool should_enable_touch;
base::Value response(base::Value::Type::DICTIONARY);
response.SetPath(kRequestId, std::move(*request_id_value));
switch (policy_) {
case TouchInputPolicy::FORCE_ENABLE:
// Touch is always enabled for whitelisted applications, regardless of
// what they specified in "touchEnabled".
should_enable_touch = true;
// Whitelisted applications should not show SDK-provided on-screen
// controls.
response.SetPath(kDisplayControls, base::Value(false));
break;
case TouchInputPolicy::FORCE_DISABLE:
// If the application is blacklisted, then reject the Promise by not
// setting a value in kDisplayControls.
should_enable_touch = false;
break;
case TouchInputPolicy::UNSPECIFIED:
// If no policy is specified for the application, then apply its requested
// state.
should_enable_touch = should_enable_touch_value->GetBool();
response.SetPath(kDisplayControls, base::Value(true));
break;
}
frame_->SetEnableInput(should_enable_touch);
// Send the acknowledgement message to JS.
std::string response_json;
CHECK(base::JSONWriter::Write(response, &response_json));
fuchsia::web::WebMessage response_message = {};
response_message.set_data(cr_fuchsia::MemBufferFromString(
response_json, "cast-touch-message-response"));
port_->PostMessage(std::move(response_message),
[](fuchsia::web::MessagePort_PostMessage_Result result) {
LOG_IF(ERROR, result.is_err())
<< "PostMessage failed, reason: "
<< static_cast<int>(result.err());
});
ReadNextMessage();
}
// Copyright 2019 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 FUCHSIA_RUNNERS_CAST_TOUCH_INPUT_BINDINGS_H_
#define FUCHSIA_RUNNERS_CAST_TOUCH_INPUT_BINDINGS_H_
#include <fuchsia/web/cpp/fidl.h>
#include "base/macros.h"
#include "fuchsia/runners/cast/named_message_port_connector.h"
enum class TouchInputPolicy {
UNSPECIFIED,
FORCE_ENABLE,
FORCE_DISABLE,
};
// Implements the native portions of the setTouchInputEnabled() Cast JS
// API.
class TouchInputBindings {
public:
// |policy|: Touch capabilities for the application declared by the
// ApplicationConfig service.
// |frame|: The Frame which is hosting the Cast application.
// Must outlive |this|.
// |connector|: Used to supply the messaging channel to the JS layer.
TouchInputBindings(TouchInputPolicy policy,
fuchsia::web::Frame* frame,
NamedMessagePortConnector* connector);
~TouchInputBindings();
private:
// Receives a MessagePort from the API.
void OnPortReceived(fidl::InterfaceHandle<fuchsia::web::MessagePort> port);
// Processes setTouchInputEnabled() calls.
void OnControlMessageReceived(fuchsia::web::WebMessage message);
void ReadNextMessage();
const TouchInputPolicy policy_;
fuchsia::web::Frame* const frame_;
NamedMessagePortConnector* const connector_;
fuchsia::web::MessagePortPtr port_;
DISALLOW_COPY_AND_ASSIGN(TouchInputBindings);
};
#endif // FUCHSIA_RUNNERS_CAST_TOUCH_INPUT_BINDINGS_H_
// Copyright 2019 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.
'use strict';
// Don't supercede an Agent-provided API function.
if (!cast.__platform__.setTouchInputSupport) {
cast.__platform__.__touchInput__ = new class {
constructor() {
this.port_ = cast.__platform__.PortConnector.bind(
'cast.__platform__.__touchInput__');
this.port_.onmessage = function(message) {
var responseParsed = JSON.parse(message.data);
if (responseParsed) {
this.onAck(responseParsed.requestId,
responseParsed.displayControls);
}
}.bind(this);
}
// Receives an acknowledgement from the native bindings layer and relays the
// result to the Promise.
onAck(requestId, displayControls) {
if (!this.pendingRequests_.hasOwnProperty(requestId)) {
console.error('Received ack for unknown request ID: ' + requestId);
return;
}
var request = this.pendingRequests_[requestId];
delete this.pendingRequests_[requestId];
if (displayControls === undefined) {
request.reject();
} else {
request.resolve({'displayControls': displayControls});
}
}
// Requests touch input support from the native bindings layer and returns a
// Promise with the result.
// If the request was successful, the Promise will be resolved with a
// dictionary indicating whether onscreen controls should be shown for the
// application.
// If the request was rejected, then the Promise will be rejected.
setTouchInputSupport(touchEnabled) {
return new Promise((resolve, reject) => {
var requestId = this.currentRequestId_++;
this.pendingRequests_[requestId] = {
'resolve': resolve,
'reject': reject,
};
this.port_.postMessage(JSON.stringify({
'requestId': requestId,
'touchEnabled': touchEnabled,
}));
});
}
// Port for sending requests and receiving acknowledgements with the native
// bindings layer.
port_ = null;
// A dictionary relating inflight request IDs to their Promise
// resolve/reject functions.
pendingRequests_ = {};
// Unique ID of the next request.
currentRequestId_ = 0;
};
cast.__platform__.setTouchInputSupport =
cast.__platform__.__touchInput__.setTouchInputSupport.bind(
cast.__platform__.__touchInput__);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment