Skip to content

Commit

Permalink
Gamepad API support for chrome on android
Browse files Browse the repository at this point in the history
This change adds code to get gamepad data from java objects and
provide these updates to the GamepadProvider which then writes to
GamepadHardwareBuffer which in turn is read by SharedMemoryReader and
later returned by JS to the web page.

This also adds new framework classes/methods required for Gamepad API
support. Frameworks changes are responsible for :
  - Identifying gamepad devices and their capabilities.
  - Managing connected gamepad devices
  - Map the connected gamepad devices to standard Gamepad format.
  - Keeping gamepads axes/buttons data up-to-date and returning it to
    native whenever requested. In android we cannot get gamepad data
    directly from sources, so framework is modified to capture
    gamepad key and motion events and extract gamepad data from these
    events.

* Class GamepadPlatformDataFetcherAndroid : Android specific
  implementation of gamepad data fetcher.
  - Responsible for communication with java class and accessing gamepad data.
  - It adds methods for communication with singleton java GamepadList class
to get gamepads data.

* Class ContentViewCore : Manages gamepad list and notifies of new
  key/motion event for gamepads.

* Class GamepadList : A new class to manage connected gamepad devices

* Class GamepadDevice : A new class to manage information related to
  each gamepad device.

* Class GamepadMappings : This class is responsible for mapping of
  known gamepads to the standard gamepad.

This change enables gamepad API by default.

Adds support for parsing float array return type in JNI generator.

NVIDIA Shield and XBox360 gamepads are mapped to the standard gamepad

BUG=330094

TEST=http://www.html5rocks.com/en/tutorials/doodles/gamepad/gamepad-tester/tester.html

R=tsepez@chromium.org
R=darin@chromium.org

Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=270620

Review URL: https://codereview.chromium.org/133943002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274212 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
skhatri@nvidia.com committed Jun 2, 2014
1 parent a80607d commit 41dada5
Show file tree
Hide file tree
Showing 20 changed files with 931 additions and 5 deletions.
2 changes: 2 additions & 0 deletions android_webview/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ $(call intermediates-dir-for,GYP,shared,,,$(TARGET_2ND_ARCH))/templates/org/chro
$(call intermediates-dir-for,GYP,shared,,,$(TARGET_2ND_ARCH))/templates/org/chromium/content/browser/GestureEventType.java \
$(call intermediates-dir-for,GYP,shared,,,$(TARGET_2ND_ARCH))/templates/org/chromium/content/browser/PageTransitionTypes.java \
$(call intermediates-dir-for,GYP,shared,,,$(TARGET_2ND_ARCH))/templates/org/chromium/content/browser/SpeechRecognitionError.java \
$(call intermediates-dir-for,GYP,shared,,,$(TARGET_2ND_ARCH))/templates/org/chromium/content/browser/input/CanonicalAxisIndex.java \
$(call intermediates-dir-for,GYP,shared,,,$(TARGET_2ND_ARCH))/templates/org/chromium/content/browser/input/CanonicalButtonIndex.java \
$(call intermediates-dir-for,GYP,shared,,,$(TARGET_2ND_ARCH))/templates/org/chromium/content/browser/input/PopupItemType.java \
$(call intermediates-dir-for,GYP,shared,,,$(TARGET_2ND_ARCH))/templates/org/chromium/content/common/ResultCodes.java \
$(call intermediates-dir-for,GYP,shared,,,$(TARGET_2ND_ARCH))/templates/org/chromium/content/common/ScreenOrientationValues.java \
Expand Down
1 change: 1 addition & 0 deletions android_webview/android_webview.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
'dependencies': [
'../base/base.gyp:base_java_application_state',
'../base/base.gyp:base_java_memory_pressure_level_list',
'../content/content.gyp:content_gamepad_mapping',
'../content/content.gyp:gesture_event_type_java',
'../content/content.gyp:page_transition_types_java',
'../content/content.gyp:popup_item_type_java',
Expand Down
1 change: 1 addition & 0 deletions base/android/jni_generator/jni_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@ def GetStaticCastForReturnType(return_type):
'short[]': 'jshortArray',
'int[]': 'jintArray',
'long[]': 'jlongArray',
'float[]': 'jfloatArray',
'double[]': 'jdoubleArray' }
ret = type_map.get(return_type, None)
if ret:
Expand Down
3 changes: 3 additions & 0 deletions content/browser/android/browser_jni_registrar.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "content/browser/battery_status/battery_status_manager.h"
#include "content/browser/device_sensors/sensor_manager_android.h"
#include "content/browser/frame_host/navigation_controller_android.h"
#include "content/browser/gamepad/gamepad_platform_data_fetcher_android.h"
#include "content/browser/geolocation/location_api_adapter_android.h"
#include "content/browser/media/android/media_drm_credential_manager.h"
#include "content/browser/media/android/media_resource_getter_impl.h"
Expand Down Expand Up @@ -62,6 +63,8 @@ base::android::RegistrationMethod kContentRegisteredMethods[] = {
{"DateTimePickerAndroid", content::RegisterDateTimeChooserAndroid},
{"DownloadControllerAndroidImpl",
content::DownloadControllerAndroidImpl::RegisterDownloadController},
{"GamepadList", content::GamepadPlatformDataFetcherAndroid::
RegisterGamepadPlatformDataFetcherAndroid},
{"InterstitialPageDelegateAndroid",
content::InterstitialPageDelegateAndroid::
RegisterInterstitialPageDelegateAndroid},
Expand Down
16 changes: 16 additions & 0 deletions content/browser/gamepad/canonical_axis_index_list.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2014 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.

// This file intentionally does not have header guards, it's included
// inside a macro to generate enum values.

// This file defines the canonical axes mapping order for gamepad-like devices.

// TODO(SaurabhK): Consolidate with CanonicalAxisIndex enum in
// gamepad_standard_mappings.h, crbug.com/351558.
CANONICAL_AXIS_INDEX(AXIS_LEFT_STICK_X, 0)
CANONICAL_AXIS_INDEX(AXIS_LEFT_STICK_Y, 1)
CANONICAL_AXIS_INDEX(AXIS_RIGHT_STICK_X, 2)
CANONICAL_AXIS_INDEX(AXIS_RIGHT_STICK_Y, 3)
CANONICAL_AXIS_INDEX(NUM_CANONICAL_AXES, 4)
28 changes: 28 additions & 0 deletions content/browser/gamepad/canonical_button_index_list.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2014 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.

// This file intentionally does not have header guards, it's included
// inside a macro to generate enum values.
// This defines the canonical button mapping order for gamepad-like devices.

// TODO(SaurabhK): Consolidate with CanonicalButtonIndex enum in
// gamepad_standard_mappings.h, crbug.com/351558.
CANONICAL_BUTTON_INDEX(BUTTON_PRIMARY, 0)
CANONICAL_BUTTON_INDEX(BUTTON_SECONDARY, 1)
CANONICAL_BUTTON_INDEX(BUTTON_TERTIARY, 2)
CANONICAL_BUTTON_INDEX(BUTTON_QUATERNARY, 3)
CANONICAL_BUTTON_INDEX(BUTTON_LEFT_SHOULDER, 4)
CANONICAL_BUTTON_INDEX(BUTTON_RIGHT_SHOULDER, 5)
CANONICAL_BUTTON_INDEX(BUTTON_LEFT_TRIGGER, 6)
CANONICAL_BUTTON_INDEX(BUTTON_RIGHT_TRIGGER, 7)
CANONICAL_BUTTON_INDEX(BUTTON_BACK_SELECT, 8)
CANONICAL_BUTTON_INDEX(BUTTON_START, 9)
CANONICAL_BUTTON_INDEX(BUTTON_LEFT_THUMBSTICK, 10)
CANONICAL_BUTTON_INDEX(BUTTON_RIGHT_THUMBSTICK, 11)
CANONICAL_BUTTON_INDEX(BUTTON_DPAD_UP, 12)
CANONICAL_BUTTON_INDEX(BUTTON_DPAD_DOWN, 13)
CANONICAL_BUTTON_INDEX(BUTTON_DPAD_LEFT, 14)
CANONICAL_BUTTON_INDEX(BUTTON_DPAD_RIGHT, 15)
CANONICAL_BUTTON_INDEX(BUTTON_META, 16)
CANONICAL_BUTTON_INDEX(NUM_CANONICAL_BUTTONS, 17)
10 changes: 8 additions & 2 deletions content/browser/gamepad/gamepad_platform_data_fetcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
#include "base/compiler_specific.h"
#include "content/browser/gamepad/gamepad_data_fetcher.h"

#if defined(OS_WIN)
#if defined(OS_ANDROID)
#include "content/browser/gamepad/gamepad_platform_data_fetcher_android.h"
#elif defined(OS_WIN)
#include "content/browser/gamepad/gamepad_platform_data_fetcher_win.h"
#elif defined(OS_MACOSX)
#include "content/browser/gamepad/gamepad_platform_data_fetcher_mac.h"
Expand All @@ -22,7 +24,11 @@

namespace content {

#if defined(OS_WIN)
#if defined(OS_ANDROID)

typedef GamepadPlatformDataFetcherAndroid GamepadPlatformDataFetcher;

#elif defined(OS_WIN)

typedef GamepadPlatformDataFetcherWin GamepadPlatformDataFetcher;

Expand Down
149 changes: 149 additions & 0 deletions content/browser/gamepad/gamepad_platform_data_fetcher_android.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// Copyright 2014 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/gamepad/gamepad_platform_data_fetcher_android.h"

#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/debug/trace_event.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"

#include "jni/GamepadList_jni.h"

#include "third_party/WebKit/public/platform/WebGamepads.h"

using base::android::AttachCurrentThread;
using base::android::CheckException;
using base::android::ClearException;
using base::android::ConvertJavaStringToUTF8;
using base::android::ScopedJavaLocalRef;
using blink::WebGamepad;
using blink::WebGamepads;

namespace content {

bool
GamepadPlatformDataFetcherAndroid::RegisterGamepadPlatformDataFetcherAndroid(
JNIEnv* env) {
return RegisterNativesImpl(env);
}

GamepadPlatformDataFetcherAndroid::GamepadPlatformDataFetcherAndroid() {
PauseHint(false);
}

GamepadPlatformDataFetcherAndroid::~GamepadPlatformDataFetcherAndroid() {
PauseHint(true);
}

void GamepadPlatformDataFetcherAndroid::GetGamepadData(
blink::WebGamepads* pads,
bool devices_changed_hint) {
TRACE_EVENT0("GAMEPAD", "GetGamepadData");

pads->length = 0;

JNIEnv* env = AttachCurrentThread();
if (!env)
return;

Java_GamepadList_updateGamepadData(env, reinterpret_cast<intptr_t>(pads));
}

void GamepadPlatformDataFetcherAndroid::PauseHint(bool paused) {
JNIEnv* env = AttachCurrentThread();
if (!env)
return;

Java_GamepadList_notifyForGamepadsAccess(env, paused);
}

static void SetGamepadData(JNIEnv* env,
jobject obj,
jlong gamepads,
jint index,
jboolean mapping,
jboolean connected,
jstring devicename,
jlong timestamp,
jfloatArray jaxes,
jfloatArray jbuttons) {
DCHECK(gamepads);
blink::WebGamepads* pads = reinterpret_cast<WebGamepads*>(gamepads);
DCHECK_EQ(pads->length, unsigned(index));
DCHECK_LT(index, static_cast<int>(blink::WebGamepads::itemsLengthCap));

++pads->length;

blink::WebGamepad& pad = pads->items[index];

pad.connected = connected;

pad.timestamp = timestamp;

// Do not set gamepad parameters for all the gamepad devices that are not
// attached.
if (!connected)
return;

// Map the Gamepad DeviceName String to the WebGamepad Id. Ideally it should
// be mapped to vendor and product information but it is only available at
// kernel level and it can not be queried using class
// android.hardware.input.InputManager.
// TODO(SaurabhK): Store a cached WebGamePad object in
// GamepadPlatformDataFetcherAndroid and only update constant WebGamepad
// values when a device has changed.
base::string16 device_name;
base::android::ConvertJavaStringToUTF16(env, devicename, &device_name);
const size_t name_to_copy =
std::min(device_name.size(), WebGamepad::idLengthCap - 1);
memcpy(pad.id,
device_name.data(),
name_to_copy * sizeof(base::string16::value_type));
pad.id[name_to_copy] = 0;

base::string16 mapping_name = base::UTF8ToUTF16(mapping ? "standard" : "");
const size_t mapping_to_copy =
std::min(mapping_name.size(), WebGamepad::mappingLengthCap - 1);
memcpy(pad.mapping,
mapping_name.data(),
mapping_to_copy * sizeof(base::string16::value_type));
pad.mapping[mapping_to_copy] = 0;

pad.timestamp = timestamp;

std::vector<float> axes;
base::android::JavaFloatArrayToFloatVector(env, jaxes, &axes);

// Set WebGamepad axeslength to total number of axes on the gamepad device.
// Only return the first axesLengthCap if axeslength captured by GamepadList
// is larger than axesLengthCap.
pad.axesLength = std::min(static_cast<int>(axes.size()),
static_cast<int>(WebGamepad::axesLengthCap));

// Copy axes state to the WebGamepad axes[].
for (unsigned int i = 0; i < pad.axesLength; i++) {
pad.axes[i] = static_cast<double>(axes[i]);
}

std::vector<float> buttons;
base::android::JavaFloatArrayToFloatVector(env, jbuttons, &buttons);

// Set WebGamepad buttonslength to total number of axes on the gamepad
// device. Only return the first buttonsLengthCap if axeslength captured by
// GamepadList is larger than buttonsLengthCap.
pad.buttonsLength = std::min(static_cast<int>(buttons.size()),
static_cast<int>(WebGamepad::buttonsLengthCap));

// Copy buttons state to the WebGamepad buttons[].
for (unsigned int j = 0; j < pad.buttonsLength; j++) {
pad.buttons[j].pressed = buttons[j];
pad.buttons[j].value = buttons[j];
}
}

} // namespace content
40 changes: 40 additions & 0 deletions content/browser/gamepad/gamepad_platform_data_fetcher_android.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright 2014 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.

// Define the data fetcher that GamepadProvider will use for android port.
// (GamepadPlatformDataFetcher).

#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_ANDROID_H_
#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_ANDROID_H_

#include <jni.h>

#include "base/android/jni_android.h"
#include "content/browser/gamepad/gamepad_data_fetcher.h"
#include "content/browser/gamepad/gamepad_provider.h"
#include "content/browser/gamepad/gamepad_standard_mappings.h"
#include "third_party/WebKit/public/platform/WebGamepads.h"

namespace content {

class GamepadPlatformDataFetcherAndroid : public GamepadDataFetcher {
public:
GamepadPlatformDataFetcherAndroid();
virtual ~GamepadPlatformDataFetcherAndroid();

virtual void PauseHint(bool paused) OVERRIDE;

virtual void GetGamepadData(blink::WebGamepads* pads,
bool devices_changed_hint) OVERRIDE;

// Registers the JNI methods for GamepadsReader.
static bool RegisterGamepadPlatformDataFetcherAndroid(JNIEnv* env);

private:
DISALLOW_COPY_AND_ASSIGN(GamepadPlatformDataFetcherAndroid);
};

} // namespace content

#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_ANDROID_H_
4 changes: 4 additions & 0 deletions content/browser/gamepad/gamepad_provider.cc
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ void GamepadProvider::Initialize(scoped_ptr<GamepadDataFetcher> fetcher) {
// On Linux, the data fetcher needs to watch file descriptors, so the message
// loop needs to be a libevent loop.
const base::MessageLoop::Type kMessageLoopType = base::MessageLoop::TYPE_IO;
#elif defined(OS_ANDROID)
// On Android, keeping a message loop of default type.
const base::MessageLoop::Type kMessageLoopType =
base::MessageLoop::TYPE_DEFAULT;
#else
// On Mac, the data fetcher uses IOKit which depends on CFRunLoop, so the
// message loop needs to be a UI-type loop. On Windows it must be a UI loop
Expand Down
7 changes: 5 additions & 2 deletions content/child/runtime_features.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#if defined(OS_ANDROID)
#include <cpu-features.h>
#include "base/android/build_info.h"
#include "media/base/android/media_codec_bridge.h"
#endif

Expand All @@ -33,8 +34,10 @@ static void SetRuntimeFeatureDefaultsForPlatform() {
media::MediaCodecBridge::IsAvailable() &&
((android_getCpuFamily() == ANDROID_CPU_FAMILY_ARM) ||
(android_getCpuFamily() == ANDROID_CPU_FAMILY_X86)));
// Android does not support the Gamepad API.
WebRuntimeFeatures::enableGamepad(false);

// Android supports gamepad API for JellyBean and beyond
WebRuntimeFeatures::enableGamepad(
base::android::BuildInfo::GetInstance()->sdk_int() >= 16);
// Android does not have support for PagePopup
WebRuntimeFeatures::enablePagePopup(false);
// Android does not yet support the Web Notification API. crbug.com/115320
Expand Down
17 changes: 17 additions & 0 deletions content/content.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@
'common_aidl',
'content_common',
'content_strings_grd',
'content_gamepad_mapping',
'gesture_event_type_java',
'page_transition_types_java',
'popup_item_type_java',
Expand Down Expand Up @@ -545,6 +546,22 @@
}],
],
},
{
'target_name': 'content_gamepad_mapping',
'type': 'none',
'sources': [
'public/android/java/src/org/chromium/content/browser/input/CanonicalButtonIndex.template',
'public/android/java/src/org/chromium/content/browser/input/CanonicalAxisIndex.template',
],
'variables': {
'package_name': 'org/chromium/content/browser/input',
'template_deps': [
'browser/gamepad/canonical_axis_index_list.h',
'browser/gamepad/canonical_button_index_list.h',
],
},
'includes': [ '../build/android/java_cpp_template.gypi' ],
},
],
}], # OS == "android"
],
Expand Down
4 changes: 3 additions & 1 deletion content/content_browser.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,8 @@
'browser/gamepad/gamepad_consumer.h',
'browser/gamepad/gamepad_data_fetcher.h',
'browser/gamepad/gamepad_platform_data_fetcher.h',
'browser/gamepad/gamepad_platform_data_fetcher_android.cc',
'browser/gamepad/gamepad_platform_data_fetcher_android.h',
'browser/gamepad/gamepad_platform_data_fetcher_linux.cc',
'browser/gamepad/gamepad_platform_data_fetcher_linux.h',
'browser/gamepad/gamepad_platform_data_fetcher_mac.h',
Expand Down Expand Up @@ -1426,7 +1428,7 @@
'browser/power_profiler/power_data_provider_dummy.cc'
]
}],
['OS!="win" and OS!="mac" and (OS!="linux" or use_udev==0)', {
['OS!="win" and OS!="mac" and OS!="android" and (OS!="linux" or use_udev==0)', {
'sources': [
'browser/gamepad/gamepad_platform_data_fetcher.cc',
]
Expand Down
1 change: 1 addition & 0 deletions content/content_jni.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
'public/android/java/src/org/chromium/content/browser/ContentViewStatics.java',
'public/android/java/src/org/chromium/content/browser/DeviceSensors.java',
'public/android/java/src/org/chromium/content/browser/DownloadController.java',
'public/android/java/src/org/chromium/content/browser/input/GamepadList.java',
'public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java',
'public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java',
'public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java',
Expand Down
Loading

0 comments on commit 41dada5

Please sign in to comment.