1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
|
page.title=Supporting Controllers Across Android Versions
trainingnavtop=true
@jd:body
<!-- This is the training bar -->
<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#prepare">Prepare to Abstract APIs for Game Controller
Suppport</a></li>
<li><a href="#abstraction">Add an Interface for Backward Compatibility</a></li>
<li><a href="#newer">Implement the Interface on Android 4.1 and Higher</a></li>
<li><a href="#older">Implement the Interface on Android 2.3 up to Android
4.0</a></li>
<li><a href="#using">Use the Version-Specific Implementations</a></li>
</ol>
<h2>Try it out</h2>
<div class="download-box">
<a href="http://developer.android.com/shareables/training/ControllerSample.zip"
class="button">Download the sample</a>
<p class="filename">ControllerSample.zip</p>
</div>
</div>
</div>
<p>If you are supporting game controllers in your game, it's your responsibility
to make sure that your game responds to controllers consistently across devices
running on different versions of Android. This lets your game reach a wider
audience, and your players can enjoy a seamless gameplay experience with
their controllers even when they switch or upgrade their Android devices.</p>
<p>This lesson demonstrates how to use APIs available in Android 4.1 and higher
in a backward compatible way, enabling your game to support the following
features on devices running Android 2.3 and higher:</p>
<ul>
<li>The game can detect if a new game controller is added, changed, or removed.</li>
<li>The game can query the capabilities of a game controller.</li>
<li>The game can recognize incoming motion events from a game controller.</li>
</ul>
<p>The examples in this lesson are based on the reference implementation
provided by the sample {@code ControllerSample.zip} available for download
above. This sample shows how to implement the {@code InputManagerCompat}
interface to support different versions of Android. To compile the sample, you
must use Android 4.1 (API level 16) or higher. Once compiled, the sample app
runs on any device running Android 2.3 (API level 9) or higher as the build
target.
</p>
<h2 id="prepare">Prepare to Abstract APIs for Game Controller Support</h2>
<p>Suppose you want to be able to determine if a game controller's connection
status has changed on devices running on Android 2.3 (API level 9). However,
the APIs are only available in Android 4.1 (API level 16) and higher, so you
need to provide an implementation that supports Android 4.1 and higher while
providing a fallback mechanism that supports Android 2.3 up to Android 4.0.</p>
<p>To help you determine which features require such a fallback mechanism for
older versions, table 1 lists the differences in game controller support
between Android 2.3 (API level 9), 3.1 (API level 12), and 4.1 (API level
16).</p>
<p class="table-caption" id="game-controller-support-table">
<strong>Table 1.</strong> APIs for game controller support across
different Android versions.
</p>
<table>
<tbody>
<tr>
<th>Controller Information</th>
<th>Controller API</th>
<th>API level 9</th>
<th>API level 12</th>
<th>API level 16</th>
</tr>
<tr>
<td rowspan="5">Device Identification</td>
<td>{@link android.hardware.input.InputManager#getInputDeviceIds()}</td>
<td style="text-align: center;"><big> </big></td>
<td style="text-align: center;"><big> </big></td>
<td style="text-align: center;"><big>•</big></td>
</tr>
<tr>
<td>{@link android.hardware.input.InputManager#getInputDevice(int)
getInputDevice()}</td>
<td style="text-align: center;"> </td>
<td style="text-align: center;"><big> </big></td>
<td style="text-align: center;"><big>•</big></td>
</tr>
<tr>
<td>{@link android.view.InputDevice#getVibrator()}</td>
<td style="text-align: center;"> </td>
<td style="text-align: center;"><big> </big></td>
<td style="text-align: center;"><big>•</big></td>
</tr>
<td>{@link android.view.InputDevice#SOURCE_JOYSTICK}</td>
<td style="text-align: center;"> </td>
<td style="text-align: center;"><big>•</big></td>
<td style="text-align: center;"><big>•</big></td>
</tr>
<tr>
<td>{@link android.view.InputDevice#SOURCE_GAMEPAD}</td>
<td style="text-align: center;"> </td>
<td style="text-align: center;"><big>•</big></td>
<td style="text-align: center;"><big>•</big></td>
</tr>
<tr>
<td rowspan="3">Connection Status</td>
<td>{@link android.hardware.input.InputManager.InputDeviceListener#onInputDeviceAdded(int) onInputDeviceAdded()}</td>
<td style="text-align: center;"> </td>
<td style="text-align: center;"> </td>
<td style="text-align: center;"><big>•</big></td>
</tr>
<tr>
<td>{@link android.hardware.input.InputManager.InputDeviceListener#onInputDeviceChanged(int) onInputDeviceChanged()}</td>
<td style="text-align: center;"> </td>
<td style="text-align: center;"> </td>
<td style="text-align: center;"><big>•</big></td>
</tr>
<tr>
<td>{@link android.hardware.input.InputManager.InputDeviceListener#onInputDeviceRemoved(int) onInputDeviceRemoved()}</td>
<td style="text-align: center;"> </td>
<td style="text-align: center;"> </td>
<td style="text-align: center;"><big>•</big></td>
</tr>
<tr>
<td rowspan="4">Input Event Identification</td>
<td>D-pad press (
{@link android.view.KeyEvent#KEYCODE_DPAD_UP},
{@link android.view.KeyEvent#KEYCODE_DPAD_DOWN},
{@link android.view.KeyEvent#KEYCODE_DPAD_LEFT},
{@link android.view.KeyEvent#KEYCODE_DPAD_RIGHT},
{@link android.view.KeyEvent#KEYCODE_DPAD_CENTER})</td>
<td style="text-align: center;"><big>•</big></td>
<td style="text-align: center;"><big>•</big></td>
<td style="text-align: center;"><big>•</big></td>
</tr>
<tr>
<td>Gamepad button press (
{@link android.view.KeyEvent#KEYCODE_BUTTON_A BUTTON_A},
{@link android.view.KeyEvent#KEYCODE_BUTTON_B BUTTON_B},
{@link android.view.KeyEvent#KEYCODE_BUTTON_THUMBL BUTTON_THUMBL},
{@link android.view.KeyEvent#KEYCODE_BUTTON_THUMBR BUTTON_THUMBR},
{@link android.view.KeyEvent#KEYCODE_BUTTON_SELECT BUTTON_SELECT},
{@link android.view.KeyEvent#KEYCODE_BUTTON_START BUTTON_START},
{@link android.view.KeyEvent#KEYCODE_BUTTON_R1 BUTTON_R1},
{@link android.view.KeyEvent#KEYCODE_BUTTON_L1 BUTTON_L1},
{@link android.view.KeyEvent#KEYCODE_BUTTON_R2 BUTTON_R2},
{@link android.view.KeyEvent#KEYCODE_BUTTON_L2 BUTTON_L2})</td>
<td style="text-align: center;"> </td>
<td style="text-align: center;"><big>•</big></td>
<td style="text-align: center;"><big>•</big></td>
</tr>
<tr>
<td>Joystick and hat switch movement (
{@link android.view.MotionEvent#AXIS_X},
{@link android.view.MotionEvent#AXIS_Y},
{@link android.view.MotionEvent#AXIS_Z},
{@link android.view.MotionEvent#AXIS_RZ},
{@link android.view.MotionEvent#AXIS_HAT_X},
{@link android.view.MotionEvent#AXIS_HAT_Y})</td>
<td style="text-align: center;"> </td>
<td style="text-align: center;"><big>•</big></td>
<td style="text-align: center;"><big>•</big></td>
</tr>
<tr>
<td>Analog trigger press (
{@link android.view.MotionEvent#AXIS_LTRIGGER},
{@link android.view.MotionEvent#AXIS_RTRIGGER})</td>
<td style="text-align: center;"> </td>
<td style="text-align: center;"><big>•</big></td>
<td style="text-align: center;"><big>•</big></td>
</tr>
</tbody>
</table>
<p>You can use abstraction to build version-aware game controller support that
works across platforms. This approach involves the following steps:</p>
<ol>
<li>Define an intermediary Java interface that abstracts the implementation of
the game controller features required by your game.</li>
<li>Create a proxy implementation of your interface that uses APIs in Android
4.1 and higher.</li>
<li>Create a custom implementation of your interface that uses APIs available
between Android 2.3 up to Android 4.0.</li>
<li>Create the logic for switching between these implementations at runtime,
and begin using the interface in your game.</li>
</ol>
<p>For an overview of how abstraction can be used to ensure that applications
can work in a backward compatible way across different versions of Android, see
<a href="{@docRoot}training/backward-compatible-ui/index.html">Creating
Backward-Compatible UIs</a>.
</p>
<h2 id="abstraction">Add an Interface for Backward Compatibility</h2>
<p>To provide backward compatibility, you can create a custom interface then
add version-specific implementations. One advantage of this approach is that it
lets you mirror the public interfaces on Android 4.1 (API level 16) that
support game controllers.</p>
<pre>
// The InputManagerCompat interface is a reference example.
// The full code is provided in the ControllerSample.zip sample.
public interface InputManagerCompat {
...
public InputDevice getInputDevice(int id);
public int[] getInputDeviceIds();
public void registerInputDeviceListener(
InputManagerCompat.InputDeviceListener listener,
Handler handler);
public void unregisterInputDeviceListener(
InputManagerCompat.InputDeviceListener listener);
public void onGenericMotionEvent(MotionEvent event);
public void onPause();
public void onResume();
public interface InputDeviceListener {
void onInputDeviceAdded(int deviceId);
void onInputDeviceChanged(int deviceId);
void onInputDeviceRemoved(int deviceId);
}
...
}
</pre>
<p>The {@code InputManagerCompat} interface provides the following methods:</p>
<dl>
<dt>{@code getInputDevice()}</dt>
<dd>Mirrors {@link android.hardware.input.InputManager#getInputDevice(int)
getInputDevice()}. Obtains the {@link android.view.InputDevice}
object that represents the capabilities of a game controller.</dd>
<dt>{@code getInputDeviceIds()}</dt>
<dd>Mirrors {@link android.hardware.input.InputManager#getInputDeviceIds()
getInputDeviceIds()}. Returns an array of integers, each of
which is an ID for a different input device. This is useful if you're building
a game that supports multiple players and you want to detect how many
controllers are connected.</dd>
<dt>{@code registerInputDeviceListener()}</dt>
<dd>Mirrors {@link android.hardware.input.InputManager#registerInputDeviceListener(android.hardware.input.InputManager.InputDeviceListener, android.os.Handler)
registerInputDeviceListener()}. Lets you register to be informed when a new
device is added, changed, or removed.</dd>
<dt>{@code unregisterInputDeviceListener()}</dt>
<dd>Mirrors {@link android.hardware.input.InputManager#unregisterInputDeviceListener(android.hardware.input.InputManager.InputDeviceListener) unregisterInputDeviceListener()}.
Unregisters an input device listener.</dd>
<dt>{@code onGenericMotionEvent()}</dt>
<dd>Mirrors {@link android.view.View#onGenericMotionEvent(android.view.MotionEvent)
onGenericMotionEvent()}. Lets your game intercept and handle
{@link android.view.MotionEvent} objects and axis values that represent events
such as joystick movements and analog trigger presses.</dd>
<dt>{@code onPause()}</dt>
<dd>Stops polling for game controller events when the
main activity is paused, or when the game no longer has focus.</dd>
<dt>{@code onResume()}</dt>
<dd>Starts polling for game controller events when the
main activity is resumed, or when the game is started and runs in the
foreground.</dd>
<dt>{@code InputDeviceListener}</dt>
<dd>Mirrors the {@link android.hardware.input.InputManager.InputDeviceListener}
interface. Lets your game know when a game controller has been added, changed, or
removed.</dd>
</dl>
<p>Next, create implementations for {@code InputManagerCompat} that work
across different platform versions. If your game is running on Android 4.1 or
higher and calls an {@code InputManagerCompat} method, the proxy implementation
calls the equivalent method in {@link android.hardware.input.InputManager}.
However, if your game is running on Android 2.3 up to Android 4.0, the custom implementation processes calls to {@code InputManagerCompat} methods by using
only APIs introduced no later than Android 2.3. Regardless of which
version-specific implementation is used at runtime, the implementation passes
the call results back transparently to the game.</p>
<img src="{@docRoot}images/training/backward-compatible-inputmanager.png" alt=""
id="figure1" />
<p class="img-caption">
<strong>Figure 1.</strong> Class diagram of interface and version-specific
implementations.
</p>
<h2 id="newer">Implement the Interface on Android 4.1 and Higher</h2>
<p>{@code InputManagerCompatV16} is an implementation of the
{@code InputManagerCompat} interface that proxies method calls to an
actual {@link android.hardware.input.InputManager} and {@link
android.hardware.input.InputManager.InputDeviceListener}. The
{@link android.hardware.input.InputManager} is obtained from the system
{@link android.content.Context}.</p>
<pre>
// The InputManagerCompatV16 class is a reference implementation.
// The full code is provided in the ControllerSample.zip sample.
public class InputManagerV16 implements InputManagerCompat {
private final InputManager mInputManager;
private final Map<InputManagerCompat.InputDeviceListener,
V16InputDeviceListener> mListeners;
public InputManagerV16(Context context) {
mInputManager = (InputManager)
context.getSystemService(Context.INPUT_SERVICE);
mListeners = new HashMap<InputManagerCompat.InputDeviceListener,
V16InputDeviceListener>();
}
@Override
public InputDevice getInputDevice(int id) {
return mInputManager.getInputDevice(id);
}
@Override
public int[] getInputDeviceIds() {
return mInputManager.getInputDeviceIds();
}
static class V16InputDeviceListener implements
InputManager.InputDeviceListener {
final InputManagerCompat.InputDeviceListener mIDL;
public V16InputDeviceListener(InputDeviceListener idl) {
mIDL = idl;
}
@Override
public void onInputDeviceAdded(int deviceId) {
mIDL.onInputDeviceAdded(deviceId);
}
// Do the same for device change and removal
...
}
@Override
public void registerInputDeviceListener(InputDeviceListener listener,
Handler handler) {
V16InputDeviceListener v16Listener = new
V16InputDeviceListener(listener);
mInputManager.registerInputDeviceListener(v16Listener, handler);
mListeners.put(listener, v16Listener);
}
// Do the same for unregistering an input device listener
...
@Override
public void onGenericMotionEvent(MotionEvent event) {
// unused in V16
}
@Override
public void onPause() {
// unused in V16
}
@Override
public void onResume() {
// unused in V16
}
}
</pre>
<h2 id="older">Implementing the Interface on Android 2.3 up to Android 4.0</h2>
<p>The {@code InputManagerV9} implementation uses APIs introduced no later
than Android 2.3. To create an implementation of {@code
InputManagerCompat} that supports Android 2.3 up to Android 4.0, you can use
the following objects:
<ul>
<li>A {@link android.util.SparseArray} of device IDs to track the
game controllers that are connected to the device.</li>
<li>A {@link android.os.Handler} to process device events. When an app is started
or resumed, the {@link android.os.Handler} receives a message to start polling
for game controller disconnection. The {@link android.os.Handler} will start a
loop to check each known connected game controller and see if a device ID is
returned. A {@code null} return value indicates that the game controller is
disconnected. The {@link android.os.Handler} stops polling when the app is
paused.</li>
<li>A {@link java.util.Map} of {@code InputManagerCompat.InputDeviceListener}
objects. You will use the listeners to update the connection status of tracked
game controllers.</li>
</ul>
<pre>
// The InputManagerCompatV9 class is a reference implementation.
// The full code is provided in the ControllerSample.zip sample.
public class InputManagerV9 implements InputManagerCompat {
private final SparseArray<long[]> mDevices;
private final Map<InputDeviceListener, Handler> mListeners;
private final Handler mDefaultHandler;
…
public InputManagerV9() {
mDevices = new SparseArray<long[]>();
mListeners = new HashMap<InputDeviceListener, Handler>();
mDefaultHandler = new PollingMessageHandler(this);
}
}
</pre>
<p>Implement a {@code PollingMessageHandler} object that extends
{@link android.os.Handler}, and override the
{@link android.os.Handler#handleMessage(android.os.Message) handleMessage()}
method. This method checks if an attached game controller has been
disconnected and notifies registered listeners.</p>
<pre>
private static class PollingMessageHandler extends Handler {
private final WeakReference<InputManagerV9> mInputManager;
PollingMessageHandler(InputManagerV9 im) {
mInputManager = new WeakReference<InputManagerV9>(im);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case MESSAGE_TEST_FOR_DISCONNECT:
InputManagerV9 imv = mInputManager.get();
if (null != imv) {
long time = SystemClock.elapsedRealtime();
int size = imv.mDevices.size();
for (int i = 0; i < size; i++) {
long[] lastContact = imv.mDevices.valueAt(i);
if (null != lastContact) {
if (time - lastContact[0] > CHECK_ELAPSED_TIME) {
// check to see if the device has been
// disconnected
int id = imv.mDevices.keyAt(i);
if (null == InputDevice.getDevice(id)) {
// Notify the registered listeners
// that the game controller is disconnected
...
imv.mDevices.remove(id);
} else {
lastContact[0] = time;
}
}
}
}
sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT,
CHECK_ELAPSED_TIME);
}
break;
}
}
}
</pre>
<p>To start and stop polling for game controller disconnection, override
these methods:</p>
<pre>
private static final int MESSAGE_TEST_FOR_DISCONNECT = 101;
private static final long CHECK_ELAPSED_TIME = 3000L;
@Override
public void onPause() {
mDefaultHandler.removeMessages(MESSAGE_TEST_FOR_DISCONNECT);
}
@Override
public void onResume() {
mDefaultHandler.sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT,
CHECK_ELAPSED_TIME);
}
</pre>
<p>To detect that an input device has been added, override the
{@code onGenericMotionEvent()} method. When the system reports a motion event,
check if this event came from a device ID that is already tracked, or from a
new device ID. If the device ID is new, notify registered listeners.</p>
<pre>
@Override
public void onGenericMotionEvent(MotionEvent event) {
// detect new devices
int id = event.getDeviceId();
long[] timeArray = mDevices.get(id);
if (null == timeArray) {
// Notify the registered listeners that a game controller is added
...
timeArray = new long[1];
mDevices.put(id, timeArray);
}
long time = SystemClock.elapsedRealtime();
timeArray[0] = time;
}
</pre>
<p>Notification of listeners is implemented by using the
{@link android.os.Handler} object to send a {@code DeviceEvent}
{@link java.lang.Runnable} object to the message queue. The {@code DeviceEvent}
contains a reference to an {@code InputManagerCompat.InputDeviceListener}. When
the {@code DeviceEvent} runs, the appropriate callback method of the listener
is called to signal if the game controller was added, changed, or removed.
</p>
<pre>
@Override
public void registerInputDeviceListener(InputDeviceListener listener,
Handler handler) {
mListeners.remove(listener);
if (handler == null) {
handler = mDefaultHandler;
}
mListeners.put(listener, handler);
}
@Override
public void unregisterInputDeviceListener(InputDeviceListener listener) {
mListeners.remove(listener);
}
private void notifyListeners(int why, int deviceId) {
// the state of some device has changed
if (!mListeners.isEmpty()) {
for (InputDeviceListener listener : mListeners.keySet()) {
Handler handler = mListeners.get(listener);
DeviceEvent odc = DeviceEvent.getDeviceEvent(why, deviceId,
listener);
handler.post(odc);
}
}
}
private static class DeviceEvent implements Runnable {
private int mMessageType;
private int mId;
private InputDeviceListener mListener;
private static Queue<DeviceEvent> sObjectQueue =
new ArrayDeque<DeviceEvent>();
...
static DeviceEvent getDeviceEvent(int messageType, int id,
InputDeviceListener listener) {
DeviceEvent curChanged = sObjectQueue.poll();
if (null == curChanged) {
curChanged = new DeviceEvent();
}
curChanged.mMessageType = messageType;
curChanged.mId = id;
curChanged.mListener = listener;
return curChanged;
}
@Override
public void run() {
switch (mMessageType) {
case ON_DEVICE_ADDED:
mListener.onInputDeviceAdded(mId);
break;
case ON_DEVICE_CHANGED:
mListener.onInputDeviceChanged(mId);
break;
case ON_DEVICE_REMOVED:
mListener.onInputDeviceRemoved(mId);
break;
default:
// Handle unknown message type
...
break;
}
// Put this runnable back in the queue
sObjectQueue.offer(this);
}
}
</pre>
<p>You now have two implementations of {@code InputManagerCompat}: one that
works on devices running Android 4.1 and higher, and another
that works on devices running Android 2.3 up to Android 4.0.</p>
<h2 id="using">Use the Version-Specific Implementation</h2>
<p>The version-specific switching logic is implemented in a class that acts as
a <a href="http://en.wikipedia.org/wiki/Factory_(software_concept)"
class="external-link" target="_blank">factory</a>.</p>
<pre>
public static class Factory {
public static InputManagerCompat getInputManager(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
return new InputManagerV16(context);
} else {
return new InputManagerV9();
}
}
}
</pre>
<p>Now you can simply instantiate an {@code InputManagerCompat} object and
register an {@code InputManagerCompat.InputDeviceListener} in your main
{@link android.view.View}. Because of the version-switching logic you set
up, your game automatically uses the implementation that's appropriate for the
version of Android the device is running.</p>
<pre>
public class GameView extends View implements InputDeviceListener {
private InputManagerCompat mInputManager;
...
public GameView(Context context, AttributeSet attrs) {
mInputManager =
InputManagerCompat.Factory.getInputManager(this.getContext());
mInputManager.registerInputDeviceListener(this, null);
...
}
}
</pre>
<p>Next, override the
{@link android.view.View#onGenericMotionEvent(android.view.MotionEvent)
onGenericMotionEvent()} method in your main view, as described in
<a href="controller-input.html#analog">Handle a MotionEvent from a Game
Controller</a>. Your game should now be able to process game controller events
consistently on devices running Android 2.3 (API level 9) and higher.
<p>
<pre>
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
mInputManager.onGenericMotionEvent(event);
// Handle analog input from the controller as normal
...
return super.onGenericMotionEvent(event);
}
</pre>
<p>You can find a complete implementation of this compatibility code in the
{@code GameView} class provided in the sample {@code ControllerSample.zip}
available for download above.</p>
|