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
17package android.view;
18
19import android.content.Context;
20import android.hardware.input.InputManager;
21import android.os.Parcel;
22import android.os.Parcelable;
23import android.os.Vibrator;
24import android.os.NullVibrator;
25
26import java.util.ArrayList;
27import 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 */
44public 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