Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1154)

Unified Diff: content/public/android/java/src/org/chromium/content/browser/GamepadList.java

Issue 133943002: Gamepad API support for chrome on android (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/public/android/java/src/org/chromium/content/browser/GamepadList.java
diff --git a/content/public/android/java/src/org/chromium/content/browser/GamepadList.java b/content/public/android/java/src/org/chromium/content/browser/GamepadList.java
new file mode 100644
index 0000000000000000000000000000000000000000..47a89f15ff1c0c5ffcdf694da9f8ab460d95edf8
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content/browser/GamepadList.java
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of NVIDIA CORPORATION nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package org.chromium.content.browser;
+
+import android.content.Context;
+import android.hardware.input.InputManager;
+import android.hardware.input.InputManager.InputDeviceListener;
+import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import org.chromium.base.CalledByNative;
+
+/*
+ * Class to manage connected gamepad devices list.
+ */
+class GamepadList implements InputDeviceListener {
+ private static final int MAX_GAMEPADS = 4;
+ private GamepadDevice[] mGamepadDevices = new GamepadDevice[MAX_GAMEPADS];
+ protected boolean mHaveDevicesBeenInteractedWith = false;
+ private boolean IS_GAMEPAD_ACCESSED = false;
+ private InputManager inputManager;
+
+ private GamepadList(Context context) {
+
+ inputManager = (InputManager) context.getSystemService(Context.INPUT_SERVICE);
+ // Get list of all the attached input devices.
+ int[] deviceIds = inputManager.getInputDeviceIds();
+
+ for (int i = 0; i < deviceIds.length; i++) {
+ InputDevice inputDevice = InputDevice.getDevice(deviceIds[i]);
+ // Check for gamepad device
+ if (isGamepadDevice(inputDevice)) {
+ // Register a new gamepad device.
+ registerGamepad(inputDevice);
+ }
+ }
+ // Register an input device listener.
+ inputManager.registerInputDeviceListener(this, null);
+ }
+
+ private static GamepadList gamepadList = null;
+
+ public boolean haveDevicesBeenInteractedWith() { return mHaveDevicesBeenInteractedWith; }
+
+ // Override InputDeviceListener methods
+ @Override
+ public void onInputDeviceChanged(int deviceId) {
+ }
+
+ @Override
+ public void onInputDeviceRemoved(int deviceId) {
+ unregisterGamepad(deviceId);
+ }
+
+ @Override
+ public void onInputDeviceAdded(int deviceId) {
+ InputDevice inputDevice = InputDevice.getDevice(deviceId);
+ if (isGamepadDevice(inputDevice))
+ registerGamepad(inputDevice);
+ }
+
+ public static GamepadList createInstance(Context context) {
+ if (gamepadList != null) {
+ return gamepadList;
+ } else {
+ gamepadList = new GamepadList(context);
+ return gamepadList;
+ }
+ }
+
+ @CalledByNative
+ public static GamepadList getInstance() {
+ if (gamepadList != null) {
+ return gamepadList;
+ } else {
+ return null;
+ }
+ }
+
+ @CalledByNative
+ private void notifyForGamepadsAccess(boolean isaccesspaused) {
+ IS_GAMEPAD_ACCESSED = !isaccesspaused;
+ }
+
+ @CalledByNative
+ private GamepadList getGamepadList() {
+ // Gamepads must only appear in the list if they are currently connected to the user agent,
+ // and at least one device has been interacted with by the user. If no devices have been
+ // interacted with, devices must not appear in the list to avoid a malicious page from
+ // fingerprinting the user.
+ if (haveDevicesBeenInteractedWith()) {
+ return gamepadList;
+ }
+ else {
+ return null;
+ }
+ }
+
+ @CalledByNative
+ private int getDeviceCount() {
+ int count = 0;
+ for (int i = 0; i < getCount(); ++i) {
+ if (getDevice(i) != null) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ @CalledByNative
+ private String getDeviceName(int index) {
+ return getDevice(index).getName();
+ }
+
+ @CalledByNative
+ private long getDeviceTimestamp(int index) {
+ return getDevice(index).getTimestamp();
+ }
+
+ @CalledByNative
+ private float[] getDeviceAxes(int index) {
+ return getDevice(index).getAxes();
+ }
+
+ @CalledByNative
+ private float[] getDeviceButtons(int index) {
+ return getDevice(index).getButtons();
+ }
+
+ @CalledByNative
+ private boolean isDeviceConnected(int index) {
+ if (index < MAX_GAMEPADS && getDevice(index) != null) {
+ return true;
+ }
+ return false;
+ }
+
+ @CalledByNative
+ private boolean isKnownGamepadLayout(int index) {
+ return getDevice(index).isKnownGamepadLayout();
+ }
+
+ public GamepadDevice getDeviceById(int deviceId) {
+ for (int i = 0; i < getCount(); ++i) {
+ GamepadDevice gamepad = mGamepadDevices[i];
+ if (gamepad != null && gamepad.getId() == deviceId) {
+ return gamepad;
+ }
+ }
+ return null;
+ }
+
+ public GamepadDevice getDevice(int index) {
+ // Maximum 4 Gamepads can be connected at a time starting at index zero.
+ assert index >= 0 && index <= getCount() - 1;
+ return mGamepadDevices[index];
+ }
+
+ public int getCount() {
+ return MAX_GAMEPADS;
+ }
+
+ public boolean updateForEvent(KeyEvent event) {
+ GamepadDevice gamepad = getGamepadForEvent(event);
+ if (gamepad != null) {
+ mHaveDevicesBeenInteractedWith = true;
+ return gamepad.updateForEvent(event);
+ }
+ return false;
+ }
+
+ public boolean updateForEvent(MotionEvent event) {
+ GamepadDevice gamepad = getGamepadForEvent(event);
+ if (gamepad != null) {
+ mHaveDevicesBeenInteractedWith = true;
+ return gamepad.updateForEvent(event);
+ }
+ return false;
+ }
+
+ public void onPause() {
+ inputManager.unregisterInputDeviceListener(this);
+ }
+
+ public void onResume() {
+ // Re-initialize gamepad list.
+ // Check if any registered gamepad is disconnected when webview was in pause state.
+ for (int i = 0; i < getCount(); ++i) {
+ if (mGamepadDevices[i] != null) {
+ InputDevice device = InputDevice.getDevice(mGamepadDevices[i].getId());
+ if (device == null) {
+ // Remove disconnected gamepad.
+ mGamepadDevices[i] = null;
+ }
+ }
+ }
+ // Check if any new gamepad is connected when webview was in pause state.
+ int[] deviceIds = inputManager.getInputDeviceIds();
+ for (int i = 0; i < deviceIds.length; ++i) {
+ InputDevice device = InputDevice.getDevice(deviceIds[i]);
+ if (isGamepadDevice(device)) {
+ GamepadDevice gamepad = getDeviceById(deviceIds[i]);
+ if (gamepad == null) {
+ // Found unregistered gamepad, could be a new device connected when
+ // webview was in puase state or disconnected and re-connected same device.
+ registerGamepad(device);
+ }
+ }
+ }
+ inputManager.registerInputDeviceListener(this, null);
+ }
+
+ protected int getNextAvailableIndex() {
+ // When multiple gamepads are connected to a user agent, indices must be assigned on a
+ // first-come first-serve basis, starting at zero. If a gamepad is disconnected, previously
+ // assigned indices must not be reassigned to gamepads that continue to be connected.
+ // However, if a gamepad is disconnected, and subsequently the same or a different
+ // gamepad is then connected, index entries must be reused.
+
+ for (int i = 0; i < getCount(); ++i) {
+ if (getDevice(i) == null) {
+ return i;
+ }
+ }
+ // Reached maximum gamepads limit.
+ return -1;
+ }
+
+ protected boolean registerGamepad(InputDevice inputDevice) {
+ int index = getNextAvailableIndex();
+ if (index == -1) {
+ return false; // invalid index
+ }
+
+ GamepadDevice gamepad = new GamepadDevice(index, inputDevice);
+ mGamepadDevices[index] = gamepad;
+ return true;
+ }
+
+ protected void unregisterGamepad(int deviceId) {
+ GamepadDevice gamepadDevice = getDeviceById(deviceId);
+ if (gamepadDevice == null) {
+ return; // Not a registered device.
+ }
+ int index = gamepadDevice.getIndex();
+ mGamepadDevices[index] = null;
+ }
+
+ private boolean isGamepadDevice(InputDevice inputDevice) {
+ int sources = inputDevice.getSources();
+ if ((sources & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK ) {
+ //Found gamepad device
+ return true;
+ }
+ return false;
+ }
+
+ private GamepadDevice getGamepadForEvent(InputEvent event) {
+ int deviceId = event.getDeviceId();
+ GamepadDevice gamepad = getDeviceById(deviceId);
+ return gamepad;
+ }
+
+ public boolean isGamepadAccessed() {
+ return IS_GAMEPAD_ACCESSED;
+ }
+
+ public boolean isGamepadEvent(MotionEvent event) {
+ if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK) {
+ return true;
+ }
+ return false;
+ }
+
+ // Returns true if event's keycode corresponds to a gamepad key.
+ // Specific handling for dpad keys is required because
+ // KeyEvent.isGamepadButton doesn't consider dpad keys.
+ public boolean isGamepadEvent(KeyEvent event) {
+ int keyCode = event.getKeyCode();
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_UP:
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ return true;
+ default:
+ return KeyEvent.isGamepadButton(keyCode);
+ }
+ }
+
+}

Powered by Google App Engine
This is Rietveld 408576698