0

Create a pipeline from render frame host to VibrationManager

Design doc: go/crca-cspp-ping-vibration-api

Change-Id: I7b34c92559fcca9f650240b4b7afab3c76f9a7da
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5490193
Reviewed-by: Ken Buchanan <kenrb@chromium.org>
Commit-Queue: Seung Jae Lim <andysjlim@chromium.org>
Reviewed-by: Matt Reynolds <mattreynolds@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1299589}
This commit is contained in:
Seung Jae Lim
2024-05-10 23:30:00 +00:00
committed by Chromium LUCI CQ
parent 9bbe7a89ec
commit c16c5e138a
25 changed files with 344 additions and 168 deletions

@ -3443,7 +3443,8 @@ class TestVibrationManager : public device::mojom::VibrationManager {
}
void BindVibrationManager(
mojo::PendingReceiver<device::mojom::VibrationManager> receiver) {
mojo::PendingReceiver<device::mojom::VibrationManager> receiver,
mojo::PendingRemote<device::mojom::VibrationManagerListener> listener) {
receiver_.Bind(std::move(receiver));
}

@ -701,12 +701,15 @@ VibrationManagerBinder& GetVibrationManagerBinderOverride() {
}
void BindVibrationManager(
RenderFrameHostImpl* frame,
mojo::PendingReceiver<device::mojom::VibrationManager> receiver) {
const auto& binder = GetVibrationManagerBinderOverride();
if (binder)
binder.Run(std::move(receiver));
else
GetDeviceService().BindVibrationManager(std::move(receiver));
if (binder) {
binder.Run(std::move(receiver), frame->CreateVibrationManagerListener());
} else {
GetDeviceService().BindVibrationManager(
std::move(receiver), frame->CreateVibrationManagerListener());
}
}
void BindMediaPlayerObserverClientHandler(
@ -914,7 +917,7 @@ void PopulateFrameBinders(RenderFrameHostImpl* host, mojo::BinderMap* map) {
&RenderFrameHostImpl::GetSensorProvider, base::Unretained(host)));
map->Add<device::mojom::VibrationManager>(
base::BindRepeating(&BindVibrationManager));
base::BindRepeating(&BindVibrationManager, base::Unretained(host)));
map->Add<payments::mojom::PaymentManager>(base::BindRepeating(
&RenderFrameHostImpl::CreatePaymentManager, base::Unretained(host)));

@ -79,7 +79,8 @@ CONTENT_EXPORT void OverrideBatteryMonitorBinderForTesting(
// Allows tests to override how frame hosts bind VibrationManager receivers.
using VibrationManagerBinder = base::RepeatingCallback<void(
mojo::PendingReceiver<device::mojom::VibrationManager>)>;
mojo::PendingReceiver<device::mojom::VibrationManager>,
mojo::PendingRemote<device::mojom::VibrationManagerListener>)>;
CONTENT_EXPORT void OverrideVibrationManagerBinderForTesting(
VibrationManagerBinder binder);

@ -80,7 +80,7 @@ namespace mojom {
class DisplayCutoutHost;
class FullscreenOptions;
class WindowFeatures;
}
} // namespace mojom
class PageState;
namespace web_pref {
struct WebPreferences;
@ -101,7 +101,7 @@ namespace ui {
class ClipboardFormatType;
struct AXUpdatesAndEvents;
struct AXLocationChanges;
}
} // namespace ui
namespace content {
class FrameTreeNode;
@ -627,6 +627,7 @@ class CONTENT_EXPORT RenderFrameHostDelegate {
RenderFrameHostImpl* render_frame_host,
blink::mojom::StorageTypeAccessed storage_type,
bool blocked) {}
virtual void OnVibrate(RenderFrameHostImpl* render_frame_host) {}
// Notified that the renderer responded after calling GetSavableResourceLinks.
virtual void SavableResourceLinksResponse(

@ -16347,6 +16347,14 @@ RenderFrameHostImpl::CreateSharedDictionaryAccessObserver() {
return remote;
}
mojo::PendingRemote<device::mojom::VibrationManagerListener>
RenderFrameHostImpl::CreateVibrationManagerListener() {
mojo::PendingRemote<device::mojom::VibrationManagerListener> remote;
vibration_manager_listeners_.Add(this,
remote.InitWithNewPipeAndPassReceiver());
return remote;
}
#if BUILDFLAG(ENABLE_MDNS)
void RenderFrameHostImpl::CreateMdnsResponder(
mojo::PendingReceiver<network::mojom::MdnsResponder> receiver) {
@ -16404,6 +16412,10 @@ void RenderFrameHostImpl::OnSharedDictionaryAccessed(
delegate_->OnSharedDictionaryAccessed(this, *details);
}
void RenderFrameHostImpl::OnVibrate() {
delegate_->OnVibrate(this);
}
void RenderFrameHostImpl::SetEmbeddingToken(
const base::UnguessableToken& embedding_token) {
// Everything in this method depends on whether the embedding token has

@ -112,6 +112,7 @@
#include "net/cookies/cookie_setting_override.h"
#include "net/net_buildflags.h"
#include "ppapi/buildflags/buildflags.h"
#include "services/device/public/mojom/vibration_manager.mojom.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "services/network/public/cpp/attribution_reporting_runtime_features.h"
#include "services/network/public/cpp/cross_origin_embedder_policy.h"
@ -317,6 +318,7 @@ class CONTENT_EXPORT RenderFrameHostImpl
public blink::mojom::NonAssociatedLocalFrameHost,
public blink::mojom::LocalMainFrameHost,
public ui::AXActionHandlerBase,
public device::mojom::VibrationManagerListener,
public network::mojom::CookieAccessObserver,
public network::mojom::TrustTokenAccessObserver,
public network::mojom::SharedDictionaryAccessObserver,
@ -2627,6 +2629,9 @@ class CONTENT_EXPORT RenderFrameHostImpl
mojo::PendingRemote<network::mojom::SharedDictionaryAccessObserver>
CreateSharedDictionaryAccessObserver();
mojo::PendingRemote<device::mojom::VibrationManagerListener>
CreateVibrationManagerListener();
// network::mojom::CookieAccessObserver:
void OnCookiesAccessed(std::vector<network::mojom::CookieAccessDetailsPtr>
details_vector) override;
@ -2639,6 +2644,9 @@ class CONTENT_EXPORT RenderFrameHostImpl
void OnSharedDictionaryAccessed(
network::mojom::SharedDictionaryAccessDetailsPtr details) override;
// device::mojom::VibrationManagerListener:
void OnVibrate() override;
void GetSavableResourceLinksFromRenderer();
// Helper for checking if a navigation to an error page should be excluded
@ -4980,6 +4988,9 @@ class CONTENT_EXPORT RenderFrameHostImpl
mojo::ReceiverSet<network::mojom::SharedDictionaryAccessObserver>
shared_dictionary_observers_;
mojo::ReceiverSet<device::mojom::VibrationManagerListener>
vibration_manager_listeners_;
// Indicates whether this frame is an outer delegate frame for some other
// RenderFrameHost. This will be a valid ID if so, and
// `kFrameTreeNodeInvalidId` otherwise.

@ -11,18 +11,43 @@
#include "content/browser/browser_interface_binders.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/mojom/vibration_manager.mojom.h"
namespace content {
namespace {
class VibrationObserver : public WebContentsObserver {
public:
explicit VibrationObserver(WebContents* web_contents)
: WebContentsObserver(web_contents) {}
void VibrationRequested() override {
did_vibrate_ = true;
run_loop_.Quit();
}
void Wait() {
if (!did_vibrate_) {
run_loop_.Run();
}
}
bool DidVibrate() { return did_vibrate_; }
private:
bool did_vibrate_ = false;
base::RunLoop run_loop_;
};
class VibrationTest : public ContentBrowserTest,
public device::mojom::VibrationManager {
public:
@ -39,8 +64,10 @@ class VibrationTest : public ContentBrowserTest,
}
void BindVibrationManager(
mojo::PendingReceiver<device::mojom::VibrationManager> receiver) {
mojo::PendingReceiver<device::mojom::VibrationManager> receiver,
mojo::PendingRemote<device::mojom::VibrationManagerListener> listener) {
receiver_.Bind(std::move(receiver));
listener_.Bind(std::move(listener));
}
protected:
@ -61,12 +88,14 @@ class VibrationTest : public ContentBrowserTest,
vibrate_milliseconds_ = milliseconds;
std::move(callback).Run();
std::move(vibrate_done_).Run();
listener_->OnVibrate();
}
void Cancel(CancelCallback callback) override { std::move(callback).Run(); }
int64_t vibrate_milliseconds_ = -1;
base::OnceClosure vibrate_done_;
mojo::Receiver<device::mojom::VibrationManager> receiver_{this};
mojo::Remote<device::mojom::VibrationManagerListener> listener_;
};
IN_PROC_BROWSER_TEST_F(VibrationTest, Vibrate) {
@ -80,6 +109,19 @@ IN_PROC_BROWSER_TEST_F(VibrationTest, Vibrate) {
ASSERT_EQ(1234, vibrate_milliseconds());
}
IN_PROC_BROWSER_TEST_F(VibrationTest, VibrateNotifiesListener) {
VibrationObserver observer(shell()->web_contents());
EXPECT_FALSE(observer.DidVibrate());
ASSERT_TRUE(NavigateToURL(shell(), GetTestUrl(".", "simple_page.html")));
base::RunLoop run_loop;
TriggerVibrate(1234, run_loop.QuitClosure());
run_loop.Run();
observer.Wait();
EXPECT_TRUE(observer.DidVibrate());
}
} // namespace
} // namespace content

@ -3475,6 +3475,12 @@ void WebContentsImpl::NotifyStorageAccessed(
storage_type, blocked);
}
void WebContentsImpl::OnVibrate(RenderFrameHostImpl* rfh) {
OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::OnVibrate",
"render_frame_host", rfh);
observers_.NotifyObservers(&WebContentsObserver::VibrationRequested);
}
std::optional<blink::ParsedPermissionsPolicy>
WebContentsImpl::GetPermissionsPolicyForIsolatedWebApp(
RenderFrameHostImpl* source) {

@ -778,6 +778,8 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
void NotifyStorageAccessed(RenderFrameHostImpl*,
blink::mojom::StorageTypeAccessed storage_type,
bool blocked) override;
void OnVibrate(RenderFrameHostImpl*) override;
std::optional<blink::ParsedPermissionsPolicy>
GetPermissionsPolicyForIsolatedWebApp(RenderFrameHostImpl* source) override;

@ -919,6 +919,9 @@ class CONTENT_EXPORT WebContentsObserver : public base::CheckedObserver {
// Called when WebContents received a request to lock the pointer.
virtual void PointerLockRequested() {}
// Called when WebContents received a request to vibrate the page.
virtual void VibrationRequested() {}
WebContents* web_contents() const;
protected:

@ -47,6 +47,7 @@ source_set("lib") {
"//services/device/screen_orientation",
"//services/device/time_zone_monitor",
"//services/device/usb/mojo",
"//services/device/vibration",
"//services/device/wake_lock",
"//services/service_manager/public/cpp",
"//ui/gfx",
@ -65,7 +66,6 @@ source_set("lib") {
deps += [
"//services/device/battery",
"//services/device/hid",
"//services/device/vibration",
]
}
@ -187,6 +187,7 @@ source_set("tests") {
"//services/device/public/cpp/power_monitor",
"//services/device/public/mojom",
"//services/device/public/mojom:geolocation_internals",
"//services/device/vibration",
"//services/device/wake_lock",
"//services/network:test_support",
"//testing/gmock",
@ -257,10 +258,7 @@ source_set("tests") {
"geolocation/network_location_provider_unittest.cc",
"geolocation/wifi_data_provider_common_unittest.cc",
]
deps += [
":device_service_jni_headers",
"//services/device/vibration/android:vibration_jni_headers",
]
deps += [ ":device_service_jni_headers" ]
} else {
sources += [
"battery/battery_monitor_impl_unittest.cc",
@ -272,7 +270,6 @@ source_set("tests") {
"//components/variations:test_support",
"//services/device/battery",
"//services/device/hid",
"//services/device/vibration",
]
if ((!is_linux && !is_chromeos) || use_udev) {

@ -10,10 +10,8 @@ import org.jni_zero.JNINamespace;
import org.chromium.device.battery.BatteryMonitorFactory;
import org.chromium.device.mojom.BatteryMonitor;
import org.chromium.device.mojom.NfcProvider;
import org.chromium.device.mojom.VibrationManager;
import org.chromium.device.nfc.NfcDelegate;
import org.chromium.device.nfc.NfcProviderImpl;
import org.chromium.device.vibration.VibrationManagerImpl;
import org.chromium.mojo.system.impl.CoreImpl;
import org.chromium.services.service_manager.InterfaceRegistry;
@ -30,6 +28,5 @@ class InterfaceRegistrar {
.toMessagePipeHandle());
registry.addInterface(BatteryMonitor.MANAGER, new BatteryMonitorFactory());
registry.addInterface(NfcProvider.MANAGER, new NfcProviderImpl.Factory(nfcDelegate));
registry.addInterface(VibrationManager.MANAGER, new VibrationManagerImpl.Factory());
}
}

@ -27,6 +27,7 @@
#include "services/device/public/mojom/battery_monitor.mojom.h"
#include "services/device/serial/serial_port_manager_impl.h"
#include "services/device/time_zone_monitor/time_zone_monitor.h"
#include "services/device/vibration/vibration_manager_impl.h"
#include "services/device/wake_lock/wake_lock_provider.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "ui/gfx/native_widget_types.h"
@ -35,11 +36,11 @@
#include "base/android/jni_android.h"
#include "services/device/device_service_jni_headers/InterfaceRegistrar_jni.h"
#include "services/device/screen_orientation/screen_orientation_listener_android.h"
#include "services/device/vibration/vibration_manager_android.h"
#else
#include "services/device/battery/battery_monitor_impl.h"
#include "services/device/battery/battery_status_service.h"
#include "services/device/hid/hid_manager_impl.h"
#include "services/device/vibration/vibration_manager_impl.h"
#endif
#if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && defined(USE_UDEV)
@ -214,11 +215,12 @@ void DeviceService::BindNFCProvider(
#endif
void DeviceService::BindVibrationManager(
mojo::PendingReceiver<mojom::VibrationManager> receiver) {
mojo::PendingReceiver<mojom::VibrationManager> receiver,
mojo::PendingRemote<mojom::VibrationManagerListener> listener) {
#if BUILDFLAG(IS_ANDROID)
GetJavaInterfaceProvider()->GetInterface(std::move(receiver));
VibrationManagerAndroid::Create(std::move(receiver), std::move(listener));
#else
VibrationManagerImpl::Create(std::move(receiver));
VibrationManagerImpl::Create(std::move(receiver), std::move(listener));
#endif
}

@ -174,7 +174,8 @@ class DeviceService : public mojom::DeviceService {
#endif
void BindVibrationManager(
mojo::PendingReceiver<mojom::VibrationManager> receiver) override;
mojo::PendingReceiver<mojom::VibrationManager> receiver,
mojo::PendingRemote<mojom::VibrationManagerListener> listener) override;
#if !BUILDFLAG(IS_ANDROID)
void BindHidManager(

@ -67,8 +67,9 @@ interface DeviceService {
[EnableIf=is_android]
BindNFCProvider(pending_receiver<NFCProvider> receiver);
// Binds a VibrationManager endpoint.
BindVibrationManager(pending_receiver<VibrationManager> receiver);
// Binds a VibrationManager endpoint and a VibrationManagerListener endpoint.
BindVibrationManager(pending_receiver<VibrationManager> receiver,
pending_remote<VibrationManagerListener> listener);
// Binds a HidManager endpoint.
[EnableIf=enable_hid]

@ -4,8 +4,20 @@
module device.mojom;
// Responsible for handling the device vibration, if applicable. Desktop devices
// currently do not support this but Android does. There are separate
// implementations to handle this under vibration_manager_impl.cc.
interface VibrationManager {
// TODO(mvanouwerkerk): Add something like StructTraits to validate arguments.
Vibrate(int64 milliseconds) => ();
// Cancels the vibration after the VibrationManager vibrates the device.
Cancel() => ();
};
// Listens when the VibrationManager implementation calls Vibrate function.
// Currently, this mojo connection exists to connect between the RenderFrameHost
// and the device directory VibrationManagerImpl in the device service.
interface VibrationManagerListener {
// Called when VibrationManager calls Vibrate.
OnVibrate();
};

@ -5,26 +5,36 @@
import("//build/config/features.gni")
import("//mojo/public/tools/bindings/mojom.gni")
# On android, VibrationManager mojo interface is implemented directly in Java.
if (!is_android) {
source_set("vibration") {
visibility = [
"//services/device:lib",
"//services/device:tests",
if (is_android) {
import("//build/config/android/rules.gni")
import("//third_party/jni_zero/jni_zero.gni")
}
source_set("vibration") {
visibility = [
"//services/device:lib",
"//services/device:tests",
]
sources = [
"vibration_manager_impl.cc",
"vibration_manager_impl.h",
]
configs += [ "//build/config/compiler:wexit_time_destructors" ]
public_deps = [ "//services/device/public/mojom" ]
deps = [
"//base",
"//mojo/public/cpp/bindings",
]
if (is_android) {
sources += [
"vibration_manager_android.cc",
"vibration_manager_android.h",
]
sources = [
"vibration_manager_impl.h",
"vibration_manager_impl_default.cc",
]
configs += [ "//build/config/compiler:wexit_time_destructors" ]
public_deps = [ "//services/device/public/mojom" ]
deps = [
"//base",
"//mojo/public/cpp/bindings",
]
deps += [ "//services/device/vibration/android:vibration_jni_headers" ]
}
}

@ -8,14 +8,14 @@ import("//third_party/jni_zero/jni_zero.gni")
generate_jni("vibration_jni_headers") {
sources =
[ "java/src/org/chromium/device/vibration/VibrationManagerImpl.java" ]
[ "java/src/org/chromium/device/vibration/VibrationManagerAndroid.java" ]
}
android_library("vibration_manager_java") {
visibility = [ "//services/device:*" ]
sources =
[ "java/src/org/chromium/device/vibration/VibrationManagerImpl.java" ]
[ "java/src/org/chromium/device/vibration/VibrationManagerAndroid.java" ]
deps = [
"//base:base_java",

@ -8,25 +8,15 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.os.Vibrator;
import org.jni_zero.CalledByNative;
import org.jni_zero.CalledByNativeForTesting;
import org.jni_zero.JNINamespace;
import org.chromium.base.ContextUtils;
import org.chromium.base.Log;
import org.chromium.base.ResettersForTesting;
import org.chromium.device.mojom.VibrationManager;
import org.chromium.mojo.system.MojoException;
import org.chromium.services.service_manager.InterfaceFactory;
import org.jni_zero.CalledByNative;
import org.jni_zero.JNINamespace;
/**
* Android implementation of the VibrationManager interface defined in
* services/device/public/mojom/vibration_manager.mojom.
*/
/** Android implementation details for device::VibrationManagerAndroid. */
@JNINamespace("device")
public class VibrationManagerImpl implements VibrationManager {
private static final String TAG = "VibrationManagerImpl";
public class VibrationManagerAndroid {
private static final String TAG = "VibrationManager";
private static final long MINIMUM_VIBRATION_DURATION_MS = 1; // 1 millisecond
private static final long MAXIMUM_VIBRATION_DURATION_MS = 10000; // 10 seconds
@ -35,10 +25,7 @@ public class VibrationManagerImpl implements VibrationManager {
private final Vibrator mVibrator;
private final boolean mHasVibratePermission;
private static long sVibrateMilliSecondsForTesting = -1;
private static boolean sVibrateCancelledForTesting;
public VibrationManagerImpl() {
public VibrationManagerAndroid() {
Context appContext = ContextUtils.getApplicationContext();
mAudioManager = (AudioManager) appContext.getSystemService(Context.AUDIO_SERVICE);
mVibrator = (Vibrator) appContext.getSystemService(Context.VIBRATOR_SERVICE);
@ -51,14 +38,13 @@ public class VibrationManagerImpl implements VibrationManager {
}
}
@Override
public void close() {}
@CalledByNative
static VibrationManagerAndroid getInstance() {
return new VibrationManagerAndroid();
}
@Override
public void onConnectionError(MojoException e) {}
@Override
public void vibrate(long milliseconds, Vibrate_Response callback) {
@CalledByNative
public void vibrate(long milliseconds) {
// Though the Blink implementation already sanitizes vibration times, don't
// trust any values passed from the client.
long sanitizedMilliseconds =
@ -70,37 +56,12 @@ public class VibrationManagerImpl implements VibrationManager {
&& mHasVibratePermission) {
mVibrator.vibrate(sanitizedMilliseconds);
}
sVibrateMilliSecondsForTesting = sanitizedMilliseconds;
callback.call();
}
@Override
public void cancel(Cancel_Response callback) {
if (mHasVibratePermission) {
mVibrator.cancel();
}
sVibrateCancelledForTesting = true;
ResettersForTesting.register(() -> sVibrateCancelledForTesting = false);
callback.call();
}
/** A factory for implementations of the VibrationManager interface. */
public static class Factory implements InterfaceFactory<VibrationManager> {
public Factory() {}
@Override
public VibrationManager createImpl() {
return new VibrationManagerImpl();
}
}
@CalledByNative
static long getVibrateMilliSecondsForTesting() {
return sVibrateMilliSecondsForTesting;
}
@CalledByNativeForTesting
static boolean getVibrateCancelledForTesting() {
return sVibrateCancelledForTesting;
public void cancel() {
if (mHasVibratePermission) {
mVibrator.cancel();
}
}
}

@ -0,0 +1,39 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/device/vibration/vibration_manager_android.h"
#include "base/android/jni_android.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "services/device/vibration/android/vibration_jni_headers/VibrationManagerAndroid_jni.h"
namespace device {
VibrationManagerAndroid::VibrationManagerAndroid(
mojo::PendingRemote<mojom::VibrationManagerListener> listener)
: VibrationManagerImpl(std::move(listener)) {
impl_.Reset(Java_VibrationManagerAndroid_getInstance(
base::android::AttachCurrentThread()));
}
VibrationManagerAndroid::~VibrationManagerAndroid() = default;
void VibrationManagerAndroid::PlatformVibrate(int64_t milliseconds) {
Java_VibrationManagerAndroid_vibrate(base::android::AttachCurrentThread(),
impl_, milliseconds);
}
void VibrationManagerAndroid::PlatformCancel() {
Java_VibrationManagerAndroid_cancel(base::android::AttachCurrentThread(),
impl_);
}
void VibrationManagerAndroid::Create(
mojo::PendingReceiver<mojom::VibrationManager> receiver,
mojo::PendingRemote<mojom::VibrationManagerListener> listener) {
mojo::MakeSelfOwnedReceiver(
std::make_unique<VibrationManagerAndroid>(std::move(listener)),
std::move(receiver));
}
} // namespace device

@ -0,0 +1,38 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SERVICES_DEVICE_VIBRATION_VIBRATION_MANAGER_ANDROID_H_
#define SERVICES_DEVICE_VIBRATION_VIBRATION_MANAGER_ANDROID_H_
#include <jni.h>
#include "base/android/scoped_java_ref.h"
#include "services/device/vibration/vibration_manager_impl.h"
namespace device {
class VibrationManagerAndroid : public VibrationManagerImpl {
public:
static void Create(
mojo::PendingReceiver<mojom::VibrationManager> receiver,
mojo::PendingRemote<mojom::VibrationManagerListener> listener);
explicit VibrationManagerAndroid(
mojo::PendingRemote<mojom::VibrationManagerListener> listener);
VibrationManagerAndroid(const VibrationManagerAndroid&) = delete;
VibrationManagerAndroid& operator=(const VibrationManagerAndroid&) = delete;
~VibrationManagerAndroid() override;
protected:
// VibrationManagerImpl:
void PlatformVibrate(int64_t milliseconds) override;
void PlatformCancel() override;
private:
base::android::ScopedJavaGlobalRef<jobject> impl_;
};
} // namespace device
#endif // SERVICES_DEVICE_VIBRATION_VIBRATION_MANAGER_ANDROID_H_

@ -0,0 +1,54 @@
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/device/vibration/vibration_manager_impl.h"
#include <utility>
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
namespace device {
int64_t VibrationManagerImpl::milli_seconds_for_testing_ = -1;
bool VibrationManagerImpl::cancelled_for_testing_ = false;
VibrationManagerImpl::VibrationManagerImpl(
mojo::PendingRemote<mojom::VibrationManagerListener> listener) {
CHECK(!listener_);
listener_.Bind(std::move(listener));
}
VibrationManagerImpl::~VibrationManagerImpl() = default;
void VibrationManagerImpl::Vibrate(int64_t milliseconds,
VibrateCallback callback) {
PlatformVibrate(milliseconds);
VibrationManagerImpl::milli_seconds_for_testing_ = milliseconds;
if (listener_) {
listener_->OnVibrate();
}
std::move(callback).Run();
}
void VibrationManagerImpl::Cancel(CancelCallback callback) {
VibrationManagerImpl::cancelled_for_testing_ = true;
std::move(callback).Run();
}
void VibrationManagerImpl::PlatformVibrate(int64_t milliseconds) {}
void VibrationManagerImpl::PlatformCancel() {}
// static
void VibrationManagerImpl::Create(
mojo::PendingReceiver<mojom::VibrationManager> receiver,
mojo::PendingRemote<mojom::VibrationManagerListener> listener) {
mojo::MakeSelfOwnedReceiver(
std::make_unique<VibrationManagerImpl>(std::move(listener)),
std::move(receiver));
}
} // namespace device

@ -5,17 +5,41 @@
#ifndef SERVICES_DEVICE_VIBRATION_VIBRATION_MANAGER_IMPL_H_
#define SERVICES_DEVICE_VIBRATION_VIBRATION_MANAGER_IMPL_H_
#include <stdint.h>
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/mojom/vibration_manager.mojom.h"
namespace device {
class VibrationManagerImpl {
class VibrationManagerImpl : public mojom::VibrationManager {
public:
static void Create(mojo::PendingReceiver<mojom::VibrationManager> receiver);
static void Create(
mojo::PendingReceiver<mojom::VibrationManager> receiver,
mojo::PendingRemote<mojom::VibrationManagerListener> listener);
// Sets the listener that listens for any Vibrate calls from this class. The
// listener is currently set from the RenderFrameHostImpl.
explicit VibrationManagerImpl(
mojo::PendingRemote<mojom::VibrationManagerListener> listener);
VibrationManagerImpl(const VibrationManagerImpl&) = delete;
VibrationManagerImpl& operator=(const VibrationManagerImpl&) = delete;
~VibrationManagerImpl() override;
// mojom::VibrationManager
void Vibrate(int64_t milliseconds, VibrateCallback callback) override;
void Cancel(CancelCallback callback) override;
static int64_t milli_seconds_for_testing_;
static bool cancelled_for_testing_;
protected:
virtual void PlatformVibrate(int64_t milliseconds);
virtual void PlatformCancel();
mojo::Remote<mojom::VibrationManagerListener> listener_;
};
} // namespace device

@ -1,44 +0,0 @@
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/device/vibration/vibration_manager_impl.h"
#include <stdint.h>
#include <utility>
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
namespace device {
int64_t VibrationManagerImpl::milli_seconds_for_testing_ = -1;
bool VibrationManagerImpl::cancelled_for_testing_ = false;
namespace {
class VibrationManagerEmptyImpl : public mojom::VibrationManager {
public:
VibrationManagerEmptyImpl() {}
~VibrationManagerEmptyImpl() override {}
void Vibrate(int64_t milliseconds, VibrateCallback callback) override {
VibrationManagerImpl::milli_seconds_for_testing_ = milliseconds;
std::move(callback).Run();
}
void Cancel(CancelCallback callback) override {
VibrationManagerImpl::cancelled_for_testing_ = true;
std::move(callback).Run();
}
};
} // namespace
// static
void VibrationManagerImpl::Create(
mojo::PendingReceiver<mojom::VibrationManager> receiver) {
mojo::MakeSelfOwnedReceiver(std::make_unique<VibrationManagerEmptyImpl>(),
std::move(receiver));
}
} // namespace device

@ -2,24 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/device/vibration/vibration_manager_impl.h"
#include "base/run_loop.h"
#include "build/build_config.h"
#include "base/test/gmock_callback_support.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/device_service_test_base.h"
#include "services/device/public/mojom/vibration_manager.mojom.h"
#if BUILDFLAG(IS_ANDROID)
#include "base/android/jni_android.h"
#include "services/device/vibration/android/vibration_jni_headers/VibrationManagerImpl_jni.h"
#else
#include "services/device/vibration/vibration_manager_impl.h"
#endif
#include "testing/gmock/include/gmock/gmock.h"
namespace device {
using ::base::test::RunClosure;
namespace {
class VibrationManagerImplTest : public DeviceServiceTestBase {
class VibrationManagerImplTest : public DeviceServiceTestBase,
public mojom::VibrationManagerListener {
public:
VibrationManagerImplTest() = default;
@ -32,8 +31,10 @@ class VibrationManagerImplTest : public DeviceServiceTestBase {
void SetUp() override {
DeviceServiceTestBase::SetUp();
mojo::PendingRemote<device::mojom::VibrationManagerListener> remote;
listener_.Bind(remote.InitWithNewPipeAndPassReceiver());
device_service()->BindVibrationManager(
vibration_manager_.BindNewPipeAndPassReceiver());
vibration_manager_.BindNewPipeAndPassReceiver(), std::move(remote));
}
void Vibrate(int64_t milliseconds) {
@ -49,25 +50,18 @@ class VibrationManagerImplTest : public DeviceServiceTestBase {
}
int64_t GetVibrationMilliSeconds() {
#if BUILDFLAG(IS_ANDROID)
return Java_VibrationManagerImpl_getVibrateMilliSecondsForTesting(
base::android::AttachCurrentThread());
#else
return VibrationManagerImpl::milli_seconds_for_testing_;
#endif
}
bool GetVibrationCancelled() {
#if BUILDFLAG(IS_ANDROID)
return Java_VibrationManagerImpl_getVibrateCancelledForTesting(
base::android::AttachCurrentThread());
#else
return VibrationManagerImpl::cancelled_for_testing_;
#endif
}
MOCK_METHOD(void, OnVibrate, (), (override));
private:
mojo::Remote<mojom::VibrationManager> vibration_manager_;
mojo::Receiver<mojom::VibrationManagerListener> listener_{this};
};
TEST_F(VibrationManagerImplTest, VibrateThenCancel) {
@ -80,6 +74,14 @@ TEST_F(VibrationManagerImplTest, VibrateThenCancel) {
EXPECT_TRUE(GetVibrationCancelled());
}
TEST_F(VibrationManagerImplTest, VibrateNotifiesListener) {
base::RunLoop loop;
EXPECT_CALL(*this, OnVibrate)
.WillOnce(base::test::RunClosure(loop.QuitClosure()));
Vibrate(10000);
loop.Run();
}
} // namespace
} // namespace device