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

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();
78 if (!isGamepadSupported()) return;
79 getInstance().attachedToWindow(context);
80 }
81
82 private void attachedToWindow(Context context) {
83 if (mAttachedToWindowCounter++ == 0) {
84 mInputManager = (InputManager) context.getSystemService(Context.INPU T_SERVICE);
85 synchronized (mLock) {
86 initializeDevices();
87 }
88 // Register an input device listener.
89 mInputManager.registerInputDeviceListener(mInputDeviceListener, null );
90 }
91 }
92
93 /**
94 * Notifies the GamepadList that a {@link ContentView} is detached from it's window.
95 */
96 public static void onDetachedFromWindow() {
97 assert ThreadUtils.runningOnUiThread();
98 if (!isGamepadSupported()) return;
99 getInstance().detachedFromWindow();
100 }
101
102 private void detachedFromWindow() {
103 if (--mAttachedToWindowCounter == 0) {
104 synchronized (mLock) {
105 for (int i = 0; i < MAX_GAMEPADS; ++i) {
106 mGamepadDevices[i] = null;
107 }
108 }
109 mInputManager.unregisterInputDeviceListener(mInputDeviceListener);
110 mInputManager = null;
111 }
112 }
113
114 // ------------------------------------------------------------
115
116 private void onInputDeviceChangedImpl(int deviceId) {}
117
118 private void onInputDeviceRemovedImpl(int deviceId) {
119 synchronized (mLock) {
120 unregisterGamepad(deviceId);
121 }
122 }
123
124 private void onInputDeviceAddedImpl(int deviceId) {
125 InputDevice inputDevice = InputDevice.getDevice(deviceId);
126 if (!isGamepadDevice(inputDevice)) return;
127 synchronized (mLock) {
128 registerGamepad(inputDevice);
129 }
130 }
131
132 // ------------------------------------------------------------
133
134 private static GamepadList getInstance() {
135 assert isGamepadSupported();
136 return LazyHolder.INSTANCE;
137 }
138
139 private int getDeviceCount() {
140 int count = 0;
141 for (int i = 0; i < MAX_GAMEPADS; i++) {
142 if (getDevice(i) != null) {
143 count++;
144 }
145 }
146 return count;
147 }
148
149 private boolean isDeviceConnected(int index) {
150 if (index < MAX_GAMEPADS && getDevice(index) != null) {
151 return true;
152 }
153 return false;
154 }
155
156 private GamepadDevice getDeviceById(int deviceId) {
157 for (int i = 0; i < MAX_GAMEPADS; i++) {
158 GamepadDevice gamepad = mGamepadDevices[i];
159 if (gamepad != null && gamepad.getId() == deviceId) {
160 return gamepad;
161 }
162 }
163 return null;
164 }
165
166 private GamepadDevice getDevice(int index) {
167 // Maximum 4 Gamepads can be connected at a time starting at index zero.
168 assert index >= 0 && index < MAX_GAMEPADS;
169 return mGamepadDevices[index];
170 }
171
172 /**
173 * Handles key events from the gamepad devices.
174 * @return True if the event has been consumed.
175 */
176 public static boolean dispatchKeyEvent(KeyEvent event) {
177 if (!isGamepadSupported()) return false;
178 if (!isGamepadEvent(event)) return false;
179 return getInstance().handleKeyEvent(event);
180 }
181
182 private boolean handleKeyEvent(KeyEvent event) {
183 synchronized (mLock) {
184 if (!mIsGamepadAccessed) return false;
185 GamepadDevice gamepad = getGamepadForEvent(event);
186 if (gamepad == null) return false;
187 return gamepad.handleKeyEvent(event);
188 }
189 }
190
191 /**
192 * Handles motion events from the gamepad devices.
193 * @return True if the event has been consumed.
194 */
195 public static boolean onGenericMotionEvent(MotionEvent event) {
196 if (!isGamepadSupported()) return false;
197 if (!isGamepadEvent(event)) return false;
198 return getInstance().handleMotionEvent(event);
199 }
200
201 private boolean handleMotionEvent(MotionEvent event) {
202 synchronized (mLock) {
203 if (!mIsGamepadAccessed) return false;
204 GamepadDevice gamepad = getGamepadForEvent(event);
205 if (gamepad == null) return false;
206 return gamepad.handleMotionEvent(event);
207 }
208 }
209
210 private int getNextAvailableIndex() {
211 // When multiple gamepads are connected to a user agent, indices must be assigned on a
212 // first-come first-serve basis, starting at zero. If a gamepad is disco nnected, previously
213 // assigned indices must not be reassigned to gamepads that continue to be connected.
214 // However, if a gamepad is disconnected, and subsequently the same or a different
215 // gamepad is then connected, index entries must be reused.
216
217 for (int i = 0; i < MAX_GAMEPADS; ++i) {
218 if (getDevice(i) == null) {
219 return i;
220 }
221 }
222 // Reached maximum gamepads limit.
223 return -1;
224 }
225
226 private boolean registerGamepad(InputDevice inputDevice) {
227 int index = getNextAvailableIndex();
228 if (index == -1) return false; // invalid index
229
230 GamepadDevice gamepad = new GamepadDevice(index, inputDevice);
231 mGamepadDevices[index] = gamepad;
232 return true;
233 }
234
235 private void unregisterGamepad(int deviceId) {
236 GamepadDevice gamepadDevice = getDeviceById(deviceId);
237 if (gamepadDevice == null) return; // Not a registered device.
238 int index = gamepadDevice.getIndex();
239 mGamepadDevices[index] = null;
240 }
241
242 private static boolean isGamepadDevice(InputDevice inputDevice) {
243 return ((inputDevice.getSources() & InputDevice.SOURCE_JOYSTICK) ==
Feng Qian 2014/10/09 21:49:15 inputDevice could be null, see http://developer.an
244 InputDevice.SOURCE_JOYSTICK);
245 }
246
247 private GamepadDevice getGamepadForEvent(InputEvent event) {
248 return getDeviceById(event.getDeviceId());
249 }
250
251 /**
252 * @return True if the motion event corresponds to a gamepad event.
253 */
254 public static boolean isGamepadEvent(MotionEvent event) {
255 return ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice .SOURCE_JOYSTICK);
256 }
257
258 /**
259 * @return True if event's keycode corresponds to a gamepad key.
260 */
261 public static boolean isGamepadEvent(KeyEvent event) {
262 int keyCode = event.getKeyCode();
263 switch (keyCode) {
264 // Specific handling for dpad keys is required because
265 // KeyEvent.isGamepadButton doesn't consider dpad keys.
266 case KeyEvent.KEYCODE_DPAD_UP:
267 case KeyEvent.KEYCODE_DPAD_DOWN:
268 case KeyEvent.KEYCODE_DPAD_LEFT:
269 case KeyEvent.KEYCODE_DPAD_RIGHT:
270 return true;
271 default:
272 return KeyEvent.isGamepadButton(keyCode);
273 }
274 }
275
276 private static boolean isGamepadSupported() {
277 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
278 }
279
280 @CalledByNative
281 static void updateGamepadData(long webGamepadsPtr) {
282 if (!isGamepadSupported()) return;
283 getInstance().grabGamepadData(webGamepadsPtr);
284 }
285
286 private void grabGamepadData(long webGamepadsPtr) {
287 synchronized (mLock) {
288 for (int i = 0; i < MAX_GAMEPADS; i++) {
289 final GamepadDevice device = getDevice(i);
290 if (device != null) {
291 device.updateButtonsAndAxesMapping();
292 nativeSetGamepadData(webGamepadsPtr, i, device.isStandardGam epad(), true,
293 device.getName(), device.getTimestamp(), device.getA xes(),
294 device.getButtons());
295 } else {
296 nativeSetGamepadData(webGamepadsPtr, i, false, false, null, 0, null, null);
297 }
298 }
299 }
300 }
301
302 @CalledByNative
303 static void notifyForGamepadsAccess(boolean isAccessPaused) {
304 if (!isGamepadSupported()) return;
305 getInstance().setIsGamepadAccessed(!isAccessPaused);
306 }
307
308 private void setIsGamepadAccessed(boolean isGamepadAccessed) {
309 synchronized (mLock) {
310 mIsGamepadAccessed = isGamepadAccessed;
311 if (isGamepadAccessed) {
312 for (int i = 0; i < MAX_GAMEPADS; i++) {
313 GamepadDevice gamepadDevice = getDevice(i);
314 if (gamepadDevice == null) continue;
315 gamepadDevice.clearData();
316 }
317 }
318 }
319 }
320
321 private native void nativeSetGamepadData(long webGamepadsPtr, int index, boo lean mapping,
322 boolean connected, String devicename, long timestamp, float[] axes, float[] buttons);
323
324 private static class LazyHolder {
325 private static final GamepadList INSTANCE = new GamepadList();
326 }
327
328 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698