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