Commit 6ca5bedb authored by billorr's avatar billorr Committed by Commit bot

Expose Gamepad API instance for Cardboard button

This change exposes a gamepad with a single button, which is driven by the touch screen.

BUG=718665

Review-Url: https://codereview.chromium.org/2879973002
Cr-Commit-Position: refs/heads/master@{#473986}
parent 217d81bc
......@@ -20,13 +20,11 @@ import android.widget.FrameLayout.LayoutParams;
import com.google.vr.ndk.base.AndroidCompat;
import com.google.vr.ndk.base.GvrLayout;
import org.chromium.base.CommandLine;
import org.chromium.base.ThreadUtils;
import org.chromium.base.VisibleForTesting;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.NativePage;
import org.chromium.chrome.browser.UrlConstants;
import org.chromium.chrome.browser.tab.EmptyTabObserver;
......@@ -230,9 +228,12 @@ public class VrShellImpl
@Override
@SuppressLint("ClickableViewAccessibility")
public boolean onTouch(View v, MotionEvent event) {
if (!CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_VR_SHELL_DEV)
&& event.getActionMasked() == MotionEvent.ACTION_DOWN) {
nativeOnTriggerEvent(mNativeVrShell);
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
nativeOnTriggerEvent(mNativeVrShell, true);
return true;
} else if (event.getActionMasked() == MotionEvent.ACTION_UP
|| event.getActionMasked() == MotionEvent.ACTION_CANCEL) {
nativeOnTriggerEvent(mNativeVrShell, false);
return true;
}
return false;
......@@ -413,25 +414,6 @@ public class VrShellImpl
mRenderToSurfaceLayout.invalidate();
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
// Normally, touch event is dispatched to presentation view only if the phone is paired with
// a Cardboard viewer. This is annoying when we just want to quickly verify a Cardboard
// behavior. This allows us to trigger cardboard trigger event without pair to a Cardboard.
boolean cardboardTriggered = false;
if (CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_VR_SHELL_DEV)
&& event.getActionMasked() == MotionEvent.ACTION_DOWN) {
nativeOnTriggerEvent(mNativeVrShell);
cardboardTriggered = true;
}
boolean parentConsumed = super.dispatchTouchEvent(event);
if (mOnDispatchTouchEventForTesting != null) {
mOnDispatchTouchEventForTesting.onDispatchTouchEvent(
parentConsumed, cardboardTriggered);
}
return parentConsumed;
}
@Override
public void onResume() {
super.onResume();
......@@ -627,7 +609,7 @@ public class VrShellImpl
private native void nativeSwapContents(
long nativeVrShell, WebContents webContents, MotionEventSynthesizer eventSynthesizer);
private native void nativeDestroy(long nativeVrShell);
private native void nativeOnTriggerEvent(long nativeVrShell);
private native void nativeOnTriggerEvent(long nativeVrShell, boolean touched);
private native void nativeOnPause(long nativeVrShell);
private native void nativeOnResume(long nativeVrShell);
private native void nativeOnLoadProgressChanged(long nativeVrShell, double progress);
......
......@@ -43,6 +43,7 @@ class MockBrowserInterface : public VrBrowserInterface {
MOCK_METHOD1(SetScreenCapturingIndicator, void(bool));
MOCK_METHOD1(SetAudioCapturingIndicator, void(bool));
MOCK_METHOD0(ExitCct, void());
MOCK_METHOD1(ToggleCardboardGamepad, void(bool));
// Stub this as scoped pointers don't work as mock method parameters.
void ProcessContentGesture(std::unique_ptr<blink::WebInputEvent>) {}
......
......@@ -43,6 +43,7 @@ class VrBrowserInterface {
virtual void OnContentPaused(bool enabled) = 0;
virtual void NavigateBack() = 0;
virtual void ExitCct() = 0;
virtual void ToggleCardboardGamepad(bool enabled) = 0;
};
} // namespace vr_shell
......
......@@ -122,6 +122,12 @@ void VrGLThread::ExitCct() {
FROM_HERE, base::Bind(&VrShell::ExitCct, weak_vr_shell_));
}
void VrGLThread::ToggleCardboardGamepad(bool enabled) {
main_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(&VrShell::ToggleCardboardGamepad, weak_vr_shell_, enabled));
}
void VrGLThread::SetFullscreen(bool enabled) {
WaitUntilThreadStarted();
task_runner()->PostTask(FROM_HERE, base::Bind(&UiSceneManager::SetFullscreen,
......
......@@ -59,6 +59,7 @@ class VrGLThread : public base::Thread,
void OnContentPaused(bool enabled) override;
void NavigateBack() override;
void ExitCct() override;
void ToggleCardboardGamepad(bool enabled) override;
// UiInterface implementation (VrShell calling to the UI).
void SetFullscreen(bool enabled) override;
......
......@@ -42,6 +42,7 @@
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_features.h"
#include "content/public/common/referrer.h"
#include "device/vr/android/gvr/cardboard_gamepad_data_fetcher.h"
#include "device/vr/android/gvr/gvr_device.h"
#include "device/vr/android/gvr/gvr_device_provider.h"
#include "device/vr/android/gvr/gvr_gamepad_data_fetcher.h"
......@@ -181,11 +182,16 @@ bool RegisterVrShell(JNIEnv* env) {
VrShell::~VrShell() {
DVLOG(1) << __FUNCTION__ << "=" << this;
poll_capturing_media_task_.Cancel();
if (gamepad_source_active_) {
if (gvr_gamepad_source_active_) {
device::GamepadDataFetcherManager::GetInstance()->RemoveSourceFactory(
device::GAMEPAD_SOURCE_GVR);
}
if (cardboard_gamepad_source_active_) {
device::GamepadDataFetcherManager::GetInstance()->RemoveSourceFactory(
device::GAMEPAD_SOURCE_CARDBOARD);
}
delegate_provider_->RemoveDelegate();
{
// The GvrLayout is, and must always be, used only on the UI thread, and the
......@@ -246,10 +252,49 @@ void VrShell::ExitCct() {
Java_VrShellImpl_exitCct(env, j_vr_shell_.obj());
}
void VrShell::OnTriggerEvent(JNIEnv* env, const JavaParamRef<jobject>& obj) {
void VrShell::ToggleCardboardGamepad(bool enabled) {
// enable/disable updating gamepad state
if (cardboard_gamepad_source_active_ && !enabled) {
device::GamepadDataFetcherManager::GetInstance()->RemoveSourceFactory(
device::GAMEPAD_SOURCE_CARDBOARD);
cardboard_gamepad_data_fetcher_ = nullptr;
cardboard_gamepad_source_active_ = false;
}
if (!cardboard_gamepad_source_active_ && enabled) {
// enable the gamepad
if (!delegate_provider_->device_provider())
return;
unsigned int device_id =
delegate_provider_->device_provider()->Device()->id();
device::GamepadDataFetcherManager::GetInstance()->AddFactory(
new device::CardboardGamepadDataFetcher::Factory(this, device_id));
cardboard_gamepad_source_active_ = true;
}
}
void VrShell::OnTriggerEvent(JNIEnv* env,
const JavaParamRef<jobject>& obj,
bool touched) {
WaitForGlThread();
PostToGlThread(FROM_HERE, base::Bind(&VrShellGl::OnTriggerEvent,
gl_thread_->GetVrShellGl()));
// Send screen taps over to VrShellGl to be turned into simulated clicks for
// cardboard.
if (touched)
PostToGlThread(FROM_HERE, base::Bind(&VrShellGl::OnTriggerEvent,
gl_thread_->GetVrShellGl()));
// If we are running cardboard, update gamepad state.
if (cardboard_gamepad_source_active_) {
device::CardboardGamepadData pad;
pad.timestamp = cardboard_gamepad_timer_++;
pad.is_screen_touching = touched;
if (cardboard_gamepad_data_fetcher_) {
cardboard_gamepad_data_fetcher_->SetGamepadData(pad);
}
}
}
void VrShell::OnPause(JNIEnv* env, const JavaParamRef<jobject>& obj) {
......@@ -605,25 +650,32 @@ void VrShell::ProcessContentGesture(
}
void VrShell::UpdateGamepadData(device::GvrGamepadData pad) {
if (!gamepad_source_active_) {
if (!gvr_gamepad_source_active_) {
if (!delegate_provider_->device_provider())
return;
unsigned int device_id =
delegate_provider_->device_provider()->Device()->id();
device::GamepadDataFetcherManager::GetInstance()->AddFactory(
new device::GvrGamepadDataFetcher::Factory(this, device_id));
gamepad_source_active_ = true;
gvr_gamepad_source_active_ = true;
}
if (gamepad_data_fetcher_) {
gamepad_data_fetcher_->SetGamepadData(pad);
if (gvr_gamepad_data_fetcher_) {
gvr_gamepad_data_fetcher_->SetGamepadData(pad);
}
}
void VrShell::RegisterGamepadDataFetcher(
void VrShell::RegisterGvrGamepadDataFetcher(
device::GvrGamepadDataFetcher* fetcher) {
DVLOG(1) << __FUNCTION__ << "(" << fetcher << ")";
gamepad_data_fetcher_ = fetcher;
gvr_gamepad_data_fetcher_ = fetcher;
}
void VrShell::RegisterCardboardGamepadDataFetcher(
device::CardboardGamepadDataFetcher* fetcher) {
DVLOG(1) << __FUNCTION__ << "(" << fetcher << ")";
cardboard_gamepad_data_fetcher_ = fetcher;
}
bool VrShell::HasDaydreamSupport(JNIEnv* env) {
......
......@@ -17,6 +17,7 @@
#include "chrome/browser/android/vr_shell/ui_interface.h"
#include "chrome/browser/android/vr_shell/vr_controller_model.h"
#include "content/public/browser/web_contents_observer.h"
#include "device/vr/android/gvr/cardboard_gamepad_data_provider.h"
#include "device/vr/android/gvr/gvr_delegate.h"
#include "device/vr/android/gvr/gvr_gamepad_data_provider.h"
#include "device/vr/vr_service.mojom.h"
......@@ -64,7 +65,8 @@ class VrMetricsHelper;
// The native instance of the Java VrShell. This class is not threadsafe and
// must only be used on the UI thread.
class VrShell : public device::PresentingGvrDelegate,
device::GvrGamepadDataProvider {
device::GvrGamepadDataProvider,
device::CardboardGamepadDataProvider {
public:
VrShell(JNIEnv* env,
jobject obj,
......@@ -83,7 +85,8 @@ class VrShell : public device::PresentingGvrDelegate,
const base::android::JavaParamRef<jobject>& obj);
void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
void OnTriggerEvent(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj);
const base::android::JavaParamRef<jobject>& obj,
bool touched);
void OnPause(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
void OnResume(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
void SetSurface(JNIEnv* env,
......@@ -114,6 +117,7 @@ class VrShell : public device::PresentingGvrDelegate,
void OnContentPaused(bool paused);
void NavigateBack();
void ExitCct();
void ToggleCardboardGamepad(bool enabled);
base::android::ScopedJavaGlobalRef<jobject> TakeContentSurface(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj);
......@@ -164,7 +168,11 @@ class VrShell : public device::PresentingGvrDelegate,
// device::GvrGamepadDataProvider implementation.
void UpdateGamepadData(device::GvrGamepadData) override;
void RegisterGamepadDataFetcher(device::GvrGamepadDataFetcher*) override;
void RegisterGvrGamepadDataFetcher(device::GvrGamepadDataFetcher*) override;
// device::CardboardGamepadDataProvider implementation.
void RegisterCardboardGamepadDataFetcher(
device::CardboardGamepadDataFetcher*) override;
private:
~VrShell() override;
......@@ -236,10 +244,15 @@ class VrShell : public device::PresentingGvrDelegate,
gvr_context* gvr_api_;
// Are we currently providing a gamepad factory to the gamepad manager?
bool gamepad_source_active_ = false;
// Registered fetcher, must remain alive for UpdateGamepadData calls.
bool gvr_gamepad_source_active_ = false;
bool cardboard_gamepad_source_active_ = false;
// Registered fetchers, must remain alive for UpdateGamepadData calls.
// That's ok since the fetcher is only destroyed from VrShell's destructor.
device::GvrGamepadDataFetcher* gamepad_data_fetcher_ = nullptr;
device::GvrGamepadDataFetcher* gvr_gamepad_data_fetcher_ = nullptr;
device::CardboardGamepadDataFetcher* cardboard_gamepad_data_fetcher_ =
nullptr;
int64_t cardboard_gamepad_timer_ = 0;
base::WeakPtrFactory<VrShell> weak_ptr_factory_;
......
......@@ -454,6 +454,11 @@ void VrShellGl::GvrInit(gvr_context* gvr_api) {
}
UMA_HISTOGRAM_ENUMERATION("VRViewerType", static_cast<int>(viewerType),
static_cast<int>(ViewerType::VIEWER_TYPE_MAX));
cardboard_ = (viewerType == ViewerType::CARDBOARD);
if (cardboard_ && web_vr_mode_) {
browser_->ToggleCardboardGamepad(true);
}
}
void VrShellGl::InitializeRenderer() {
......@@ -538,7 +543,8 @@ void VrShellGl::UpdateController(const gfx::Vector3dF& head_direction) {
controller_->UpdateState(head_direction);
pointer_start_ = controller_->GetPointerStart();
browser_->UpdateGamepadData(controller_->GetGamepadData());
device::GvrGamepadData controller_data = controller_->GetGamepadData();
browser_->UpdateGamepadData(controller_data);
}
void VrShellGl::HandleControllerInput(const gfx::Vector3dF& head_direction) {
......@@ -1402,6 +1408,11 @@ void VrShellGl::OnResume() {
void VrShellGl::SetWebVrMode(bool enabled) {
web_vr_mode_ = enabled;
if (cardboard_) {
browser_->ToggleCardboardGamepad(enabled);
}
if (!enabled) {
submit_client_.reset();
}
......
......@@ -217,6 +217,7 @@ class VrShellGl : public device::mojom::VRVSyncProvider {
std::unique_ptr<VrShellRenderer> vr_shell_renderer_;
bool cardboard_ = false;
bool touch_pending_ = false;
vr::Quatf controller_quat_;
......
......@@ -22,6 +22,7 @@ enum GamepadSource {
GAMEPAD_SOURCE_NONE = 0,
GAMEPAD_SOURCE_ANDROID,
GAMEPAD_SOURCE_GVR,
GAMEPAD_SOURCE_CARDBOARD,
GAMEPAD_SOURCE_LINUX_UDEV,
GAMEPAD_SOURCE_MAC_GC,
GAMEPAD_SOURCE_MAC_HID,
......
......@@ -45,6 +45,9 @@ if (enable_vr) {
if (is_android && (current_cpu == "arm" || current_cpu == "arm64")) {
sources += [
"android/gvr/cardboard_gamepad_data_fetcher.cc",
"android/gvr/cardboard_gamepad_data_fetcher.h",
"android/gvr/cardboard_gamepad_data_provider.h",
"android/gvr/gvr_delegate.cc",
"android/gvr/gvr_delegate.h",
"android/gvr/gvr_delegate_provider.cc",
......
// 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 "device/vr/android/gvr/cardboard_gamepad_data_fetcher.h"
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "device/gamepad/public/cpp/gamepads.h"
#include "device/vr/android/gvr/cardboard_gamepad_data_provider.h"
#include "device/vr/vr_types.h"
namespace device {
namespace {
void CopyToUString(UChar* dest, size_t dest_length, base::string16 src) {
static_assert(sizeof(base::string16::value_type) == sizeof(UChar),
"Mismatched string16/WebUChar size.");
const size_t str_to_copy = std::min(src.size(), dest_length - 1);
memcpy(dest, src.data(), str_to_copy * sizeof(base::string16::value_type));
dest[str_to_copy] = 0;
}
} // namespace
CardboardGamepadDataFetcher::Factory::Factory(
CardboardGamepadDataProvider* data_provider,
unsigned int display_id)
: data_provider_(data_provider), display_id_(display_id) {
DVLOG(1) << __FUNCTION__ << "=" << this;
}
CardboardGamepadDataFetcher::Factory::~Factory() {
DVLOG(1) << __FUNCTION__ << "=" << this;
}
std::unique_ptr<GamepadDataFetcher>
CardboardGamepadDataFetcher::Factory::CreateDataFetcher() {
return base::MakeUnique<CardboardGamepadDataFetcher>(data_provider_,
display_id_);
}
GamepadSource CardboardGamepadDataFetcher::Factory::source() {
return GAMEPAD_SOURCE_CARDBOARD;
}
CardboardGamepadDataFetcher::CardboardGamepadDataFetcher(
CardboardGamepadDataProvider* data_provider,
unsigned int display_id)
: display_id_(display_id) {
// Called on UI thread.
DVLOG(1) << __FUNCTION__ << "=" << this;
data_provider->RegisterCardboardGamepadDataFetcher(this);
}
CardboardGamepadDataFetcher::~CardboardGamepadDataFetcher() {
DVLOG(1) << __FUNCTION__ << "=" << this;
}
GamepadSource CardboardGamepadDataFetcher::source() {
return GAMEPAD_SOURCE_CARDBOARD;
}
void CardboardGamepadDataFetcher::OnAddedToProvider() {
PauseHint(false);
}
void CardboardGamepadDataFetcher::SetGamepadData(CardboardGamepadData data) {
// Called from UI thread.
gamepad_data_ = data;
}
void CardboardGamepadDataFetcher::GetGamepadData(bool devices_changed_hint) {
// Called from gamepad polling thread.
PadState* state = GetPadState(0);
if (!state)
return;
CardboardGamepadData provided_data = gamepad_data_;
Gamepad& pad = state->data;
if (state->active_state == GAMEPAD_NEWLY_ACTIVE) {
// This is the first time we've seen this device, so do some one-time
// initialization
pad.connected = true;
CopyToUString(pad.id, Gamepad::kIdLengthCap,
base::UTF8ToUTF16("Cardboard Button"));
CopyToUString(pad.mapping, Gamepad::kMappingLengthCap,
base::UTF8ToUTF16(""));
pad.buttons_length = 1;
pad.axes_length = 0;
pad.display_id = display_id_;
pad.hand = GamepadHand::kNone;
}
pad.timestamp = provided_data.timestamp;
bool pressed = provided_data.is_screen_touching;
pad.buttons[0].touched = pressed;
pad.buttons[0].pressed = pressed;
pad.buttons[0].value = pressed ? 1.0f : 0.0f;
pad.pose.not_null = false;
}
void CardboardGamepadDataFetcher::PauseHint(bool paused) {}
} // namespace device
// 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.
#ifndef DEVICE_VR_ANDROID_CARDBOARD_GAMEPAD_DATA_FETCHER_H_
#define DEVICE_VR_ANDROID_CARDBOARD_GAMEPAD_DATA_FETCHER_H_
#include <string>
#include "device/gamepad/gamepad_data_fetcher.h"
#include "device/vr/android/gvr/cardboard_gamepad_data_provider.h"
#include "device/vr/vr_export.h"
namespace device {
class DEVICE_VR_EXPORT CardboardGamepadDataFetcher : public GamepadDataFetcher {
public:
class Factory : public GamepadDataFetcherFactory {
public:
Factory(CardboardGamepadDataProvider*, unsigned int display_id);
~Factory() override;
std::unique_ptr<GamepadDataFetcher> CreateDataFetcher() override;
GamepadSource source() override;
private:
CardboardGamepadDataProvider* data_provider_;
unsigned int display_id_;
};
CardboardGamepadDataFetcher(CardboardGamepadDataProvider*,
unsigned int display_id);
~CardboardGamepadDataFetcher() override;
GamepadSource source() override;
void GetGamepadData(bool devices_changed_hint) override;
void PauseHint(bool paused) override;
void OnAddedToProvider() override;
// Called from CardboardGamepadDataProvider
void SetGamepadData(CardboardGamepadData);
private:
unsigned int display_id_;
CardboardGamepadData gamepad_data_;
DISALLOW_COPY_AND_ASSIGN(CardboardGamepadDataFetcher);
};
} // namespace device
#endif // DEVICE_VR_ANDROID_CARDBOARD_GAMEPAD_DATA_FETCHER_H_
// 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.
#ifndef DEVICE_VR_ANDROID_CARDBOARD_GAMEPAD_DATA_PROVIDER_H
#define DEVICE_VR_ANDROID_CARDBOARD_GAMEPAD_DATA_PROVIDER_H
#include "device/vr/vr_types.h"
namespace device {
class CardboardGamepadDataFetcher;
// Filled in by vr_shell and consumed by CardboardGamepadDataFetcher.
struct CardboardGamepadData {
int64_t timestamp;
bool is_screen_touching;
};
// This class exposes Cardboard controller (screen touch) data to the gamepad
// API. Data is reported by VrShell, which implements the
// CardboardGamepadDataProvider interface.
//
// More specifically, here's the lifecycle, assuming VrShell
// implements GvrGamepadDataProvider:
//
// - VrShell creates CardboardGamepadDataFetcherFactory during initialization if
// a cardboard is in use, or when WebVR presentation starts.
//
// - CardboardGamepadDataFetcherFactory creates CardboardGamepadDataFetcher.
//
// - CardboardGamepadDataFetcher registers itself with VrShell via
// VrShell::RegisterCardboardGamepadDataFetcher.
//
// - While presenting, VrShell::OnTouch calls
// CardboardGamepadDataFetcher->SetGamepadData to push button state,
// CardboardGamepadDataFetcher::GetGamepadData returns this when polled.
//
// - VrShell starts executing its destructor or WebVR presentation ends.
//
// - VrShell destructor unregisters CardboardGamepadDataFetcherFactory.
//
// - CardboardGamepadDataFetcherFactory destructor destroys
// CardboardGamepadDataFetcher.
//
class CardboardGamepadDataProvider {
public:
// Called by the gamepad data fetcher constructor to register itself
// for receiving data via SetGamepadData. The fetcher must remain
// alive while the provider is calling SetGamepadData on it.
virtual void RegisterCardboardGamepadDataFetcher(
CardboardGamepadDataFetcher*) = 0;
};
} // namespace device
#endif // DEVICE_VR_ANDROID_CARDBOARD_GAMEPAD_DATA_PROVIDER_H
......@@ -50,7 +50,7 @@ GvrGamepadDataFetcher::GvrGamepadDataFetcher(
: display_id_(display_id) {
// Called on UI thread.
DVLOG(1) << __FUNCTION__ << "=" << this;
data_provider->RegisterGamepadDataFetcher(this);
data_provider->RegisterGvrGamepadDataFetcher(this);
}
GvrGamepadDataFetcher::~GvrGamepadDataFetcher() {
......
......@@ -60,7 +60,7 @@ class GvrGamepadDataProvider {
// Called by the gamepad data fetcher constructor to register itself
// for receiving data via SetGamepadData. The fetcher must remain
// alive while the provider is calling SetGamepadData on it.
virtual void RegisterGamepadDataFetcher(GvrGamepadDataFetcher*) = 0;
virtual void RegisterGvrGamepadDataFetcher(GvrGamepadDataFetcher*) = 0;
};
} // namespace device
......
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