Home | History | Annotate | Download | only in view
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.view;
     18 
     19 import android.content.Context;
     20 import android.hardware.input.InputManager;
     21 import android.os.Parcel;
     22 import android.os.Parcelable;
     23 import android.os.Vibrator;
     24 import android.os.NullVibrator;
     25 
     26 import java.util.ArrayList;
     27 import java.util.List;
     28 
     29 /**
     30  * Describes the capabilities of a particular input device.
     31  * <p>
     32  * Each input device may support multiple classes of input.  For example, a multi-function
     33  * keyboard may compose the capabilities of a standard keyboard together with a track pad mouse
     34  * or other pointing device.
     35  * </p><p>
     36  * Some input devices present multiple distinguishable sources of input.
     37  * Applications can query the framework about the characteristics of each distinct source.
     38  * </p><p>
     39  * As a further wrinkle, different kinds of input sources uses different coordinate systems
     40  * to describe motion events.  Refer to the comments on the input source constants for
     41  * the appropriate interpretation.
     42  * </p>
     43  */
     44 public final class InputDevice implements Parcelable {
     45     private final int mId;
     46     private final int mGeneration;
     47     private final String mName;
     48     private final String mDescriptor;
     49     private final boolean mIsExternal;
     50     private final int mSources;
     51     private final int mKeyboardType;
     52     private final KeyCharacterMap mKeyCharacterMap;
     53     private final boolean mHasVibrator;
     54     private final ArrayList<MotionRange> mMotionRanges = new ArrayList<MotionRange>();
     55 
     56     private Vibrator mVibrator; // guarded by mMotionRanges during initialization
     57 
     58     /**
     59      * A mask for input source classes.
     60      *
     61      * Each distinct input source constant has one or more input source class bits set to
     62      * specify the desired interpretation for its input events.
     63      */
     64     public static final int SOURCE_CLASS_MASK = 0x000000ff;
     65 
     66     /**
     67      * The input source has buttons or keys.
     68      * Examples: {@link #SOURCE_KEYBOARD}, {@link #SOURCE_DPAD}.
     69      *
     70      * A {@link KeyEvent} should be interpreted as a button or key press.
     71      *
     72      * Use {@link #getKeyCharacterMap} to query the device's button and key mappings.
     73      */
     74     public static final int SOURCE_CLASS_BUTTON = 0x00000001;
     75 
     76     /**
     77      * The input source is a pointing device associated with a display.
     78      * Examples: {@link #SOURCE_TOUCHSCREEN}, {@link #SOURCE_MOUSE}.
     79      *
     80      * A {@link MotionEvent} should be interpreted as absolute coordinates in
     81      * display units according to the {@link View} hierarchy.  Pointer down/up indicated when
     82      * the finger touches the display or when the selection button is pressed/released.
     83      *
     84      * Use {@link #getMotionRange} to query the range of the pointing device.  Some devices permit
     85      * touches outside the display area so the effective range may be somewhat smaller or larger
     86      * than the actual display size.
     87      */
     88     public static final int SOURCE_CLASS_POINTER = 0x00000002;
     89 
     90     /**
     91      * The input source is a trackball navigation device.
     92      * Examples: {@link #SOURCE_TRACKBALL}.
     93      *
     94      * A {@link MotionEvent} should be interpreted as relative movements in device-specific
     95      * units used for navigation purposes.  Pointer down/up indicates when the selection button
     96      * is pressed/released.
     97      *
     98      * Use {@link #getMotionRange} to query the range of motion.
     99      */
    100     public static final int SOURCE_CLASS_TRACKBALL = 0x00000004;
    101 
    102     /**
    103      * The input source is an absolute positioning device not associated with a display
    104      * (unlike {@link #SOURCE_CLASS_POINTER}).
    105      *
    106      * A {@link MotionEvent} should be interpreted as absolute coordinates in
    107      * device-specific surface units.
    108      *
    109      * Use {@link #getMotionRange} to query the range of positions.
    110      */
    111     public static final int SOURCE_CLASS_POSITION = 0x00000008;
    112 
    113     /**
    114      * The input source is a joystick.
    115      *
    116      * A {@link MotionEvent} should be interpreted as absolute joystick movements.
    117      *
    118      * Use {@link #getMotionRange} to query the range of positions.
    119      */
    120     public static final int SOURCE_CLASS_JOYSTICK = 0x00000010;
    121 
    122     /**
    123      * The input source is unknown.
    124      */
    125     public static final int SOURCE_UNKNOWN = 0x00000000;
    126 
    127     /**
    128      * The input source is a keyboard.
    129      *
    130      * This source indicates pretty much anything that has buttons.  Use
    131      * {@link #getKeyboardType()} to determine whether the keyboard has alphabetic keys
    132      * and can be used to enter text.
    133      *
    134      * @see #SOURCE_CLASS_BUTTON
    135      */
    136     public static final int SOURCE_KEYBOARD = 0x00000100 | SOURCE_CLASS_BUTTON;
    137 
    138     /**
    139      * The input source is a DPad.
    140      *
    141      * @see #SOURCE_CLASS_BUTTON
    142      */
    143     public static final int SOURCE_DPAD = 0x00000200 | SOURCE_CLASS_BUTTON;
    144 
    145     /**
    146      * The input source is a game pad.
    147      * (It may also be a {@link #SOURCE_JOYSTICK}).
    148      *
    149      * @see #SOURCE_CLASS_BUTTON
    150      */
    151     public static final int SOURCE_GAMEPAD = 0x00000400 | SOURCE_CLASS_BUTTON;
    152 
    153     /**
    154      * The input source is a touch screen pointing device.
    155      *
    156      * @see #SOURCE_CLASS_POINTER
    157      */
    158     public static final int SOURCE_TOUCHSCREEN = 0x00001000 | SOURCE_CLASS_POINTER;
    159 
    160     /**
    161      * The input source is a mouse pointing device.
    162      * This code is also used for other mouse-like pointing devices such as trackpads
    163      * and trackpoints.
    164      *
    165      * @see #SOURCE_CLASS_POINTER
    166      */
    167     public static final int SOURCE_MOUSE = 0x00002000 | SOURCE_CLASS_POINTER;
    168 
    169     /**
    170      * The input source is a stylus pointing device.
    171      * <p>
    172      * Note that this bit merely indicates that an input device is capable of obtaining
    173      * input from a stylus.  To determine whether a given touch event was produced
    174      * by a stylus, examine the tool type returned by {@link MotionEvent#getToolType(int)}
    175      * for each individual pointer.
    176      * </p><p>
    177      * A single touch event may multiple pointers with different tool types,
    178      * such as an event that has one pointer with tool type
    179      * {@link MotionEvent#TOOL_TYPE_FINGER} and another pointer with tool type
    180      * {@link MotionEvent#TOOL_TYPE_STYLUS}.  So it is important to examine
    181      * the tool type of each pointer, regardless of the source reported
    182      * by {@link MotionEvent#getSource()}.
    183      * </p>
    184      *
    185      * @see #SOURCE_CLASS_POINTER
    186      */
    187     public static final int SOURCE_STYLUS = 0x00004000 | SOURCE_CLASS_POINTER;
    188 
    189     /**
    190      * The input source is a trackball.
    191      *
    192      * @see #SOURCE_CLASS_TRACKBALL
    193      */
    194     public static final int SOURCE_TRACKBALL = 0x00010000 | SOURCE_CLASS_TRACKBALL;
    195 
    196     /**
    197      * The input source is a touch pad or digitizer tablet that is not
    198      * associated with a display (unlike {@link #SOURCE_TOUCHSCREEN}).
    199      *
    200      * @see #SOURCE_CLASS_POSITION
    201      */
    202     public static final int SOURCE_TOUCHPAD = 0x00100000 | SOURCE_CLASS_POSITION;
    203 
    204     /**
    205      * The input source is a joystick.
    206      * (It may also be a {@link #SOURCE_GAMEPAD}).
    207      *
    208      * @see #SOURCE_CLASS_JOYSTICK
    209      */
    210     public static final int SOURCE_JOYSTICK = 0x01000000 | SOURCE_CLASS_JOYSTICK;
    211 
    212     /**
    213      * A special input source constant that is used when filtering input devices
    214      * to match devices that provide any type of input source.
    215      */
    216     public static final int SOURCE_ANY = 0xffffff00;
    217 
    218     /**
    219      * Constant for retrieving the range of values for {@link MotionEvent#AXIS_X}.
    220      *
    221      * @see #getMotionRange
    222      * @deprecated Use {@link MotionEvent#AXIS_X} instead.
    223      */
    224     @Deprecated
    225     public static final int MOTION_RANGE_X = MotionEvent.AXIS_X;
    226 
    227     /**
    228      * Constant for retrieving the range of values for {@link MotionEvent#AXIS_Y}.
    229      *
    230      * @see #getMotionRange
    231      * @deprecated Use {@link MotionEvent#AXIS_Y} instead.
    232      */
    233     @Deprecated
    234     public static final int MOTION_RANGE_Y = MotionEvent.AXIS_Y;
    235 
    236     /**
    237      * Constant for retrieving the range of values for {@link MotionEvent#AXIS_PRESSURE}.
    238      *
    239      * @see #getMotionRange
    240      * @deprecated Use {@link MotionEvent#AXIS_PRESSURE} instead.
    241      */
    242     @Deprecated
    243     public static final int MOTION_RANGE_PRESSURE = MotionEvent.AXIS_PRESSURE;
    244 
    245     /**
    246      * Constant for retrieving the range of values for {@link MotionEvent#AXIS_SIZE}.
    247      *
    248      * @see #getMotionRange
    249      * @deprecated Use {@link MotionEvent#AXIS_SIZE} instead.
    250      */
    251     @Deprecated
    252     public static final int MOTION_RANGE_SIZE = MotionEvent.AXIS_SIZE;
    253 
    254     /**
    255      * Constant for retrieving the range of values for {@link MotionEvent#AXIS_TOUCH_MAJOR}.
    256      *
    257      * @see #getMotionRange
    258      * @deprecated Use {@link MotionEvent#AXIS_TOUCH_MAJOR} instead.
    259      */
    260     @Deprecated
    261     public static final int MOTION_RANGE_TOUCH_MAJOR = MotionEvent.AXIS_TOUCH_MAJOR;
    262 
    263     /**
    264      * Constant for retrieving the range of values for {@link MotionEvent#AXIS_TOUCH_MINOR}.
    265      *
    266      * @see #getMotionRange
    267      * @deprecated Use {@link MotionEvent#AXIS_TOUCH_MINOR} instead.
    268      */
    269     @Deprecated
    270     public static final int MOTION_RANGE_TOUCH_MINOR = MotionEvent.AXIS_TOUCH_MINOR;
    271 
    272     /**
    273      * Constant for retrieving the range of values for {@link MotionEvent#AXIS_TOOL_MAJOR}.
    274      *
    275      * @see #getMotionRange
    276      * @deprecated Use {@link MotionEvent#AXIS_TOOL_MAJOR} instead.
    277      */
    278     @Deprecated
    279     public static final int MOTION_RANGE_TOOL_MAJOR = MotionEvent.AXIS_TOOL_MAJOR;
    280 
    281     /**
    282      * Constant for retrieving the range of values for {@link MotionEvent#AXIS_TOOL_MINOR}.
    283      *
    284      * @see #getMotionRange
    285      * @deprecated Use {@link MotionEvent#AXIS_TOOL_MINOR} instead.
    286      */
    287     @Deprecated
    288     public static final int MOTION_RANGE_TOOL_MINOR = MotionEvent.AXIS_TOOL_MINOR;
    289 
    290     /**
    291      * Constant for retrieving the range of values for {@link MotionEvent#AXIS_ORIENTATION}.
    292      *
    293      * @see #getMotionRange
    294      * @deprecated Use {@link MotionEvent#AXIS_ORIENTATION} instead.
    295      */
    296     @Deprecated
    297     public static final int MOTION_RANGE_ORIENTATION = MotionEvent.AXIS_ORIENTATION;
    298 
    299     /**
    300      * There is no keyboard.
    301      */
    302     public static final int KEYBOARD_TYPE_NONE = 0;
    303 
    304     /**
    305      * The keyboard is not fully alphabetic.  It may be a numeric keypad or an assortment
    306      * of buttons that are not mapped as alphabetic keys suitable for text input.
    307      */
    308     public static final int KEYBOARD_TYPE_NON_ALPHABETIC = 1;
    309 
    310     /**
    311      * The keyboard supports a complement of alphabetic keys.
    312      */
    313     public static final int KEYBOARD_TYPE_ALPHABETIC = 2;
    314 
    315     public static final Parcelable.Creator<InputDevice> CREATOR =
    316             new Parcelable.Creator<InputDevice>() {
    317         public InputDevice createFromParcel(Parcel in) {
    318             return new InputDevice(in);
    319         }
    320         public InputDevice[] newArray(int size) {
    321             return new InputDevice[size];
    322         }
    323     };
    324 
    325     // Called by native code.
    326     private InputDevice(int id, int generation, String name, String descriptor,
    327             boolean isExternal, int sources,
    328             int keyboardType, KeyCharacterMap keyCharacterMap, boolean hasVibrator) {
    329         mId = id;
    330         mGeneration = generation;
    331         mName = name;
    332         mDescriptor = descriptor;
    333         mIsExternal = isExternal;
    334         mSources = sources;
    335         mKeyboardType = keyboardType;
    336         mKeyCharacterMap = keyCharacterMap;
    337         mHasVibrator = hasVibrator;
    338     }
    339 
    340     private InputDevice(Parcel in) {
    341         mId = in.readInt();
    342         mGeneration = in.readInt();
    343         mName = in.readString();
    344         mDescriptor = in.readString();
    345         mIsExternal = in.readInt() != 0;
    346         mSources = in.readInt();
    347         mKeyboardType = in.readInt();
    348         mKeyCharacterMap = KeyCharacterMap.CREATOR.createFromParcel(in);
    349         mHasVibrator = in.readInt() != 0;
    350 
    351         for (;;) {
    352             int axis = in.readInt();
    353             if (axis < 0) {
    354                 break;
    355             }
    356             addMotionRange(axis, in.readInt(),
    357                     in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat());
    358         }
    359     }
    360 
    361     /**
    362      * Gets information about the input device with the specified id.
    363      * @param id The device id.
    364      * @return The input device or null if not found.
    365      */
    366     public static InputDevice getDevice(int id) {
    367         return InputManager.getInstance().getInputDevice(id);
    368     }
    369 
    370     /**
    371      * Gets the ids of all input devices in the system.
    372      * @return The input device ids.
    373      */
    374     public static int[] getDeviceIds() {
    375         return InputManager.getInstance().getInputDeviceIds();
    376     }
    377 
    378     /**
    379      * Gets the input device id.
    380      * <p>
    381      * Each input device receives a unique id when it is first configured
    382      * by the system.  The input device id may change when the system is restarted or if the
    383      * input device is disconnected, reconnected or reconfigured at any time.
    384      * If you require a stable identifier for a device that persists across
    385      * boots and reconfigurations, use {@link #getDescriptor()}.
    386      * </p>
    387      *
    388      * @return The input device id.
    389      */
    390     public int getId() {
    391         return mId;
    392     }
    393 
    394     /**
    395      * Gets a generation number for this input device.
    396      * The generation number is incremented whenever the device is reconfigured and its
    397      * properties may have changed.
    398      *
    399      * @return The generation number.
    400      *
    401      * @hide
    402      */
    403     public int getGeneration() {
    404         return mGeneration;
    405     }
    406 
    407     /**
    408      * Gets the input device descriptor, which is a stable identifier for an input device.
    409      * <p>
    410      * An input device descriptor uniquely identifies an input device.  Its value
    411      * is intended to be persistent across system restarts, and should not change even
    412      * if the input device is disconnected, reconnected or reconfigured at any time.
    413      * </p><p>
    414      * It is possible for there to be multiple {@link InputDevice} instances that have the
    415      * same input device descriptor.  This might happen in situations where a single
    416      * human input device registers multiple {@link InputDevice} instances (HID collections)
    417      * that describe separate features of the device, such as a keyboard that also
    418      * has a trackpad.  Alternately, it may be that the input devices are simply
    419      * indistinguishable, such as two keyboards made by the same manufacturer.
    420      * </p><p>
    421      * The input device descriptor returned by {@link #getDescriptor} should only be
    422      * used when an application needs to remember settings associated with a particular
    423      * input device.  For all other purposes when referring to a logical
    424      * {@link InputDevice} instance at runtime use the id returned by {@link #getId()}.
    425      * </p>
    426      *
    427      * @return The input device descriptor.
    428      */
    429     public String getDescriptor() {
    430         return mDescriptor;
    431     }
    432 
    433     /**
    434      * Returns true if the device is a virtual input device rather than a real one,
    435      * such as the virtual keyboard (see {@link KeyCharacterMap#VIRTUAL_KEYBOARD}).
    436      * <p>
    437      * Virtual input devices are provided to implement system-level functionality
    438      * and should not be seen or configured by users.
    439      * </p>
    440      *
    441      * @return True if the device is virtual.
    442      *
    443      * @see KeyCharacterMap#VIRTUAL_KEYBOARD
    444      */
    445     public boolean isVirtual() {
    446         return mId < 0;
    447     }
    448 
    449     /**
    450      * Returns true if the device is external (connected to USB or Bluetooth or some other
    451      * peripheral bus), otherwise it is built-in.
    452      *
    453      * @return True if the device is external.
    454      *
    455      * @hide
    456      */
    457     public boolean isExternal() {
    458         return mIsExternal;
    459     }
    460 
    461     /**
    462      * Returns true if the device is a full keyboard.
    463      *
    464      * @return True if the device is a full keyboard.
    465      *
    466      * @hide
    467      */
    468     public boolean isFullKeyboard() {
    469         return (mSources & SOURCE_KEYBOARD) == SOURCE_KEYBOARD
    470                 && mKeyboardType == KEYBOARD_TYPE_ALPHABETIC;
    471     }
    472 
    473     /**
    474      * Gets the name of this input device.
    475      * @return The input device name.
    476      */
    477     public String getName() {
    478         return mName;
    479     }
    480 
    481     /**
    482      * Gets the input sources supported by this input device as a combined bitfield.
    483      * @return The supported input sources.
    484      */
    485     public int getSources() {
    486         return mSources;
    487     }
    488 
    489     /**
    490      * Gets the keyboard type.
    491      * @return The keyboard type.
    492      */
    493     public int getKeyboardType() {
    494         return mKeyboardType;
    495     }
    496 
    497     /**
    498      * Gets the key character map associated with this input device.
    499      * @return The key character map.
    500      */
    501     public KeyCharacterMap getKeyCharacterMap() {
    502         return mKeyCharacterMap;
    503     }
    504 
    505     /**
    506      * Gets information about the range of values for a particular {@link MotionEvent} axis.
    507      * If the device supports multiple sources, the same axis may have different meanings
    508      * for each source.  Returns information about the first axis found for any source.
    509      * To obtain information about the axis for a specific source, use
    510      * {@link #getMotionRange(int, int)}.
    511      *
    512      * @param axis The axis constant.
    513      * @return The range of values, or null if the requested axis is not
    514      * supported by the device.
    515      *
    516      * @see MotionEvent#AXIS_X
    517      * @see MotionEvent#AXIS_Y
    518      * @see #getSupportedAxes()
    519      */
    520     public MotionRange getMotionRange(int axis) {
    521         final int numRanges = mMotionRanges.size();
    522         for (int i = 0; i < numRanges; i++) {
    523             final MotionRange range = mMotionRanges.get(i);
    524             if (range.mAxis == axis) {
    525                 return range;
    526             }
    527         }
    528         return null;
    529     }
    530 
    531     /**
    532      * Gets information about the range of values for a particular {@link MotionEvent} axis
    533      * used by a particular source on the device.
    534      * If the device supports multiple sources, the same axis may have different meanings
    535      * for each source.
    536      *
    537      * @param axis The axis constant.
    538      * @param source The source for which to return information.
    539      * @return The range of values, or null if the requested axis is not
    540      * supported by the device.
    541      *
    542      * @see MotionEvent#AXIS_X
    543      * @see MotionEvent#AXIS_Y
    544      * @see #getSupportedAxes()
    545      */
    546     public MotionRange getMotionRange(int axis, int source) {
    547         final int numRanges = mMotionRanges.size();
    548         for (int i = 0; i < numRanges; i++) {
    549             final MotionRange range = mMotionRanges.get(i);
    550             if (range.mAxis == axis && range.mSource == source) {
    551                 return range;
    552             }
    553         }
    554         return null;
    555     }
    556 
    557     /**
    558      * Gets the ranges for all axes supported by the device.
    559      * @return The motion ranges for the device.
    560      *
    561      * @see #getMotionRange(int, int)
    562      */
    563     public List<MotionRange> getMotionRanges() {
    564         return mMotionRanges;
    565     }
    566 
    567     // Called from native code.
    568     private void addMotionRange(int axis, int source,
    569             float min, float max, float flat, float fuzz) {
    570         mMotionRanges.add(new MotionRange(axis, source, min, max, flat, fuzz));
    571     }
    572 
    573     /**
    574      * Gets the vibrator service associated with the device, if there is one.
    575      * Even if the device does not have a vibrator, the result is never null.
    576      * Use {@link Vibrator#hasVibrator} to determine whether a vibrator is
    577      * present.
    578      *
    579      * Note that the vibrator associated with the device may be different from
    580      * the system vibrator.  To obtain an instance of the system vibrator instead, call
    581      * {@link Context#getSystemService} with {@link Context#VIBRATOR_SERVICE} as argument.
    582      *
    583      * @return The vibrator service associated with the device, never null.
    584      */
    585     public Vibrator getVibrator() {
    586         synchronized (mMotionRanges) {
    587             if (mVibrator == null) {
    588                 if (mHasVibrator) {
    589                     mVibrator = InputManager.getInstance().getInputDeviceVibrator(mId);
    590                 } else {
    591                     mVibrator = NullVibrator.getInstance();
    592                 }
    593             }
    594             return mVibrator;
    595         }
    596     }
    597 
    598     /**
    599      * Provides information about the range of values for a particular {@link MotionEvent} axis.
    600      *
    601      * @see InputDevice#getMotionRange(int)
    602      */
    603     public static final class MotionRange {
    604         private int mAxis;
    605         private int mSource;
    606         private float mMin;
    607         private float mMax;
    608         private float mFlat;
    609         private float mFuzz;
    610 
    611         private MotionRange(int axis, int source, float min, float max, float flat, float fuzz) {
    612             mAxis = axis;
    613             mSource = source;
    614             mMin = min;
    615             mMax = max;
    616             mFlat = flat;
    617             mFuzz = fuzz;
    618         }
    619 
    620         /**
    621          * Gets the axis id.
    622          * @return The axis id.
    623          */
    624         public int getAxis() {
    625             return mAxis;
    626         }
    627 
    628         /**
    629          * Gets the source for which the axis is defined.
    630          * @return The source.
    631          */
    632         public int getSource() {
    633             return mSource;
    634         }
    635 
    636         /**
    637          * Gets the inclusive minimum value for the axis.
    638          * @return The inclusive minimum value.
    639          */
    640         public float getMin() {
    641             return mMin;
    642         }
    643 
    644         /**
    645          * Gets the inclusive maximum value for the axis.
    646          * @return The inclusive maximum value.
    647          */
    648         public float getMax() {
    649             return mMax;
    650         }
    651 
    652         /**
    653          * Gets the range of the axis (difference between maximum and minimum).
    654          * @return The range of values.
    655          */
    656         public float getRange() {
    657             return mMax - mMin;
    658         }
    659 
    660         /**
    661          * Gets the extent of the center flat position with respect to this axis.
    662          * <p>
    663          * For example, a flat value of 8 means that the center position is between -8 and +8.
    664          * This value is mainly useful for calibrating self-centering devices.
    665          * </p>
    666          * @return The extent of the center flat position.
    667          */
    668         public float getFlat() {
    669             return mFlat;
    670         }
    671 
    672         /**
    673          * Gets the error tolerance for input device measurements with respect to this axis.
    674          * <p>
    675          * For example, a value of 2 indicates that the measured value may be up to +/- 2 units
    676          * away from the actual value due to noise and device sensitivity limitations.
    677          * </p>
    678          * @return The error tolerance.
    679          */
    680         public float getFuzz() {
    681             return mFuzz;
    682         }
    683     }
    684 
    685     @Override
    686     public void writeToParcel(Parcel out, int flags) {
    687         out.writeInt(mId);
    688         out.writeInt(mGeneration);
    689         out.writeString(mName);
    690         out.writeString(mDescriptor);
    691         out.writeInt(mIsExternal ? 1 : 0);
    692         out.writeInt(mSources);
    693         out.writeInt(mKeyboardType);
    694         mKeyCharacterMap.writeToParcel(out, flags);
    695         out.writeInt(mHasVibrator ? 1 : 0);
    696 
    697         final int numRanges = mMotionRanges.size();
    698         for (int i = 0; i < numRanges; i++) {
    699             MotionRange range = mMotionRanges.get(i);
    700             out.writeInt(range.mAxis);
    701             out.writeInt(range.mSource);
    702             out.writeFloat(range.mMin);
    703             out.writeFloat(range.mMax);
    704             out.writeFloat(range.mFlat);
    705             out.writeFloat(range.mFuzz);
    706         }
    707         out.writeInt(-1);
    708     }
    709 
    710     @Override
    711     public int describeContents() {
    712         return 0;
    713     }
    714 
    715     @Override
    716     public String toString() {
    717         StringBuilder description = new StringBuilder();
    718         description.append("Input Device ").append(mId).append(": ").append(mName).append("\n");
    719         description.append("  Descriptor: ").append(mDescriptor).append("\n");
    720         description.append("  Generation: ").append(mGeneration).append("\n");
    721         description.append("  Location: ").append(mIsExternal ? "external" : "built-in").append("\n");
    722 
    723         description.append("  Keyboard Type: ");
    724         switch (mKeyboardType) {
    725             case KEYBOARD_TYPE_NONE:
    726                 description.append("none");
    727                 break;
    728             case KEYBOARD_TYPE_NON_ALPHABETIC:
    729                 description.append("non-alphabetic");
    730                 break;
    731             case KEYBOARD_TYPE_ALPHABETIC:
    732                 description.append("alphabetic");
    733                 break;
    734         }
    735         description.append("\n");
    736 
    737         description.append("  Has Vibrator: ").append(mHasVibrator).append("\n");
    738 
    739         description.append("  Sources: 0x").append(Integer.toHexString(mSources)).append(" (");
    740         appendSourceDescriptionIfApplicable(description, SOURCE_KEYBOARD, "keyboard");
    741         appendSourceDescriptionIfApplicable(description, SOURCE_DPAD, "dpad");
    742         appendSourceDescriptionIfApplicable(description, SOURCE_TOUCHSCREEN, "touchscreen");
    743         appendSourceDescriptionIfApplicable(description, SOURCE_MOUSE, "mouse");
    744         appendSourceDescriptionIfApplicable(description, SOURCE_STYLUS, "stylus");
    745         appendSourceDescriptionIfApplicable(description, SOURCE_TRACKBALL, "trackball");
    746         appendSourceDescriptionIfApplicable(description, SOURCE_TOUCHPAD, "touchpad");
    747         appendSourceDescriptionIfApplicable(description, SOURCE_JOYSTICK, "joystick");
    748         appendSourceDescriptionIfApplicable(description, SOURCE_GAMEPAD, "gamepad");
    749         description.append(" )\n");
    750 
    751         final int numAxes = mMotionRanges.size();
    752         for (int i = 0; i < numAxes; i++) {
    753             MotionRange range = mMotionRanges.get(i);
    754             description.append("    ").append(MotionEvent.axisToString(range.mAxis));
    755             description.append(": source=0x").append(Integer.toHexString(range.mSource));
    756             description.append(" min=").append(range.mMin);
    757             description.append(" max=").append(range.mMax);
    758             description.append(" flat=").append(range.mFlat);
    759             description.append(" fuzz=").append(range.mFuzz);
    760             description.append("\n");
    761         }
    762         return description.toString();
    763     }
    764 
    765     private void appendSourceDescriptionIfApplicable(StringBuilder description, int source,
    766             String sourceName) {
    767         if ((mSources & source) == source) {
    768             description.append(" ");
    769             description.append(sourceName);
    770         }
    771     }
    772 }
    773