blob: a592121e5b4295b9b80bfe9b3532563449698ed2 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromecast/renderer/settings_ui_bindings.h"
#include <array>
#include <tuple>
#include "base/check.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "content/public/renderer/render_frame.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h"
#include "third_party/blink/public/web/web_local_frame.h"
namespace chromecast {
namespace shell {
namespace {
const int64_t kDelayBetweenReconnectionInMillis = 100;
const char kSettingsUiName[] = "settings_ui";
const char kSetSideSwipeHandler[] = "setSideSwipeHandler";
const char kSetPlatformInfoHandler[] = "setPlatformInfoHandler";
const char kRequestVisible[] = "requestVisible";
} // namespace
SettingsUiBindings::SettingsUiBindings(content::RenderFrame* frame)
: CastBinding(frame), binding_(this), weak_factory_(this) {
ReconnectMojo();
}
SettingsUiBindings::~SettingsUiBindings() {}
void SettingsUiBindings::HandleSideSwipe(
chromecast::mojom::SideSwipeEvent event,
chromecast::mojom::SideSwipeOrigin origin,
const gfx::Point& touch_location) {
if (side_swipe_handler_.IsEmpty()) {
return;
}
blink::WebLocalFrame* web_frame = render_frame()->GetWebFrame();
v8::Isolate* isolate = web_frame->GetAgentGroupScheduler()->Isolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = web_frame->MainWorldScriptContext();
v8::MicrotasksScope microtasks_scope(
context, v8::MicrotasksScope::kDoNotRunMicrotasks);
v8::Context::Scope context_scope(context);
v8::Local<v8::Function> handler =
v8::Local<v8::Function>::New(isolate, std::move(side_swipe_handler_));
v8::Local<v8::Number> touch_event =
v8::Integer::New(isolate, static_cast<int>(event));
v8::Local<v8::Number> touch_origin =
v8::Integer::New(isolate, static_cast<int>(origin));
v8::Local<v8::Number> touch_x = v8::Integer::New(isolate, touch_location.x());
v8::Local<v8::Number> touch_y = v8::Integer::New(isolate, touch_location.y());
auto args = v8::to_array<v8::Local<v8::Value>>(
{touch_event, touch_origin, touch_x, touch_y});
v8::MaybeLocal<v8::Value> maybe_result =
handler->Call(context, context->Global(), args.size(), args.data());
side_swipe_handler_ = v8::UniquePersistent<v8::Function>(isolate, handler);
v8::Local<v8::Value> result;
std::ignore = maybe_result.ToLocal(&result);
}
void SettingsUiBindings::SendPlatformInfo(
const std::string& platform_info_json) {
if (platform_info_handler_.IsEmpty()) {
pending_platform_info_json_ = platform_info_json;
return;
}
blink::WebLocalFrame* web_frame = render_frame()->GetWebFrame();
v8::Isolate* isolate = web_frame->GetAgentGroupScheduler()->Isolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = web_frame->MainWorldScriptContext();
v8::MicrotasksScope microtasks_scope(
context, v8::MicrotasksScope::kDoNotRunMicrotasks);
v8::Context::Scope context_scope(context);
v8::Local<v8::Function> handler =
v8::Local<v8::Function>::New(isolate, std::move(platform_info_handler_));
v8::Local<v8::String> platform_info =
v8::String::NewFromUtf8(isolate, platform_info_json.data(),
v8::NewStringType::kInternalized)
.ToLocalChecked();
auto args = v8::to_array<v8::Local<v8::Value>>({platform_info});
v8::MaybeLocal<v8::Value> maybe_result =
handler->Call(context, context->Global(), args.size(), args.data());
platform_info_handler_ = v8::UniquePersistent<v8::Function>(isolate, handler);
v8::Local<v8::Value> result;
std::ignore = maybe_result.ToLocal(&result);
}
void SettingsUiBindings::Install(v8::Local<v8::Object> cast_platform,
v8::Isolate* isolate) {
v8::Local<v8::Object> settings_ui =
EnsureObjectExists(isolate, cast_platform, kSettingsUiName);
InstallBinding(isolate, settings_ui, kSetSideSwipeHandler,
&SettingsUiBindings::SetSideSwipeHandler,
base::Unretained(this));
InstallBinding(isolate, settings_ui, kSetPlatformInfoHandler,
&SettingsUiBindings::SetPlatformInfoHandler,
base::Unretained(this));
InstallBinding(isolate, settings_ui, kRequestVisible,
&SettingsUiBindings::RequestVisible, base::Unretained(this));
}
void SettingsUiBindings::SetSideSwipeHandler(
v8::Local<v8::Function> side_swipe_handler) {
v8::Isolate* isolate =
render_frame()->GetWebFrame()->GetAgentGroupScheduler()->Isolate();
side_swipe_handler_ =
v8::UniquePersistent<v8::Function>(isolate, side_swipe_handler);
}
void SettingsUiBindings::SetPlatformInfoHandler(
v8::Local<v8::Function> platform_info_handler) {
v8::Isolate* isolate =
render_frame()->GetWebFrame()->GetAgentGroupScheduler()->Isolate();
platform_info_handler_ =
v8::UniquePersistent<v8::Function>(isolate, platform_info_handler);
if (!pending_platform_info_json_.empty()) {
SendPlatformInfo(pending_platform_info_json_);
pending_platform_info_json_.clear();
}
}
void SettingsUiBindings::RequestVisible(bool visible) {
if (settings_platform_ptr_) {
settings_platform_ptr_->RequestVisible(visible);
}
}
void SettingsUiBindings::ReconnectMojo() {
if (binding_.is_bound())
binding_.reset();
if (settings_platform_ptr_.is_bound())
settings_platform_ptr_.reset();
render_frame()->GetBrowserInterfaceBroker()->GetInterface(
settings_platform_ptr_.BindNewPipeAndPassReceiver());
settings_platform_ptr_.set_disconnect_handler(base::BindOnce(
&SettingsUiBindings::OnMojoConnectionError, weak_factory_.GetWeakPtr()));
settings_platform_ptr_->Connect(binding_.BindNewPipeAndPassRemote());
mojo_reconnect_timer_.Stop();
}
void SettingsUiBindings::OnMojoConnectionError() {
LOG(WARNING) << "Disconnected from settings UI MOJO. Will reconnect every "
<< kDelayBetweenReconnectionInMillis << " milliseconds.";
mojo_reconnect_timer_.Start(
FROM_HERE, base::Milliseconds(kDelayBetweenReconnectionInMillis), this,
&SettingsUiBindings::ReconnectMojo);
}
} // namespace shell
} // namespace chromecast