Index: content/public/android/java/src/org/chromium/content/browser/input/GamepadList.java |
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/GamepadList.java b/content/public/android/java/src/org/chromium/content/browser/input/GamepadList.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..820860cc7edebc88f8cfeff338e68b05c39c3d68 |
--- /dev/null |
+++ b/content/public/android/java/src/org/chromium/content/browser/input/GamepadList.java |
@@ -0,0 +1,307 @@ |
+// 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. |
+ |
+package org.chromium.content.browser.input; |
+ |
+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; |
+import org.chromium.base.JNINamespace; |
+import org.chromium.base.ThreadUtils; |
+ |
+@JNINamespace("content") |
Ted C
2014/04/16 23:36:53
the annotations usually go right above the class d
SaurabhK
2014/04/18 14:51:57
On 2014/04/16 23:36:53, Ted C wrote:
Done.
|
+ |
+/** |
+ * Class to manage connected gamepad devices list. |
+ * |
+ * It is a Java counterpart of GamepadPlatformDataFetcherAndroid and feeds Gamepad API with input |
+ * data. |
+ */ |
+public class GamepadList implements InputDeviceListener { |
+ private static final int MAX_GAMEPADS = 4; |
+ |
+ private static GamepadList sGamepadList = null; |
+ |
+ private final Object mLock = new Object(); |
+ |
+ private GamepadDevice[] mGamepadDevices = new GamepadDevice[MAX_GAMEPADS]; |
+ private InputManager mInputManager; |
+ private int mAttachedToWindowCounter; |
+ private boolean mIsGamepadAccessed; |
+ |
+ private GamepadList() {} |
+ |
+ private void initializeDevices() { |
+ // Get list of all the attached input devices. |
+ int[] deviceIds = mInputManager.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); |
+ } |
+ } |
+ } |
+ |
+ /** |
+ * Notifies the GamepadList that a {@link ContentView} is attached to a window and it should |
+ * prepare itself for gamepad input. It must be called before {@link onGenericMotionEvent} and |
+ * {@link dispatchKeyEvent}. |
+ */ |
+ public static void onAttachedToWindow(Context context) { |
+ assert ThreadUtils.runningOnUiThread(); |
+ createInstance(); |
+ sGamepadList.attachedToWindow(context); |
+ } |
+ |
+ private void attachedToWindow(Context context) { |
+ if (mAttachedToWindowCounter++ == 0) { |
+ mInputManager = (InputManager) context.getSystemService(Context.INPUT_SERVICE); |
Ted C
2014/04/16 23:36:53
one too many spaces after the =
SaurabhK
2014/04/18 14:51:57
On 2014/04/16 23:36:53, Ted C wrote:
Done.
|
+ synchronized (mLock) { |
+ initializeDevices(); |
+ } |
+ // Register an input device listener. |
+ mInputManager.registerInputDeviceListener(this, null); |
+ } |
+ } |
+ |
+ /** |
+ * Notifies the GamepadList that a {@link ContentView} is detached from it's window. |
+ */ |
+ public static void onDetachedFromWindow() { |
+ assert ThreadUtils.runningOnUiThread(); |
+ sGamepadList.detachedFromWindow(); |
+ } |
+ |
+ private void detachedFromWindow() { |
+ if (--mAttachedToWindowCounter == 0) { |
+ synchronized (mLock) { |
+ for (int i = 0; i < MAX_GAMEPADS; ++i) { |
+ mGamepadDevices[i] = null; |
+ } |
+ } |
+ mInputManager.unregisterInputDeviceListener(this); |
+ mInputManager = null; |
+ } |
+ } |
+ |
+ // ------------------------------------------------------------ |
+ |
+ // Override InputDeviceListener methods |
+ @Override |
+ public void onInputDeviceChanged(int deviceId) { |
+ } |
+ |
+ @Override |
+ public void onInputDeviceRemoved(int deviceId) { |
+ synchronized (mLock) { |
+ unregisterGamepad(deviceId); |
+ } |
+ } |
+ |
+ @Override |
+ public void onInputDeviceAdded(int deviceId) { |
+ InputDevice inputDevice = InputDevice.getDevice(deviceId); |
+ if (!isGamepadDevice(inputDevice)) return; |
+ synchronized (mLock) { |
+ registerGamepad(inputDevice); |
+ } |
+ } |
+ |
+ // ------------------------------------------------------------ |
+ |
+ private static void createInstance() { |
+ if (sGamepadList == null) { |
+ sGamepadList = new GamepadList(); |
+ } |
+ } |
+ |
+ private int getDeviceCount() { |
+ int count = 0; |
+ for (int i = 0; i < MAX_GAMEPADS; i++) { |
+ if (getDevice(i) != null) { |
+ count++; |
+ } |
+ } |
+ return count; |
+ } |
+ |
+ private boolean isDeviceConnected(int index) { |
+ if (index < MAX_GAMEPADS && getDevice(index) != null) { |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ private GamepadDevice getDeviceById(int deviceId) { |
+ for (int i = 0; i < MAX_GAMEPADS; i++) { |
+ GamepadDevice gamepad = mGamepadDevices[i]; |
+ if (gamepad != null && gamepad.getId() == deviceId) { |
+ return gamepad; |
+ } |
+ } |
+ return null; |
+ } |
+ |
+ private GamepadDevice getDevice(int index) { |
+ // Maximum 4 Gamepads can be connected at a time starting at index zero. |
+ assert index >= 0 && index < MAX_GAMEPADS; |
+ return mGamepadDevices[index]; |
+ } |
+ |
+ /** |
+ * Handles key events from the gamepad devices. |
+ * @return True if the event has been consumed. |
+ */ |
+ public static boolean dispatchKeyEvent(KeyEvent event) { |
+ if (!isGamepadEvent(event)) return false; |
+ return sGamepadList.handleKeyEvent(event); |
+ } |
+ |
+ private boolean handleKeyEvent(KeyEvent event) { |
+ synchronized (mLock) { |
+ if (!mIsGamepadAccessed) return false; |
+ GamepadDevice gamepad = getGamepadForEvent(event); |
+ if (gamepad == null) return false; |
+ return gamepad.handleKeyEvent(event); |
+ } |
+ } |
+ |
+ /** |
+ * Handles motion events from the gamepad devices. |
+ * @return True if the event has been consumed. |
+ */ |
+ public static boolean onGenericMotionEvent(MotionEvent event) { |
+ if (!isGamepadEvent(event)) return false; |
+ return sGamepadList.handleMotionEvent(event); |
+ } |
+ |
+ private boolean handleMotionEvent(MotionEvent event) { |
+ synchronized (mLock) { |
+ if (!mIsGamepadAccessed) return false; |
+ GamepadDevice gamepad = getGamepadForEvent(event); |
+ if (gamepad == null) return false; |
+ return gamepad.handleMotionEvent(event); |
+ } |
+ } |
+ |
+ private 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 < MAX_GAMEPADS; ++i) { |
+ if (getDevice(i) == null) { |
+ return i; |
+ } |
+ } |
+ // Reached maximum gamepads limit. |
+ return -1; |
+ } |
+ |
+ private 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; |
+ } |
+ |
+ private void unregisterGamepad(int deviceId) { |
+ GamepadDevice gamepadDevice = getDeviceById(deviceId); |
+ if (gamepadDevice == null) return; // Not a registered device. |
+ int index = gamepadDevice.getIndex(); |
+ mGamepadDevices[index] = null; |
+ } |
+ |
+ private static boolean isGamepadDevice(InputDevice inputDevice) { |
+ return ((inputDevice.getSources() & InputDevice.SOURCE_JOYSTICK) == |
+ InputDevice.SOURCE_JOYSTICK); |
+ } |
+ |
+ private GamepadDevice getGamepadForEvent(InputEvent event) { |
+ int deviceId = event.getDeviceId(); |
+ GamepadDevice gamepad = getDeviceById(deviceId); |
+ return gamepad; |
Ted C
2014/04/16 23:36:53
I think this is fine just as:
return getDeviceByI
SaurabhK
2014/04/18 14:51:57
On 2014/04/16 23:36:53, Ted C wrote:
Done.
|
+ } |
+ |
+ /** |
+ * @return True if the motion event corresponds to a gamepad event. |
+ */ |
+ public static boolean isGamepadEvent(MotionEvent event) { |
+ return ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK); |
+ } |
+ |
+ /** |
+ * @return True if event's keycode corresponds to a gamepad key. |
+ * Specific handling for dpad keys is required because |
Ted C
2014/04/16 23:36:53
these two lines are implementation specific. They
SaurabhK
2014/04/18 14:51:57
On 2014/04/16 23:36:53, Ted C wrote:
Moved to swi
|
+ * KeyEvent.isGamepadButton doesn't consider dpad keys. |
+ */ |
+ public static 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); |
+ } |
+ } |
+ |
+ @CalledByNative |
+ static void getGamepadData(long gamepads) { |
Ted C
2014/04/16 23:36:53
I would call this updateGamepadData because it doe
SaurabhK
2014/04/18 14:51:57
On 2014/04/16 23:36:53, Ted C wrote:
Using webGam
|
+ assert sGamepadList != null; |
+ sGamepadList.grabGamepadData(gamepads); |
+ } |
+ |
+ private void grabGamepadData(long gamepads) { |
+ synchronized (mLock) { |
+ for (int i = 0; i < MAX_GAMEPADS; i++) { |
+ final GamepadDevice device = getDevice(i); |
+ if (device != null) { |
+ device.mapButtonsAndAxes(); |
Ted C
2014/04/16 23:36:53
maybe updateButtonsAndAxesMapping
The verb "map"
SaurabhK
2014/04/18 14:51:57
On 2014/04/16 23:36:53, Ted C wrote:
Using update
|
+ nativeSetGamepadData(gamepads, i, device.getMapping(), true, device.getName(), |
+ device.getTimestamp(), device.getAxes(), device.getButtons()); |
+ } |
+ else |
Ted C
2014/04/16 23:36:53
the else needs to be on the line with the } from t
SaurabhK
2014/04/18 14:51:57
On 2014/04/16 23:36:53, Ted C wrote:
THanks for t
|
+ nativeSetGamepadData(gamepads, i, false, false, null, 0, null, null); |
+ } |
+ } |
+ } |
+ |
+ @CalledByNative |
+ static void notifyForGamepadsAccess(boolean isAccessPaused) { |
+ assert sGamepadList != null; |
+ sGamepadList.setIsGamepadAccessed(!isAccessPaused); |
+ } |
+ |
+ private void setIsGamepadAccessed(boolean isGamepadAccessed) { |
+ synchronized (mLock) { |
+ mIsGamepadAccessed = isGamepadAccessed; |
+ if (isGamepadAccessed) { |
+ for (int i = 0; i < MAX_GAMEPADS; i++) { |
+ GamepadDevice gamepadDevice = getDevice(i); |
+ if (gamepadDevice == null) continue; |
+ gamepadDevice.clearData(); |
+ } |
+ } |
+ } |
+ } |
+ |
+ private native void nativeSetGamepadData(long gamepads, int index, boolean mapping, |
+ boolean connected, String devicename, long timestamp, float[] axes, float[] buttons); |
+ |
+} |