Home | History | Annotate | Download | only in game-controllers
      1 page.title=Handling Controller Actions
      2 trainingnavtop=true
      3 
      4 @jd:body
      5 
      6 <!-- This is the training bar -->
      7 <div id="tb-wrapper">
      8 <div id="tb">
      9 
     10 <h2>This lesson teaches you to</h2>
     11 <ol>
     12   <li><a href="#input">Verify a Game Controller is Connected</a></li>
     13   <li><a href="#button">Process Gamepad Button Presses</a>
     14   </li>
     15   <li><a href="#dpad">Process Directional Pad Input</a>
     16   </li>
     17   <li><a href="#joystick">Process Joystick Movements</a>
     18   </li>
     19 </ol>
     20 
     21 <h2>Try it out</h2>
     22 <div class="download-box">
     23   <a href="http://developer.android.com/shareables/training/ControllerSample.zip"
     24 class="button">Download the sample</a>
     25   <p class="filename">ControllerSample.zip</p>
     26 </div>
     27 
     28 </div>
     29 </div>
     30 
     31 <p>At the system level, Android reports input event codes from game controllers
     32 as Android key codes and axis values. In your game, you can receive these codes
     33 and values and convert them to specific in-game actions.</p>
     34 
     35 <p>When players physically connect or wirelessly pair a game controller to
     36 their Android-powered devices, the system auto-detects the controller
     37 as an input device and starts reporting its input events. Your game can receive
     38 these input events by implementing the following callback methods in your active
     39 {@link android.app.Activity} or focused {@link android.view.View} (you should
     40 implement the callbacks for either the {@link android.app.Activity} or
     41 {@link android.view.View}, but not both): </p>
     42 <ul>
     43 <li>From {@link android.app.Activity}:
     44     <ul>
     45     <li>{@link android.app.Activity#dispatchGenericMotionEvent(android.view.MotionEvent)
     46       dispatchGenericMotionEvent(android.view. MotionEvent)}
     47         <p>Called to process generic motion events such as joystick movements.</p>
     48     </li>
     49     <li>{@link android.app.Activity#dispatchKeyEvent(android.view.KeyEvent)
     50       dispatchKeyEvent(android.view.KeyEvent)}
     51         <p>Called to process key events such as a press or release of a
     52           gamepad or D-pad button.</p>
     53     </li>
     54     </ul>
     55 </li>
     56 <li>From {@link android.view.View}:
     57     <ul>
     58     <li>{@link android.view.View#onGenericMotionEvent(android.view.MotionEvent)
     59 onGenericMotionEvent(android.view.MotionEvent)}
     60         <p>Called to process generic motion events such as joystick movements.</p>
     61     </li>
     62     <li>{@link android.view.View#onKeyDown(int, android.view.KeyEvent) onKeyDown(int, android.view.KeyEvent)}
     63         <p>Called to process a press of a physical key such as a gamepad or
     64           D-pad button.</p>
     65     </li>
     66     <li>{@link android.view.View#onKeyUp(int, android.view.KeyEvent) onKeyUp(int, android.view.KeyEvent)}
     67         <p>Called to process a release of a physical key such as a gamepad or
     68           D-pad button.</p>
     69     </li>
     70     </ul>
     71 </li>
     72 </ul>
     73 
     74 <p>The recommended approach is to capture the events from the
     75   specific {@link android.view.View} object that the user interacts with.
     76   Inspect the following objects provided by the callbacks to get information
     77   about the type of input event received:</p>
     78 
     79 <dl>
     80 <dt>{@link android.view.KeyEvent}</dt>
     81    <dd>An object that describes directional
     82 pad</a> (D-pad) and gamepad button events. Key events are accompanied by a
     83 <em>key code</em> that indicates the specific button triggered, such as
     84 {@link android.view.KeyEvent#KEYCODE_DPAD_DOWN DPAD_DOWN}
     85 or {@link android.view.KeyEvent#KEYCODE_BUTTON_A BUTTON_A}. You can obtain the
     86 key code by calling {@link android.view.KeyEvent#getKeyCode()} or from key
     87 event callbacks such as
     88 {@link android.view.View#onKeyDown(int, android.view.KeyEvent) onKeyDown()}.
     89 <dd>
     90 <dt>{@link android.view.MotionEvent}</dt>
     91    <dd>An object that describes input from joystick and shoulder trigger
     92    movements. Motion events are accompanied by an action code and a set of
     93 <em>axis values</em>. The action code specifies the state change that occurred
     94 such as a joystick being moved. The axis values describe the position and other
     95 movement properties for a specific physical control, such as
     96 {@link android.view.MotionEvent#AXIS_X} or
     97 {@link android.view.MotionEvent#AXIS_RTRIGGER}. You can obtain the action code
     98 by calling {@link android.view.MotionEvent#getAction()} and the axis value by
     99 calling {@link android.view.MotionEvent#getAxisValue(int) getAxisValue()}.
    100 <dd>
    101 </dl>
    102 <p>This lesson focuses on how you can handle input from the most common types of
    103 physical controls (gamepad buttons, directional pads, and
    104 joysticks) in a game screen by implementing the above-mentioned
    105 {@link android.view.View} callback methods and processing
    106 {@link android.view.KeyEvent} and {@link android.view.MotionEvent} objects.</p>
    107 
    108 <h2 id="input">Verify a Game Controller is Connected</h2>
    109 <p>When reporting input events, Android does not distinguish
    110 between events that came from a non-game controller device and events that came
    111 from a game controller. For example, a touch screen action generates an
    112 {@link android.view.MotionEvent#AXIS_X} event that represents the X
    113 coordinate of the touch surface, but a joystick generates an {@link android.view.MotionEvent#AXIS_X} event that represents the X position of the joystick. If
    114 your game cares about handling game-controller input, you should first check
    115 that the input event comes from a relevant source type.</p>
    116 <p>To verify that a connected input device is a game controller, call
    117 {@link android.view.InputDevice#getSources()} to obtain a combined bit field of
    118 input source types supported on that device. You can then test to see if
    119 the following fields are set:</p>
    120 <ul>
    121 <li>A source type of {@link android.view.InputDevice#SOURCE_GAMEPAD} indicates
    122 that the input device has gamepad buttons (for example,
    123 {@link android.view.KeyEvent#KEYCODE_BUTTON_A BUTTON_A}). Note that this source
    124 type does not strictly indicate if the game controller has D-pad buttons,
    125 although most gamepads typically have directional controls.</li>
    126 <li>A source type of {@link android.view.InputDevice#SOURCE_DPAD} indicates that
    127 the input device has D-pad buttons (for example,
    128 {@link android.view.KeyEvent#KEYCODE_DPAD_UP DPAD_UP}).</li>
    129 <li>A source type of {@link android.view.InputDevice#SOURCE_JOYSTICK}
    130 indicates that the input device has analog control sticks (for example, a
    131 joystick that records movements along {@link android.view.MotionEvent#AXIS_X}
    132 and {@link android.view.MotionEvent#AXIS_Y}).</li>
    133 </ul>
    134 <p>The following code snippet shows a helper method that lets you check whether
    135   the connected input devices are game controllers. If so, the method retrieves
    136   the device IDs for the game controllers. You can then associate each device
    137   ID with a player in your game, and process game actions for each connected
    138   player separately. To learn more about supporting multiple game controllers
    139   that are simultaneously connected on the same Android device, see
    140   <a href="multiple-controllers.html">Supporting Multiple Game Controllers</a>.</p>
    141 <pre>
    142 public ArrayList<Integer> getGameControllerIds() {
    143     ArrayList<Integer> gameControllerDeviceIds = new ArrayList<Integer>();
    144     int[] deviceIds = InputDevice.getDeviceIds();
    145     for (int deviceId : deviceIds) {
    146         InputDevice dev = InputDevice.getDevice(deviceId);
    147         int sources = dev.getSources();
    148 
    149         // Verify that the device has gamepad buttons, control sticks, or both.
    150         if (((sources &amp; InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
    151                 || ((sources &amp; InputDevice.SOURCE_JOYSTICK)
    152                 == InputDevice.SOURCE_JOYSTICK)) {
    153             // This device is a game controller. Store its device ID.
    154             if (!gameControllerDeviceIds.contains(deviceId)) {
    155                 gameControllerDeviceIds.add(deviceId);
    156             }
    157         }
    158     }
    159     return gameControllerDeviceIds;
    160 }
    161 </pre>
    162 <p>Additionally, you might want to check for individual input capabilities
    163 supported by a connected game controller. This might be useful, for example, if
    164 you want your game to use only input from the set of physical controls it
    165 understands.</p>
    166 <p>To detect if a specific key code or axis code is supported by a connected
    167 game controller, use these techniques:</p>
    168 <ul>
    169 <li>In Android 4.4 (API level 19) or higher, you can determine if a key code is
    170 supported on a connected game controller by calling
    171 {@link android.view.InputDevice#hasKeys(int...)}.</li>
    172 <li>In Android 3.1 (API level 12) or higher, you can find all available axes
    173 supported on a connected game controller by first calling
    174 {@link android.view.InputDevice#getMotionRanges()}. Then, on each
    175 {@link android.view.InputDevice.MotionRange} object returned, call
    176 {@link android.view.InputDevice.MotionRange#getAxis()} to get its axis ID.</li>
    177 </ul>
    178 
    179 <h2 id="button">Process Gamepad Button Presses</h2>
    180 <p>Figure 1 shows how Android maps key codes and axis values to the physical
    181 controls on most game controllers.</p>
    182 <img src="{@docRoot}images/training/game-controller-profiles.png" alt=""
    183 id="figure1" />
    184 <p class="img-caption">
    185   <strong>Figure 1.</strong> Profile for a generic game controller.
    186 </p>
    187 <p>The callouts in the figure refer to the following:</p>
    188 <div style="-moz-column-count:2;-webkit-column-count:2;column-count:2;">
    189 <ol style="margin-left:30px;list-style:decimal;">
    190 <li>{@link android.view.MotionEvent#AXIS_HAT_X},
    191 {@link android.view.MotionEvent#AXIS_HAT_Y},
    192 {@link android.view.KeyEvent#KEYCODE_DPAD_UP DPAD_UP},
    193 {@link android.view.KeyEvent#KEYCODE_DPAD_DOWN DPAD_DOWN},
    194 {@link android.view.KeyEvent#KEYCODE_DPAD_LEFT DPAD_LEFT},
    195 {@link android.view.KeyEvent#KEYCODE_DPAD_RIGHT DPAD_RIGHT}
    196 </li>
    197 <li>{@link android.view.MotionEvent#AXIS_X},
    198 {@link android.view.MotionEvent#AXIS_Y},
    199 {@link android.view.KeyEvent#KEYCODE_BUTTON_THUMBL BUTTON_THUMBL}</li>
    200 <li>{@link android.view.MotionEvent#AXIS_Z},
    201 {@link android.view.MotionEvent#AXIS_RZ},
    202 {@link android.view.KeyEvent#KEYCODE_BUTTON_THUMBR BUTTON_THUMBR}</li>
    203 <li>{@link android.view.KeyEvent#KEYCODE_BUTTON_X BUTTON_X}</li>
    204 <li>{@link android.view.KeyEvent#KEYCODE_BUTTON_A BUTTON_A}</li>
    205 <li>{@link android.view.KeyEvent#KEYCODE_BUTTON_Y BUTTON_Y}</li>
    206 <li>{@link android.view.KeyEvent#KEYCODE_BUTTON_B BUTTON_B}</li>
    207 <li>{@link android.view.KeyEvent#KEYCODE_BUTTON_R1 BUTTON_R1}</li>
    208 <li>{@link android.view.MotionEvent#AXIS_RTRIGGER},
    209 {@link android.view.MotionEvent#AXIS_THROTTLE}</li>
    210 <li>{@link android.view.MotionEvent#AXIS_LTRIGGER},
    211 {@link android.view.MotionEvent#AXIS_BRAKE}</li>
    212 <li>{@link android.view.KeyEvent#KEYCODE_BUTTON_L1 BUTTON_L1}</li>
    213 </ol>
    214 </div>
    215 <p>Common key codes generated by gamepad button presses include
    216  {@link android.view.KeyEvent#KEYCODE_BUTTON_A BUTTON_A},
    217 {@link android.view.KeyEvent#KEYCODE_BUTTON_B BUTTON_B},
    218 {@link android.view.KeyEvent#KEYCODE_BUTTON_SELECT BUTTON_SELECT},
    219 and {@link android.view.KeyEvent#KEYCODE_BUTTON_START BUTTON_START}. Some game
    220 controllers also trigger the {@link android.view.KeyEvent#KEYCODE_DPAD_CENTER
    221 DPAD_CENTER} key code when the center of the D-pad crossbar is pressed. Your
    222 game can inspect the key code by calling {@link android.view.KeyEvent#getKeyCode()}
    223 or from key event callbacks such as
    224 {@link android.view.View#onKeyDown(int, android.view.KeyEvent) onKeyDown()},
    225 and if it represents an event that is relevant to your game, process it as a
    226 game action. Table 1 lists the recommended game actions for the most common
    227 gamepad buttons.
    228 </p>
    229 
    230 <p class="table-caption" id="table1">
    231   <strong>Table 1.</strong> Recommended game actions for gamepad
    232 buttons.</p>
    233 <table>
    234   <tr>
    235     <th scope="col">Game Action</th>
    236     <th scope="col">Button Key Code</th>
    237   </tr>
    238   <tr>
    239     <td>Start game in main menu, or pause/unpause during game</td>
    240     <td>{@link android.view.KeyEvent#KEYCODE_BUTTON_START BUTTON_START}<sup>*</sup></td>
    241   </tr>
    242   <tr>
    243     <td>Display menu</td>
    244     <td>{@link android.view.KeyEvent#KEYCODE_BUTTON_SELECT BUTTON_SELECT}<sup>*</sup>
    245       and {@link android.view.KeyEvent#KEYCODE_MENU}<sup>*</sup></td>
    246   </tr>
    247   <tr>
    248     <td>Same as Android <em>Back</em> navigation behavior described in the
    249       <a href="{@docRoot}design/patterns/navigation.html">Navigation</a> design
    250       guide.</td>
    251     <td>{@link android.view.KeyEvent#KEYCODE_BACK KEYCODE_BACK}</td>
    252   </tr>
    253   <tr>
    254     <td>Navigate back to a previous item in a menu</td>
    255     <td>{@link android.view.KeyEvent#KEYCODE_BUTTON_B BUTTON_B}</td>
    256   </tr>
    257   <tr>
    258     <td>Confirm selection, or perform primary game action</td>
    259     <td>{@link android.view.KeyEvent#KEYCODE_BUTTON_A BUTTON_A} and
    260 {@link android.view.KeyEvent#KEYCODE_DPAD_CENTER DPAD_CENTER}</td>
    261   </tr>
    262 </table>
    263 <p>
    264 <em>* Your game should not rely on the presence of the Start, Select, or Menu
    265   buttons.</em>
    266 </p>
    267 
    268 <p class="note"><strong>Tip: </strong>Consider providing a configuration screen
    269 in your game to allow users to personalize their own game controller mappings for
    270 game actions.</p>
    271 
    272 <p>The following snippet shows how you might override
    273 {@link android.view.View#onKeyDown(int, android.view.KeyEvent) onKeyDown()} to
    274 associate the {@link android.view.KeyEvent#KEYCODE_BUTTON_A BUTTON_A} and
    275 {@link android.view.KeyEvent#KEYCODE_DPAD_CENTER DPAD_CENTER} button presses
    276 with a game action.
    277 </p>
    278 <pre>
    279 public class GameView extends View {
    280     ...
    281 
    282     &#64;Override
    283     public boolean onKeyDown(int keyCode, KeyEvent event) {
    284         boolean handled = false;
    285         if ((event.getSource() &amp; InputDevice.SOURCE_GAMEPAD)
    286                 == InputDevice.SOURCE_GAMEPAD) {
    287             if (event.getRepeatCount() == 0) {
    288                 switch (keyCode) {
    289                     // Handle gamepad and D-pad button presses to
    290                     // navigate the ship
    291                     ...
    292 
    293                     default:
    294                          if (isFireKey(keyCode)) {
    295                              // Update the ship object to fire lasers
    296                              ...
    297                              handled = true;
    298                          }
    299                      break;
    300                 }
    301             }
    302             if (handled) {
    303                 return true;
    304             }
    305         }
    306         return super.onKeyDown(keyCode, event);
    307     }
    308 
    309     private static boolean isFireKey(int keyCode) {
    310         // Here we treat Button_A and DPAD_CENTER as the primary action
    311         // keys for the game.
    312         return keyCode == KeyEvent.KEYCODE_DPAD_CENTER
    313                 || keyCode == KeyEvent.KEYCODE_BUTTON_A;
    314     }
    315 }
    316 </pre>
    317 
    318 <p class="note"><strong>Note: </strong>On Android 4.2 (API
    319 level 17) and lower, the system treats
    320 {@link android.view.KeyEvent#KEYCODE_BUTTON_A BUTTON_A} as the Android
    321 <em>Back</em> key by default. If your app supports these Android
    322 versions, make sure to treat
    323 {@link android.view.KeyEvent#KEYCODE_BUTTON_A BUTTON_A} as the primary game
    324 action. To determine the current Android SDK
    325 version on the device, refer to the
    326 {@link android.os.Build.VERSION#SDK_INT Build.VERSION.SDK_INT} value.</p>
    327 
    328 <h2 id="dpad">Process Directional Pad Input</h2>
    329 <p>The 4-way directional pad (D-pad) is a common physical control in many game
    330 controllers. Android reports D-pad UP and DOWN presses as
    331 {@link android.view.MotionEvent#AXIS_HAT_Y} events with a range
    332 from -1.0 (up) to 1.0 (down), and D-pad LEFT or RIGHT presses as
    333 {@link android.view.MotionEvent#AXIS_HAT_X} events with a range from -1.0
    334 (left) to 1.0 (right).</p>
    335 <p>Some controllers instead report D-pad presses with a key code. If your game
    336 cares about D-pad presses, you should treat the hat axis events and the D-pad
    337 key codes as the same input events, as recommended in table 2.</p>
    338 <p class="table-caption" id="table2">
    339   <strong>Table 2.</strong> Recommended default game actions for D-pad key
    340   codes and hat axis values.</p>
    341 <table>
    342   <tr>
    343     <th scope="col">Game Action</th>
    344     <th scope="col">D-pad Key Code</th>
    345     <th scope="col">Hat Axis Code</th>
    346   </tr>
    347   <tr>
    348     <td>Move Up</td>
    349     <td>{@link android.view.KeyEvent#KEYCODE_DPAD_UP}</td>
    350     <td>{@link android.view.MotionEvent#AXIS_HAT_Y} (for values 0 to -1.0)</td>
    351   </tr>
    352   <tr>
    353     <td>Move Down</td>
    354     <td>{@link android.view.KeyEvent#KEYCODE_DPAD_DOWN}</td>
    355     <td>{@link android.view.MotionEvent#AXIS_HAT_Y} (for values 0 to 1.0)</td>
    356   </tr>
    357   <tr>
    358     <td>Move Left</td>
    359     <td>{@link android.view.KeyEvent#KEYCODE_DPAD_LEFT}</td>
    360     <td>{@link android.view.MotionEvent#AXIS_HAT_X} (for values 0 to -1.0)</td>
    361   </tr>
    362   <tr>
    363     <td>Move Right</td>
    364     <td>{@link android.view.KeyEvent#KEYCODE_DPAD_RIGHT}</td>
    365     <td>{@link android.view.MotionEvent#AXIS_HAT_X} (for values 0 to 1.0)</td>
    366   </tr>
    367 </table>
    368 
    369 
    370 <p>The following code snippet shows a helper class that lets you check the hat
    371 axis and key code values from an input event to determine the D-pad direction.
    372 </p>
    373 <pre>
    374 public class Dpad {
    375     final static int UP       = 0;
    376     final static int LEFT     = 1;
    377     final static int RIGHT    = 2;
    378     final static int DOWN     = 3;
    379     final static int CENTER   = 4;
    380 
    381     int directionPressed = -1; // initialized to -1
    382 
    383     public int getDirectionPressed(InputEvent event) {
    384         if (!isDpadDevice(event)) {
    385            return -1;
    386         }
    387 
    388         // If the input event is a MotionEvent, check its hat axis values.
    389         if (event instanceof MotionEvent) {
    390 
    391             // Use the hat axis value to find the D-pad direction
    392             MotionEvent motionEvent = (MotionEvent) event;
    393             float xaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_X);
    394             float yaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_Y);
    395 
    396             // Check if the AXIS_HAT_X value is -1 or 1, and set the D-pad
    397             // LEFT and RIGHT direction accordingly.
    398             if (Float.compare(xaxis, -1.0f) == 0) {
    399                 directionPressed =  Dpad.LEFT;
    400             } else if (Float.compare(xaxis, 1.0f) == 0) {
    401                 directionPressed =  Dpad.RIGHT;
    402             }
    403             // Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad
    404             // UP and DOWN direction accordingly.
    405             else if (Float.compare(yaxis, -1.0f) == 0) {
    406                 directionPressed =  Dpad.UP;
    407             } else if (Float.compare(yaxis, 1.0f) == 0) {
    408                 directionPressed =  Dpad.DOWN;
    409             }
    410         }
    411 
    412         // If the input event is a KeyEvent, check its key code.
    413         else if (event instanceof KeyEvent) {
    414 
    415            // Use the key code to find the D-pad direction.
    416             KeyEvent keyEvent = (KeyEvent) event;
    417             if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) {
    418                 directionPressed = Dpad.LEFT;
    419             } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT) {
    420                 directionPressed = Dpad.RIGHT;
    421             } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP) {
    422                 directionPressed = Dpad.UP;
    423             } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN) {
    424                 directionPressed = Dpad.DOWN;
    425             } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER) {
    426                 directionPressed = Dpad.CENTER;
    427             }
    428         }
    429         return directionPressed;
    430     }
    431 
    432     public static boolean isDpadDevice(InputEvent event) {
    433         // Check that input comes from a device with directional pads.
    434         if ((event.getSource() &amp; InputDevice.SOURCE_DPAD)
    435              != InputDevice.SOURCE_DPAD) {
    436              return true;
    437          } else {
    438              return false;
    439          }
    440      }
    441 }
    442 </pre>
    443 
    444 <p>You can use this helper class in your game wherever you want to process
    445   D-pad input (for example, in the
    446 {@link android.view.View#onGenericMotionEvent(android.view.MotionEvent)
    447 onGenericMotionEvent()} or
    448 {@link android.view.View#onKeyDown(int, android.view.KeyEvent) onKeyDown()}
    449 callbacks).</p>
    450 <p>For example:</p>
    451 <pre>
    452 Dpad mDpad = new Dpad();
    453 ...
    454 &#64;Override
    455 public boolean onGenericMotionEvent(MotionEvent event) {
    456 
    457     // Check if this event if from a D-pad and process accordingly.
    458     if (Dpad.isDpadDevice(event)) {
    459 
    460        int press = mDpad.getDirectionPressed(event);
    461        switch (press) {
    462             case LEFT:
    463                 // Do something for LEFT direction press
    464                 ...
    465                 return true;
    466             case RIGHT:
    467                 // Do something for RIGHT direction press
    468                 ...
    469                 return true;
    470             case UP:
    471                 // Do something for UP direction press
    472                 ...
    473                 return true;
    474             ...
    475         }
    476     }
    477 
    478     // Check if this event is from a joystick movement and process accordingly.
    479     ...
    480 }
    481 </pre>
    482 
    483 <h2 id="joystick">Process Joystick Movements</h2>
    484 <p>When players move a joystick on their game controllers, Android reports a
    485 {@link android.view.MotionEvent} that contains the
    486 {@link android.view.MotionEvent#ACTION_MOVE} action code and the updated
    487 positions of the joystick's axes. Your game can use the data provided by
    488 the {@link android.view.MotionEvent} to determine if a joystick movement it
    489 cares about happened.
    490 </p>
    491 <p>Note that joystick motion events may batch multiple movement samples together
    492 within a single object. The {@link android.view.MotionEvent} object contains
    493 the current position for each joystick axis as well as multiple historical
    494 positions for each axis.  When reporting motion events with action code {@link android.view.MotionEvent#ACTION_MOVE} (such as joystick movements), Android batches up the
    495 axis values for efficiency. The historical values for an axis consists of the
    496 set of distinct values older than the current axis value, and more recent than
    497 values reported in any previous motion events. See the
    498 {@link android.view.MotionEvent} reference for details.</p>
    499 <p>You can use the historical information to more accurately render a game
    500 object's movement based on the joystick input. To
    501 retrieve the current and historical values, call
    502 {@link android.view.MotionEvent#getAxisValue(int)
    503 getAxisValue()} or {@link android.view.MotionEvent#getHistoricalAxisValue(int,
    504 int) getHistoricalAxisValue()}. You can also find the number of historical
    505 points in the joystick event by calling
    506 {@link android.view.MotionEvent#getHistorySize()}.</p>
    507 <p>The following snippet shows how you might override the
    508 {@link android.view.View#onGenericMotionEvent(android.view.MotionEvent)
    509 onGenericMotionEvent()} callback to process joystick input. You should first
    510 process the historical values for an axis, then process its current position.
    511 </p>
    512 <pre>
    513 public class GameView extends View {
    514 
    515     &#64;Override
    516     public boolean onGenericMotionEvent(MotionEvent event) {
    517 
    518         // Check that the event came from a game controller
    519         if ((event.getSource() &amp; InputDevice.SOURCE_JOYSTICK) ==
    520                 InputDevice.SOURCE_JOYSTICK &amp;&amp;
    521                 event.getAction() == MotionEvent.ACTION_MOVE) {
    522 
    523             // Process all historical movement samples in the batch
    524             final int historySize = event.getHistorySize();
    525 
    526             // Process the movements starting from the
    527             // earliest historical position in the batch
    528             for (int i = 0; i &lt; historySize; i++) {
    529                 // Process the event at historical position i
    530                 processJoystickInput(event, i);
    531             }
    532 
    533             // Process the current movement sample in the batch (position -1)
    534             processJoystickInput(event, -1);
    535             return true;
    536         }
    537         return super.onGenericMotionEvent(event);
    538     }
    539 }
    540 </pre>
    541 <p>Before using joystick input, you need to determine if the joystick is
    542 centered, then calculate its axis movements accordingly. Joysticks typically
    543 have a <em>flat</em> area, that is, a range of values near the (0,0) coordinate
    544 at which the axis is considered to be centered. If the axis value reported by
    545 Android falls within the flat area, you should treat the controller to be at
    546 rest (that is, motionless along both axes).</p>
    547 <p>The snippet below shows a helper method that calculates the movement along
    548 each axis. You invoke this helper in the {@code processJoystickInput()} method
    549 described further below.
    550 </p>
    551 <pre>
    552 private static float getCenteredAxis(MotionEvent event,
    553         InputDevice device, int axis, int historyPos) {
    554     final InputDevice.MotionRange range =
    555             device.getMotionRange(axis, event.getSource());
    556 
    557     // A joystick at rest does not always report an absolute position of
    558     // (0,0). Use the getFlat() method to determine the range of values
    559     // bounding the joystick axis center.
    560     if (range != null) {
    561         final float flat = range.getFlat();
    562         final float value =
    563                 historyPos &lt; 0 ? event.getAxisValue(axis):
    564                 event.getHistoricalAxisValue(axis, historyPos);
    565 
    566         // Ignore axis values that are within the 'flat' region of the
    567         // joystick axis center.
    568         if (Math.abs(value) > flat) {
    569             return value;
    570         }
    571     }
    572     return 0;
    573 }
    574 </pre>
    575 <p>Putting it all together, here is how you might process joystick movements in
    576 your game:</p>
    577 <pre>
    578 private void processJoystickInput(MotionEvent event,
    579         int historyPos) {
    580 
    581     InputDevice mInputDevice = event.getDevice();
    582 
    583     // Calculate the horizontal distance to move by
    584     // using the input value from one of these physical controls:
    585     // the left control stick, hat axis, or the right control stick.
    586     float x = getCenteredAxis(event, mInputDevice,
    587             MotionEvent.AXIS_X, historyPos);
    588     if (x == 0) {
    589         x = getCenteredAxis(event, mInputDevice,
    590                 MotionEvent.AXIS_HAT_X, historyPos);
    591     }
    592     if (x == 0) {
    593         x = getCenteredAxis(event, mInputDevice,
    594                 MotionEvent.AXIS_Z, historyPos);
    595     }
    596 
    597     // Calculate the vertical distance to move by
    598     // using the input value from one of these physical controls:
    599     // the left control stick, hat switch, or the right control stick.
    600     float y = getCenteredAxis(event, mInputDevice,
    601             MotionEvent.AXIS_Y, historyPos);
    602     if (y == 0) {
    603         y = getCenteredAxis(event, mInputDevice,
    604                 MotionEvent.AXIS_HAT_Y, historyPos);
    605     }
    606     if (y == 0) {
    607         y = getCenteredAxis(event, mInputDevice,
    608                 MotionEvent.AXIS_RZ, historyPos);
    609     }
    610 
    611     // Update the ship object based on the new x and y values
    612 }
    613 </pre>
    614 <p>To support game controllers that have more sophisticated
    615 features beyond a single joystick, follow these best practices: </p>
    616 <ul>
    617 <li><strong>Handle dual controller sticks.</strong> Many game controllers have
    618 both a left and right joystick. For the left stick, Android
    619 reports horizontal movements as {@link android.view.MotionEvent#AXIS_X} events
    620 and vertical movements as {@link android.view.MotionEvent#AXIS_Y} events.
    621 For the right stick, Android reports horizontal movements as
    622 {@link android.view.MotionEvent#AXIS_Z} events and vertical movements as
    623 {@link android.view.MotionEvent#AXIS_RZ} events. Make sure to handle
    624 both controller sticks in your code.</li>
    625 <li><strong>Handle shoulder trigger presses (but provide alternative input
    626 methods).</strong> Some controllers have left and right shoulder
    627 triggers. If these triggers are present, Android reports a left trigger press
    628 as an {@link android.view.MotionEvent#AXIS_LTRIGGER} event and a
    629 right trigger press as an
    630 {@link android.view.MotionEvent#AXIS_RTRIGGER} event. On Android
    631 4.3 (API level 18), a controller that produces a
    632 {@link android.view.MotionEvent#AXIS_LTRIGGER} also reports an
    633 identical value for the {@link android.view.MotionEvent#AXIS_BRAKE} axis. The
    634 same is true for {@link android.view.MotionEvent#AXIS_RTRIGGER} and
    635 {@link android.view.MotionEvent#AXIS_GAS}. Android reports all analog trigger
    636 presses with a normalized value from 0.0 (released) to 1.0 (fully pressed). Not
    637 all controllers have triggers, so consider allowing players to perform those
    638 game actions with other buttons.
    639 </li>
    640 </ul>