OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package org.chromium.content.browser; |
| 6 |
| 7 import android.content.Context; |
| 8 import android.hardware.input.InputManager; |
| 9 import android.hardware.input.InputManager.InputDeviceListener; |
| 10 import android.view.InputDevice; |
| 11 import android.view.InputEvent; |
| 12 import android.view.KeyEvent; |
| 13 import android.view.MotionEvent; |
| 14 |
| 15 import org.chromium.base.CalledByNative; |
| 16 import org.chromium.base.JNINamespace; |
| 17 import org.chromium.base.ThreadUtils; |
| 18 |
| 19 /* |
| 20 * Class to manage connected gamepad devices list. |
| 21 */ |
| 22 @JNINamespace("content") |
| 23 class GamepadList implements InputDeviceListener { |
| 24 private static final int MAX_GAMEPADS = 4; |
| 25 private GamepadDevice[] mGamepadDevices = new GamepadDevice[MAX_GAMEPADS]; |
| 26 protected boolean mHaveDevicesBeenInteractedWith = false; |
| 27 private boolean mIsGamepadAccessed = false; |
| 28 private InputManager mInputManager; |
| 29 // Native pointer to C++ GamepadReader object which will be set by CreateJav
aObject(). |
| 30 private long mNativeGamepadReader = 0; |
| 31 private int mAttachedToWindowCounter; |
| 32 |
| 33 private GamepadList() {} |
| 34 |
| 35 private void initializeDevices() { |
| 36 // Get list of all the attached input devices. |
| 37 int[] deviceIds = mInputManager.getInputDeviceIds(); |
| 38 |
| 39 for (int i = 0; i < deviceIds.length; i++) { |
| 40 InputDevice inputDevice = InputDevice.getDevice(deviceIds[i]); |
| 41 // Check for gamepad device |
| 42 if (isGamepadDevice(inputDevice)) { |
| 43 // Register a new gamepad device. |
| 44 registerGamepad(inputDevice); |
| 45 } |
| 46 } |
| 47 // Register an input device listener. |
| 48 mInputManager.registerInputDeviceListener(this, null); |
| 49 } |
| 50 |
| 51 private static GamepadList sGamepadList = null; |
| 52 |
| 53 public static void onAttachedToWindow(Context context) { |
| 54 assert ThreadUtils.runningOnUiThread(); |
| 55 createInstance(); |
| 56 sGamepadList.attachedToWindow(context); |
| 57 } |
| 58 |
| 59 private void attachedToWindow(Context context) { |
| 60 if (mAttachedToWindowCounter++ == 0) { |
| 61 mInputManager = (InputManager) context.getSystemService(Context.INP
UT_SERVICE); |
| 62 initializeDevices(); |
| 63 } |
| 64 } |
| 65 |
| 66 public static void onDetachedFromWindow() { |
| 67 assert ThreadUtils.runningOnUiThread(); |
| 68 sGamepadList.detachedFromWindow(); |
| 69 } |
| 70 |
| 71 private void detachedFromWindow() { |
| 72 if (--mAttachedToWindowCounter == 0) { |
| 73 for (int i = 0; i < MAX_GAMEPADS; ++i) { |
| 74 mGamepadDevices[i] = null; |
| 75 } |
| 76 mInputManager.unregisterInputDeviceListener(this); |
| 77 mInputManager = null; |
| 78 } |
| 79 } |
| 80 |
| 81 // Override InputDeviceListener methods |
| 82 @Override |
| 83 public void onInputDeviceChanged(int deviceId) { |
| 84 } |
| 85 |
| 86 @Override |
| 87 public void onInputDeviceRemoved(int deviceId) { |
| 88 unregisterGamepad(deviceId); |
| 89 } |
| 90 |
| 91 @Override |
| 92 public void onInputDeviceAdded(int deviceId) { |
| 93 InputDevice inputDevice = InputDevice.getDevice(deviceId); |
| 94 if (isGamepadDevice(inputDevice)) |
| 95 registerGamepad(inputDevice); |
| 96 } |
| 97 |
| 98 public static void createInstance() { |
| 99 if (sGamepadList == null) { |
| 100 sGamepadList = new GamepadList(); |
| 101 } |
| 102 } |
| 103 |
| 104 private int getDeviceCount() { |
| 105 int count = 0; |
| 106 for (int i = 0; i < MAX_GAMEPADS; ++i) { |
| 107 if (getDevice(i) != null) { |
| 108 count++; |
| 109 } |
| 110 } |
| 111 return count; |
| 112 } |
| 113 |
| 114 private String getMapping(int index) { |
| 115 return getDevice(index).getMapping(); |
| 116 } |
| 117 |
| 118 private String getDeviceName(int index) { |
| 119 return getDevice(index).getName(); |
| 120 } |
| 121 |
| 122 private long getDeviceTimestamp(int index) { |
| 123 return getDevice(index).getTimestamp(); |
| 124 } |
| 125 |
| 126 private float[] getDeviceAxes(int index) { |
| 127 return getDevice(index).getAxes(); |
| 128 } |
| 129 |
| 130 private float[] getDeviceButtons(int index) { |
| 131 return getDevice(index).getButtons(); |
| 132 } |
| 133 |
| 134 private boolean isDeviceConnected(int index) { |
| 135 if (index < MAX_GAMEPADS && getDevice(index) != null) { |
| 136 return true; |
| 137 } |
| 138 return false; |
| 139 } |
| 140 |
| 141 public GamepadDevice getDeviceById(int deviceId) { |
| 142 for (int i = 0; i < MAX_GAMEPADS; ++i) { |
| 143 GamepadDevice gamepad = mGamepadDevices[i]; |
| 144 if (gamepad != null && gamepad.getId() == deviceId) { |
| 145 return gamepad; |
| 146 } |
| 147 } |
| 148 return null; |
| 149 } |
| 150 |
| 151 public GamepadDevice getDevice(int index) { |
| 152 // Maximum 4 Gamepads can be connected at a time starting at index zero. |
| 153 assert index >= 0 && index <= MAX_GAMEPADS - 1; |
| 154 return mGamepadDevices[index]; |
| 155 } |
| 156 |
| 157 public static boolean dispatchKeyEvent(KeyEvent event) { |
| 158 if (sGamepadList.isGamepadAccessed() && sGamepadList.isGamepadEvent(even
t)) |
| 159 return sGamepadList.updateForEvent(event); |
| 160 return false; |
| 161 } |
| 162 |
| 163 private boolean updateForEvent(KeyEvent event) { |
| 164 GamepadDevice gamepad = getGamepadForEvent(event); |
| 165 if (gamepad != null) { |
| 166 mHaveDevicesBeenInteractedWith = true; |
| 167 return gamepad.updateForEvent(event); |
| 168 } |
| 169 return false; |
| 170 } |
| 171 |
| 172 public static boolean onGenericMotionEvent(MotionEvent event) { |
| 173 if (sGamepadList.isGamepadAccessed() && sGamepadList.isGamepadEvent(even
t)) |
| 174 return sGamepadList.updateForEvent(event); |
| 175 return false; |
| 176 } |
| 177 |
| 178 private boolean updateForEvent(MotionEvent event) { |
| 179 GamepadDevice gamepad = getGamepadForEvent(event); |
| 180 if (gamepad != null) { |
| 181 mHaveDevicesBeenInteractedWith = true; |
| 182 return gamepad.updateForEvent(event); |
| 183 } |
| 184 return false; |
| 185 } |
| 186 |
| 187 protected int getNextAvailableIndex() { |
| 188 // When multiple gamepads are connected to a user agent, indices must be
assigned on a |
| 189 // first-come first-serve basis, starting at zero. If a gamepad is disco
nnected, previously |
| 190 // assigned indices must not be reassigned to gamepads that continue to
be connected. |
| 191 // However, if a gamepad is disconnected, and subsequently the same or a
different |
| 192 // gamepad is then connected, index entries must be reused. |
| 193 |
| 194 for (int i = 0; i < MAX_GAMEPADS; ++i) { |
| 195 if (getDevice(i) == null) { |
| 196 return i; |
| 197 } |
| 198 } |
| 199 // Reached maximum gamepads limit. |
| 200 return -1; |
| 201 } |
| 202 |
| 203 protected boolean registerGamepad(InputDevice inputDevice) { |
| 204 int index = getNextAvailableIndex(); |
| 205 if (index == -1) { |
| 206 return false; // invalid index |
| 207 } |
| 208 |
| 209 GamepadDevice gamepad = new GamepadDevice(index, inputDevice); |
| 210 mGamepadDevices[index] = gamepad; |
| 211 return true; |
| 212 } |
| 213 |
| 214 protected void unregisterGamepad(int deviceId) { |
| 215 GamepadDevice gamepadDevice = getDeviceById(deviceId); |
| 216 if (gamepadDevice == null) { |
| 217 return; // Not a registered device. |
| 218 } |
| 219 int index = gamepadDevice.getIndex(); |
| 220 mGamepadDevices[index] = null; |
| 221 } |
| 222 |
| 223 private boolean isGamepadDevice(InputDevice inputDevice) { |
| 224 int sources = inputDevice.getSources(); |
| 225 if ((sources & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JO
YSTICK ) { |
| 226 //Found gamepad device |
| 227 return true; |
| 228 } |
| 229 return false; |
| 230 } |
| 231 |
| 232 private GamepadDevice getGamepadForEvent(InputEvent event) { |
| 233 int deviceId = event.getDeviceId(); |
| 234 GamepadDevice gamepad = getDeviceById(deviceId); |
| 235 return gamepad; |
| 236 } |
| 237 |
| 238 public boolean isGamepadAccessed() { |
| 239 return mIsGamepadAccessed; |
| 240 } |
| 241 |
| 242 private boolean isGamepadEvent(MotionEvent event) { |
| 243 if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOU
RCE_JOYSTICK) { |
| 244 return true; |
| 245 } |
| 246 return false; |
| 247 } |
| 248 |
| 249 // Returns true if event's keycode corresponds to a gamepad key. |
| 250 // Specific handling for dpad keys is required because |
| 251 // KeyEvent.isGamepadButton doesn't consider dpad keys. |
| 252 public boolean isGamepadEvent(KeyEvent event) { |
| 253 int keyCode = event.getKeyCode(); |
| 254 switch (keyCode) { |
| 255 case KeyEvent.KEYCODE_DPAD_UP: |
| 256 case KeyEvent.KEYCODE_DPAD_DOWN: |
| 257 case KeyEvent.KEYCODE_DPAD_LEFT: |
| 258 case KeyEvent.KEYCODE_DPAD_RIGHT: |
| 259 return true; |
| 260 default: |
| 261 return KeyEvent.isGamepadButton(keyCode); |
| 262 } |
| 263 } |
| 264 |
| 265 @CalledByNative |
| 266 private void getGamepadData() { |
| 267 assert mNativeGamepadReader != 0; |
| 268 int devicecount = getDeviceCount(); |
| 269 if (devicecount == 0 || !mHaveDevicesBeenInteractedWith) |
| 270 nativeUpdateDeviceCount(mNativeGamepadReader, 0); |
| 271 else { |
| 272 nativeUpdateDeviceCount(mNativeGamepadReader, devicecount); |
| 273 for (int i = 0; i < MAX_GAMEPADS; i++) { |
| 274 if (isDeviceConnected(i)) { |
| 275 getDevice(i).mapButtonsAndAxes(); |
| 276 nativeSetGamepadData(mNativeGamepadReader, i, getMapping(i),
true, |
| 277 getDeviceName(i), getDeviceTimestamp(i)
, getDeviceAxes(i), |
| 278 getDeviceButtons(i)); |
| 279 } |
| 280 else |
| 281 nativeSetGamepadData(mNativeGamepadReader, i, null, false, n
ull, 0, null, |
| 282 null); |
| 283 } |
| 284 } |
| 285 } |
| 286 |
| 287 @CalledByNative |
| 288 public static GamepadList getInstance(long nativeGamepadReader) { |
| 289 assert sGamepadList != null; |
| 290 sGamepadList.mNativeGamepadReader = nativeGamepadReader; |
| 291 return sGamepadList; |
| 292 } |
| 293 |
| 294 @CalledByNative |
| 295 private void notifyForGamepadsAccess(boolean isaccesspaused) { |
| 296 mIsGamepadAccessed = !isaccesspaused; |
| 297 } |
| 298 |
| 299 private native void nativeSetGamepadData(long nativeGamepadsReader, |
| 300 int index, |
| 301 String mapping, |
| 302 boolean connected, |
| 303 String devicename, |
| 304 long timestamp, |
| 305 float[] axes, |
| 306 float[] buttons); |
| 307 |
| 308 private native void nativeUpdateDeviceCount(long nativeGamepadsReader, int d
evicecount); |
| 309 |
| 310 } |
OLD | NEW |