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