Chromium Code Reviews| 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..06ea3d971d99d660442efc63790af16782296549 |
| --- /dev/null |
| +++ b/content/public/android/java/src/org/chromium/content/browser/GamepadList.java |
| @@ -0,0 +1,306 @@ |
| +// 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; |
| + |
| +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; |
| + |
| +/* |
| + * Class to manage connected gamepad devices list. |
| + */ |
| +@JNINamespace("content") |
| +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; |
|
kbalazs
2014/02/20 00:48:24
Shouldn't be named with initials since it's not a
SaurabhK
2014/02/26 14:14:26
On 2014/02/20 00:48:24, kbalazs wrote:
Done.
|
| + private InputManager inputManager; |
|
xwang
2014/02/25 10:26:58
inputManager -> mInputManager?
SaurabhK
2014/02/26 14:14:26
On 2014/02/25 10:26:58, xwang wrote:
Done.
|
| + // Native pointer to C++ GamepadReader object which will be set by CreateJavaObject(). |
| + private long mNativeGamepadReader = 0; |
| + |
| + 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; |
|
xwang
2014/02/25 10:26:58
gamepadList -> sGamepadList
SaurabhK
2014/02/26 14:14:26
On 2014/02/25 10:26:58, xwang wrote:
Done.
|
| + |
| + // 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; |
| + } |
| + } |
| + |
| + private boolean haveDevicesBeenInteractedWith() { return mHaveDevicesBeenInteractedWith; } |
|
xwang
2014/02/25 10:26:58
Is it necessary to add a private function to acces
SaurabhK
2014/02/26 14:14:26
On 2014/02/25 10:26:58, xwang wrote:
Removed it.
|
| + |
| + private int getDeviceCount() { |
| + int count = 0; |
| + for (int i = 0; i < getCount(); ++i) { |
| + if (getDevice(i) != null) { |
| + count++; |
| + } |
| + } |
| + return count; |
| + } |
| + |
| + private String getDeviceName(int index) { |
| + return getDevice(index).getName(); |
| + } |
| + |
| + private long getDeviceTimestamp(int index) { |
| + return getDevice(index).getTimestamp(); |
| + } |
| + |
| + private float[] getDeviceAxes(int index) { |
| + return getDevice(index).getAxes(); |
| + } |
| + |
| + private float[] getDeviceButtons(int index) { |
| + return getDevice(index).getButtons(); |
| + } |
| + |
| + private boolean isDeviceConnected(int index) { |
| + if (index < MAX_GAMEPADS && getDevice(index) != null) { |
| + return true; |
| + } |
| + return false; |
| + } |
| + |
| + 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() { |
|
kbalazs
2014/02/20 00:48:24
This doesn't look very useful to me, I would just
SaurabhK
2014/02/26 14:14:26
On 2014/02/20 00:48:24, kbalazs wrote:
Done.
|
| + return MAX_GAMEPADS; |
| + } |
| + |
| + public boolean updateForEvent(KeyEvent event) { |
| + GamepadDevice gamepad = getGamepadForEvent(event); |
| + if (gamepad != null) { |
| + mHaveDevicesBeenInteractedWith = true; |
|
kbalazs
2014/02/20 00:48:24
I think it's not strictly necessary to maintain th
|
| + 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. |
|
kbalazs
2014/02/20 00:48:24
Can you word it more generally? This feature is no
SaurabhK
2014/02/26 14:14:26
On 2014/02/20 00:48:24, kbalazs wrote:
Removing o
|
| + for (int i = 0; i < getCount(); ++i) { |
|
kbalazs
2014/02/20 00:48:24
Isn't it enough to null out the array and enumerat
|
| + 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 ) { |
|
kbalazs
2014/02/20 00:48:24
Shouln't it be '(sources & InputDevice.SOURCE_JOYS
|
| + //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) { |
|
kbalazs
2014/02/20 00:48:24
Ditto about the condition.
|
| + 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); |
| + } |
| + } |
| + |
| + @CalledByNative |
| + private void getGamepadData() { |
| + int devicecount = getDeviceCount(); |
| + if (devicecount == 0 || !haveDevicesBeenInteractedWith()) |
| + nativeUpdateDeviceCount(mNativeGamepadReader, 0); |
| + else |
| + nativeUpdateDeviceCount(mNativeGamepadReader, devicecount); |
| + for (int i = 0; i < MAX_GAMEPADS; i++) { |
| + if (isDeviceConnected(i)) |
| + nativeSetGamepadData(mNativeGamepadReader, i, true, getDeviceName(i), |
| + getDeviceTimestamp(i), getDeviceAxes(i), |
| + getDeviceButtons(i)); |
| + else |
| + nativeSetGamepadData(mNativeGamepadReader, i, false, null, 0, null, null); |
| + } |
| + } |
| + |
| + @CalledByNative |
| + public static GamepadList getInstance(long nativeGamepadReader) { |
| + if (gamepadList != null) { |
| + gamepadList.mNativeGamepadReader = nativeGamepadReader; |
| + return gamepadList; |
| + } else { |
| + return null; |
| + } |
| + } |
| + |
| + @CalledByNative |
| + private void notifyForGamepadsAccess(boolean isaccesspaused) { |
| + IS_GAMEPAD_ACCESSED = !isaccesspaused; |
| + } |
| + |
| + private native void nativeSetGamepadData(long nativeGamepadsReader, |
| + int index, |
| + boolean connected, |
| + String devicename, |
| + long timestamp, |
| + float[] axes, |
| + float[] buttons); |
| + |
| + private native void nativeUpdateDeviceCount(long nativeGamepadsReader, int devicecount); |
| + |
| +} |