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

Side by Side Diff: content/public/android/java/src/org/chromium/content/browser/input/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, 6 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 unified diff | Download patch
OLDNEW
(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.input;
6
7 import android.content.Context;
8 import android.hardware.input.InputManager;
9 import android.hardware.input.InputManager.InputDeviceListener;
10 import android.os.Build;
11 import android.view.InputDevice;
12 import android.view.InputEvent;
13 import android.view.KeyEvent;
14 import android.view.MotionEvent;
15
16 import org.chromium.base.CalledByNative;
17 import org.chromium.base.JNINamespace;
18 import org.chromium.base.ThreadUtils;
19
20 /**
21 * Class to manage connected gamepad devices list.
22 *
23 * It is a Java counterpart of GamepadPlatformDataFetcherAndroid and feeds Gamep ad API with input
24 * data.
25 */
26 @JNINamespace("content")
27 public class GamepadList {
28 private static final int MAX_GAMEPADS = 4;
29
30 private final Object mLock = new Object();
31
32 private final GamepadDevice[] mGamepadDevices = new GamepadDevice[MAX_GAMEPA DS];
33 private InputManager mInputManager;
34 private int mAttachedToWindowCounter;
35 private boolean mIsGamepadAccessed;
36 private InputDeviceListener mInputDeviceListener;
37
38 private GamepadList() {
39 mInputDeviceListener = new InputDeviceListener() {
40 // Override InputDeviceListener methods
41 @Override
42 public void onInputDeviceChanged(int deviceId) {
43 onInputDeviceChangedImpl(deviceId);
44 }
45
46 @Override
47 public void onInputDeviceRemoved(int deviceId) {
48 onInputDeviceRemovedImpl(deviceId);
49 }
50
51 @Override
52 public void onInputDeviceAdded(int deviceId) {
53 onInputDeviceAddedImpl(deviceId);
54 }
55 };
56 }
57
58 private void initializeDevices() {
59 // Get list of all the attached input devices.
60 int[] deviceIds = mInputManager.getInputDeviceIds();
61 for (int i = 0; i < deviceIds.length; i++) {
62 InputDevice inputDevice = InputDevice.getDevice(deviceIds[i]);
63 // Check for gamepad device
64 if (isGamepadDevice(inputDevice)) {
65 // Register a new gamepad device.
66 registerGamepad(inputDevice);
67 }
68 }
69 }
70
71 /**
72 * Notifies the GamepadList that a {@link ContentView} is attached to a wind ow and it should
73 * prepare itself for gamepad input. It must be called before {@link onGener icMotionEvent} and
74 * {@link dispatchKeyEvent}.
75 */
76 public static void onAttachedToWindow(Context context) {
77 assert ThreadUtils.runningOnUiThread();
jdduke (slow) 2014/05/29 17:46:36 if (!isGamepadSupported()) return;
SaurabhK 2014/05/30 09:13:45 On 2014/05/29 17:46:36, jdduke wrote: Done.
78 getInstance().attachedToWindow(context);
79 }
80
81 private void attachedToWindow(Context context) {
82 if (mAttachedToWindowCounter++ == 0) {
83 mInputManager = (InputManager) context.getSystemService(Context.INPU T_SERVICE);
84 synchronized (mLock) {
85 initializeDevices();
86 }
87 // Register an input device listener.
88 mInputManager.registerInputDeviceListener(mInputDeviceListener, null );
89 }
90 }
91
92 /**
93 * Notifies the GamepadList that a {@link ContentView} is detached from it's window.
94 */
95 public static void onDetachedFromWindow() {
96 assert ThreadUtils.runningOnUiThread();
jdduke (slow) 2014/05/29 17:46:36 if (!isGamepadSupported()) return;
SaurabhK 2014/05/30 09:13:45 On 2014/05/29 17:46:36, jdduke wrote: Done.
97 getInstance().detachedFromWindow();
98 }
99
100 private void detachedFromWindow() {
101 if (--mAttachedToWindowCounter == 0) {
102 synchronized (mLock) {
103 for (int i = 0; i < MAX_GAMEPADS; ++i) {
104 mGamepadDevices[i] = null;
105 }
106 }
107 mInputManager.unregisterInputDeviceListener(mInputDeviceListener);
108 mInputManager = null;
109 }
110 }
111
112 // ------------------------------------------------------------
113
114 private void onInputDeviceChangedImpl(int deviceId) {}
115
116 private void onInputDeviceRemovedImpl(int deviceId) {
117 synchronized (mLock) {
118 unregisterGamepad(deviceId);
119 }
120 }
121
122 private void onInputDeviceAddedImpl(int deviceId) {
123 InputDevice inputDevice = InputDevice.getDevice(deviceId);
124 if (!isGamepadDevice(inputDevice)) return;
125 synchronized (mLock) {
126 registerGamepad(inputDevice);
127 }
128 }
129
130 // ------------------------------------------------------------
131
132 private static GamepadList getInstance() {
133 assert isGamepadSupported();
134 return LazyHolder.INSTANCE;
135 }
136
137 private int getDeviceCount() {
138 int count = 0;
139 for (int i = 0; i < MAX_GAMEPADS; i++) {
140 if (getDevice(i) != null) {
141 count++;
142 }
143 }
144 return count;
145 }
146
147 private boolean isDeviceConnected(int index) {
148 if (index < MAX_GAMEPADS && getDevice(index) != null) {
149 return true;
150 }
151 return false;
152 }
153
154 private GamepadDevice getDeviceById(int deviceId) {
155 for (int i = 0; i < MAX_GAMEPADS; i++) {
156 GamepadDevice gamepad = mGamepadDevices[i];
157 if (gamepad != null && gamepad.getId() == deviceId) {
158 return gamepad;
159 }
160 }
161 return null;
162 }
163
164 private GamepadDevice getDevice(int index) {
165 // Maximum 4 Gamepads can be connected at a time starting at index zero.
166 assert index >= 0 && index < MAX_GAMEPADS;
167 return mGamepadDevices[index];
168 }
169
170 /**
171 * Handles key events from the gamepad devices.
172 * @return True if the event has been consumed.
173 */
174 public static boolean dispatchKeyEvent(KeyEvent event) {
175 if (!isGamepadSupported()) return false;
176 if (!isGamepadEvent(event)) return false;
177 return getInstance().handleKeyEvent(event);
178 }
179
180 private boolean handleKeyEvent(KeyEvent event) {
181 synchronized (mLock) {
182 if (!mIsGamepadAccessed) return false;
183 GamepadDevice gamepad = getGamepadForEvent(event);
184 if (gamepad == null) return false;
185 return gamepad.handleKeyEvent(event);
186 }
187 }
188
189 /**
190 * Handles motion events from the gamepad devices.
191 * @return True if the event has been consumed.
192 */
193 public static boolean onGenericMotionEvent(MotionEvent event) {
194 if (!isGamepadSupported()) return false;
195 if (!isGamepadEvent(event)) return false;
196 return getInstance().handleMotionEvent(event);
197 }
198
199 private boolean handleMotionEvent(MotionEvent event) {
200 synchronized (mLock) {
201 if (!mIsGamepadAccessed) return false;
202 GamepadDevice gamepad = getGamepadForEvent(event);
203 if (gamepad == null) return false;
204 return gamepad.handleMotionEvent(event);
205 }
206 }
207
208 private int getNextAvailableIndex() {
209 // When multiple gamepads are connected to a user agent, indices must be assigned on a
210 // first-come first-serve basis, starting at zero. If a gamepad is disco nnected, previously
211 // assigned indices must not be reassigned to gamepads that continue to be connected.
212 // However, if a gamepad is disconnected, and subsequently the same or a different
213 // gamepad is then connected, index entries must be reused.
214
215 for (int i = 0; i < MAX_GAMEPADS; ++i) {
216 if (getDevice(i) == null) {
217 return i;
218 }
219 }
220 // Reached maximum gamepads limit.
221 return -1;
222 }
223
224 private boolean registerGamepad(InputDevice inputDevice) {
225 int index = getNextAvailableIndex();
226 if (index == -1) return false; // invalid index
227
228 GamepadDevice gamepad = new GamepadDevice(index, inputDevice);
229 mGamepadDevices[index] = gamepad;
230 return true;
231 }
232
233 private void unregisterGamepad(int deviceId) {
234 GamepadDevice gamepadDevice = getDeviceById(deviceId);
235 if (gamepadDevice == null) return; // Not a registered device.
236 int index = gamepadDevice.getIndex();
237 mGamepadDevices[index] = null;
238 }
239
240 private static boolean isGamepadDevice(InputDevice inputDevice) {
241 return ((inputDevice.getSources() & InputDevice.SOURCE_JOYSTICK) ==
242 InputDevice.SOURCE_JOYSTICK);
243 }
244
245 private GamepadDevice getGamepadForEvent(InputEvent event) {
246 return getDeviceById(event.getDeviceId());
247 }
248
249 /**
250 * @return True if the motion event corresponds to a gamepad event.
251 */
252 public static boolean isGamepadEvent(MotionEvent event) {
253 return ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice .SOURCE_JOYSTICK);
254 }
255
256 /**
257 * @return True if event's keycode corresponds to a gamepad key.
258 */
259 public static boolean isGamepadEvent(KeyEvent event) {
260 int keyCode = event.getKeyCode();
261 switch (keyCode) {
262 // Specific handling for dpad keys is required because
263 // KeyEvent.isGamepadButton doesn't consider dpad keys.
264 case KeyEvent.KEYCODE_DPAD_UP:
265 case KeyEvent.KEYCODE_DPAD_DOWN:
266 case KeyEvent.KEYCODE_DPAD_LEFT:
267 case KeyEvent.KEYCODE_DPAD_RIGHT:
268 return true;
269 default:
270 return KeyEvent.isGamepadButton(keyCode);
271 }
272 }
273
274 private static boolean isGamepadSupported() {
275 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
276 }
277
278 @CalledByNative
279 static void updateGamepadData(long webGamepadsPtr) {
280 if (!isGamepadSupported()) return;
281 getInstance().grabGamepadData(webGamepadsPtr);
282 }
283
284 private void grabGamepadData(long webGamepadsPtr) {
285 synchronized (mLock) {
286 for (int i = 0; i < MAX_GAMEPADS; i++) {
287 final GamepadDevice device = getDevice(i);
288 if (device != null) {
289 device.updateButtonsAndAxesMapping();
290 nativeSetGamepadData(webGamepadsPtr, i, device.isStandardGam epad(), true,
291 device.getName(), device.getTimestamp(), device.getA xes(),
292 device.getButtons());
293 } else {
294 nativeSetGamepadData(webGamepadsPtr, i, false, false, null, 0, null, null);
295 }
296 }
297 }
298 }
299
300 @CalledByNative
301 static void notifyForGamepadsAccess(boolean isAccessPaused) {
302 if (!isGamepadSupported()) return;
303 getInstance().setIsGamepadAccessed(!isAccessPaused);
304 }
305
306 private void setIsGamepadAccessed(boolean isGamepadAccessed) {
307 synchronized (mLock) {
308 mIsGamepadAccessed = isGamepadAccessed;
309 if (isGamepadAccessed) {
310 for (int i = 0; i < MAX_GAMEPADS; i++) {
311 GamepadDevice gamepadDevice = getDevice(i);
312 if (gamepadDevice == null) continue;
313 gamepadDevice.clearData();
314 }
315 }
316 }
317 }
318
319 private native void nativeSetGamepadData(long webGamepadsPtr, int index, boo lean mapping,
320 boolean connected, String devicename, long timestamp, float[] axes, float[] buttons);
321
322 private static class LazyHolder {
323 private static final GamepadList INSTANCE = new GamepadList();
324 }
325
326 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698