blob: b0aa16010bbc602b0a854cd777221221164a49e3 [file] [log] [blame]
// Copyright 2017 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 "content/browser/keyboard_lock/keyboard_lock_service_impl.h"
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/containers/flat_set.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/optional.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/keyboard_lock/keyboard_lock_metrics.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/common/console_message_level.h"
#include "content/public/common/content_features.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
using blink::mojom::GetKeyboardLayoutMapResult;
using blink::mojom::KeyboardLockRequestResult;
namespace content {
namespace {
void LogKeyboardLockMethodCalled(KeyboardLockMethods method) {
UMA_HISTOGRAM_ENUMERATION(kKeyboardLockMethodCalledHistogramName, method,
KeyboardLockMethods::kCount);
}
} // namespace
KeyboardLockServiceImpl::KeyboardLockServiceImpl(
RenderFrameHost* render_frame_host,
blink::mojom::KeyboardLockServiceRequest request)
: FrameServiceBase(render_frame_host, std::move(request)),
render_frame_host_(static_cast<RenderFrameHostImpl*>(render_frame_host)) {
DCHECK(render_frame_host_);
}
// static
void KeyboardLockServiceImpl::CreateMojoService(
RenderFrameHost* render_frame_host,
blink::mojom::KeyboardLockServiceRequest request) {
DCHECK(render_frame_host);
// The object is bound to the lifetime of |render_frame_host| and the mojo
// connection. See FrameServiceBase for details.
new KeyboardLockServiceImpl(render_frame_host, std::move(request));
}
void KeyboardLockServiceImpl::RequestKeyboardLock(
const std::vector<std::string>& key_codes,
RequestKeyboardLockCallback callback) {
if (key_codes.empty())
LogKeyboardLockMethodCalled(KeyboardLockMethods::kRequestAllKeys);
else
LogKeyboardLockMethodCalled(KeyboardLockMethods::kRequestSomeKeys);
if (!base::FeatureList::IsEnabled(features::kKeyboardLockAPI)) {
std::move(callback).Run(KeyboardLockRequestResult::kSuccess);
return;
}
if (!render_frame_host_->IsCurrent()) {
std::move(callback).Run(KeyboardLockRequestResult::kFrameDetachedError);
return;
}
if (render_frame_host_->GetParent()) {
std::move(callback).Run(KeyboardLockRequestResult::kChildFrameError);
return;
}
// Per base::flat_set usage notes, the proper way to init a flat_set is
// inserting into a vector and using that to init the flat_set.
std::vector<ui::DomCode> dom_codes;
bool invalid_key_code_found = false;
for (const std::string& code : key_codes) {
ui::DomCode dom_code = ui::KeycodeConverter::CodeStringToDomCode(code);
if (dom_code != ui::DomCode::NONE) {
dom_codes.push_back(dom_code);
} else {
invalid_key_code_found = true;
render_frame_host_->AddMessageToConsole(
ConsoleMessageLevel::CONSOLE_MESSAGE_LEVEL_WARNING,
"Invalid DOMString passed into keyboard.lock(): '" + code + "'");
}
}
// If we are provided with a vector containing one or more invalid key codes,
// then exit without enabling keyboard lock. Also cancel any previous
// keyboard lock request since the most recent request failed.
if (invalid_key_code_found) {
render_frame_host_->GetRenderWidgetHost()->CancelKeyboardLock();
std::move(callback).Run(KeyboardLockRequestResult::kNoValidKeyCodesError);
return;
}
base::Optional<base::flat_set<ui::DomCode>> dom_code_set;
if (!dom_codes.empty())
dom_code_set = std::move(dom_codes);
if (render_frame_host_->GetRenderWidgetHost()->RequestKeyboardLock(
std::move(dom_code_set))) {
std::move(callback).Run(KeyboardLockRequestResult::kSuccess);
} else {
std::move(callback).Run(KeyboardLockRequestResult::kRequestFailedError);
}
}
void KeyboardLockServiceImpl::CancelKeyboardLock() {
LogKeyboardLockMethodCalled(KeyboardLockMethods::kCancelLock);
if (base::FeatureList::IsEnabled(features::kKeyboardLockAPI))
render_frame_host_->GetRenderWidgetHost()->CancelKeyboardLock();
}
void KeyboardLockServiceImpl::GetKeyboardLayoutMap(
GetKeyboardLayoutMapCallback callback) {
auto response = GetKeyboardLayoutMapResult::New();
response->status = blink::mojom::GetKeyboardLayoutMapStatus::kSuccess;
response->layout_map =
render_frame_host_->GetRenderWidgetHost()->GetKeyboardLayoutMap();
std::move(callback).Run(std::move(response));
}
KeyboardLockServiceImpl::~KeyboardLockServiceImpl() = default;
} // namespace content