InputDevice.java revision dc1ab4b5cc274b7d744c11a939bb5910becec5e0
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.os.Parcel;
20import android.os.Parcelable;
21import android.os.RemoteException;
22import android.os.ServiceManager;
23
24/**
25 * Describes the capabilities of a particular input device.
26 * <p>
27 * Each input device may support multiple classes of input.  For example, a multifunction
28 * keyboard may compose the capabilities of a standard keyboard together with a track pad mouse
29 * or other pointing device.
30 * </p><p>
31 * Some input devices present multiple distinguishable sources of input.
32 * Applications can query the framework about the characteristics of each distinct source.
33 * </p><p>
34 * As a further wrinkle, different kinds of input sources uses different coordinate systems
35 * to describe motion events.  Refer to the comments on the input source constants for
36 * the appropriate interpretation.
37 * </p>
38 */
39public final class InputDevice implements Parcelable {
40    private int mId;
41    private String mName;
42    private int mSources;
43    private int mKeyboardType;
44
45    private MotionRange[] mMotionRanges;
46
47    /**
48     * A mask for input source classes.
49     *
50     * Each distinct input source constant has one or more input source class bits set to
51     * specify the desired interpretation for its input events.
52     */
53    public static final int SOURCE_CLASS_MASK = 0x000000ff;
54
55    /**
56     * The input source has buttons or keys.
57     * Examples: {@link #SOURCE_KEYBOARD}, {@link #SOURCE_DPAD}.
58     *
59     * A {@link KeyEvent} should be interpreted as a button or key press.
60     *
61     * Use {@link #getKeyCharacterMap} to query the device's button and key mappings.
62     */
63    public static final int SOURCE_CLASS_BUTTON = 0x00000001;
64
65    /**
66     * The input source is a pointing device associated with a display.
67     * Examples: {@link #SOURCE_TOUCHSCREEN}, {@link #SOURCE_MOUSE}.
68     *
69     * A {@link MotionEvent} should be interpreted as absolute coordinates in
70     * display units according to the {@link View} hierarchy.  Pointer down/up indicated when
71     * the finger touches the display or when the selection button is pressed/released.
72     *
73     * Use {@link #getMotionRange} to query the range of the pointing device.  Some devices permit
74     * touches outside the display area so the effective range may be somewhat smaller or larger
75     * than the actual display size.
76     */
77    public static final int SOURCE_CLASS_POINTER = 0x00000002;
78
79    /**
80     * The input source is a trackball navigation device.
81     * Examples: {@link #SOURCE_TRACKBALL}.
82     *
83     * A {@link MotionEvent} should be interpreted as relative movements in device-specific
84     * units used for navigation purposes.  Pointer down/up indicates when the selection button
85     * is pressed/released.
86     *
87     * Use {@link #getMotionRange} to query the range of motion.
88     */
89    public static final int SOURCE_CLASS_TRACKBALL = 0x00000004;
90
91    /**
92     * The input source is an absolute positioning device not associated with a display
93     * (unlike {@link #SOURCE_CLASS_POINTER}).
94     *
95     * A {@link MotionEvent} should be interpreted as absolute coordinates in
96     * device-specific surface units.
97     *
98     * Use {@link #getMotionRange} to query the range of positions.
99     */
100    public static final int SOURCE_CLASS_POSITION = 0x00000008;
101
102    /**
103     * The input source is unknown.
104     */
105    public static final int SOURCE_UNKNOWN = 0x00000000;
106
107    /**
108     * The input source is a keyboard.
109     *
110     * @see #SOURCE_CLASS_BUTTON
111     */
112    public static final int SOURCE_KEYBOARD = 0x00000100 | SOURCE_CLASS_BUTTON;
113
114    /**
115     * The input source is a DPad.
116     *
117     * @see #SOURCE_CLASS_BUTTON
118     */
119    public static final int SOURCE_DPAD = 0x00000200 | SOURCE_CLASS_BUTTON;
120
121    /**
122     * The input source is a touch screen pointing device.
123     *
124     * @see #SOURCE_CLASS_POINTER
125     */
126    public static final int SOURCE_TOUCHSCREEN = 0x00001000 | SOURCE_CLASS_POINTER;
127
128    /**
129     * The input source is a mouse pointing device.
130     * This code is also used for other mouse-like pointing devices such as trackpads
131     * and trackpoints.
132     *
133     * @see #SOURCE_CLASS_POINTER
134     */
135    public static final int SOURCE_MOUSE = 0x00002000 | SOURCE_CLASS_POINTER;
136
137    /**
138     * The input source is a trackball.
139     *
140     * @see #SOURCE_CLASS_TRACKBALL
141     */
142    public static final int SOURCE_TRACKBALL = 0x00010000 | SOURCE_CLASS_TRACKBALL;
143
144    /**
145     * The input source is a touch pad or digitizer tablet that is not
146     * associated with a display (unlike {@link #SOURCE_TOUCHSCREEN}).
147     *
148     * @see #SOURCE_CLASS_POSITION
149     */
150    public static final int SOURCE_TOUCHPAD = 0x00100000 | SOURCE_CLASS_POSITION;
151
152    /**
153     * A special input source constant that is used when filtering input devices
154     * to match devices that provide any type of input source.
155     */
156    public static final int SOURCE_ANY = 0xffffff00;
157
158    /**
159     * Constant for retrieving the range of values for {@link MotionEvent.PointerCoords#x}.
160     *
161     * @see #getMotionRange
162     */
163    public static final int MOTION_RANGE_X = 0;
164
165    /**
166     * Constant for retrieving the range of values for {@link MotionEvent.PointerCoords#y}.
167     *
168     * @see #getMotionRange
169     */
170    public static final int MOTION_RANGE_Y = 1;
171
172    /**
173     * Constant for retrieving the range of values for {@link MotionEvent.PointerCoords#pressure}.
174     *
175     * @see #getMotionRange
176     */
177    public static final int MOTION_RANGE_PRESSURE = 2;
178
179    /**
180     * Constant for retrieving the range of values for {@link MotionEvent.PointerCoords#size}.
181     *
182     * @see #getMotionRange
183     */
184    public static final int MOTION_RANGE_SIZE = 3;
185
186    /**
187     * Constant for retrieving the range of values for {@link MotionEvent.PointerCoords#touchMajor}.
188     *
189     * @see #getMotionRange
190     */
191    public static final int MOTION_RANGE_TOUCH_MAJOR = 4;
192
193    /**
194     * Constant for retrieving the range of values for {@link MotionEvent.PointerCoords#touchMinor}.
195     *
196     * @see #getMotionRange
197     */
198    public static final int MOTION_RANGE_TOUCH_MINOR = 5;
199
200    /**
201     * Constant for retrieving the range of values for {@link MotionEvent.PointerCoords#toolMajor}.
202     *
203     * @see #getMotionRange
204     */
205    public static final int MOTION_RANGE_TOOL_MAJOR = 6;
206
207    /**
208     * Constant for retrieving the range of values for {@link MotionEvent.PointerCoords#toolMinor}.
209     *
210     * @see #getMotionRange
211     */
212    public static final int MOTION_RANGE_TOOL_MINOR = 7;
213
214    /**
215     * Constant for retrieving the range of values for
216     * {@link MotionEvent.PointerCoords#orientation}.
217     *
218     * @see #getMotionRange
219     */
220    public static final int MOTION_RANGE_ORIENTATION = 8;
221
222    private static final int MOTION_RANGE_LAST = MOTION_RANGE_ORIENTATION;
223
224    /**
225     * There is no keyboard.
226     */
227    public static final int KEYBOARD_TYPE_NONE = 0;
228
229    /**
230     * The keyboard is not fully alphabetic.  It may be a numeric keypad or an assortment
231     * of buttons that are not mapped as alphabetic keys suitable for text input.
232     */
233    public static final int KEYBOARD_TYPE_NON_ALPHABETIC = 1;
234
235    /**
236     * The keyboard supports a complement of alphabetic keys.
237     */
238    public static final int KEYBOARD_TYPE_ALPHABETIC = 2;
239
240    // Called by native code.
241    private InputDevice() {
242        mMotionRanges = new MotionRange[MOTION_RANGE_LAST + 1];
243    }
244
245    /**
246     * Gets information about the input device with the specified id.
247     * @param id The device id.
248     * @return The input device or null if not found.
249     */
250    public static InputDevice getDevice(int id) {
251        IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
252        try {
253            return wm.getInputDevice(id);
254        } catch (RemoteException ex) {
255            throw new RuntimeException(
256                    "Could not get input device information from Window Manager.", ex);
257        }
258    }
259
260    /**
261     * Gets the ids of all input devices in the system.
262     * @return The input device ids.
263     */
264    public static int[] getDeviceIds() {
265        IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
266        try {
267            return wm.getInputDeviceIds();
268        } catch (RemoteException ex) {
269            throw new RuntimeException(
270                    "Could not get input device ids from Window Manager.", ex);
271        }
272    }
273
274    /**
275     * Gets the input device id.
276     * @return The input device id.
277     */
278    public int getId() {
279        return mId;
280    }
281
282    /**
283     * Gets the name of this input device.
284     * @return The input device name.
285     */
286    public String getName() {
287        return mName;
288    }
289
290    /**
291     * Gets the input sources supported by this input device as a combined bitfield.
292     * @return The supported input sources.
293     */
294    public int getSources() {
295        return mSources;
296    }
297
298    /**
299     * Gets the keyboard type.
300     * @return The keyboard type.
301     */
302    public int getKeyboardType() {
303        return mKeyboardType;
304    }
305
306    /**
307     * Gets the key character map associated with this input device.
308     * @return The key character map.
309     */
310    public KeyCharacterMap getKeyCharacterMap() {
311        return KeyCharacterMap.load(mId);
312    }
313
314    /**
315     * Gets information about the range of values for a particular {@link MotionEvent}
316     * coordinate.
317     * @param rangeType The motion range constant.
318     * @return The range of values, or null if the requested coordinate is not
319     * supported by the device.
320     */
321    public MotionRange getMotionRange(int rangeType) {
322        if (rangeType < 0 || rangeType > MOTION_RANGE_LAST) {
323            throw new IllegalArgumentException("Requested range is out of bounds.");
324        }
325
326        return mMotionRanges[rangeType];
327    }
328
329    private void addMotionRange(int rangeType, float min, float max, float flat, float fuzz) {
330        if (rangeType >= 0 && rangeType <= MOTION_RANGE_LAST) {
331            MotionRange range = new MotionRange(min, max, flat, fuzz);
332            mMotionRanges[rangeType] = range;
333        }
334    }
335
336    /**
337     * Provides information about the range of values for a particular {@link MotionEvent}
338     * coordinate.
339     */
340    public static final class MotionRange {
341        private float mMin;
342        private float mMax;
343        private float mFlat;
344        private float mFuzz;
345
346        private MotionRange(float min, float max, float flat, float fuzz) {
347            mMin = min;
348            mMax = max;
349            mFlat = flat;
350            mFuzz = fuzz;
351        }
352
353        /**
354         * Gets the minimum value for the coordinate.
355         * @return The minimum value.
356         */
357        public float getMin() {
358            return mMin;
359        }
360
361        /**
362         * Gets the maximum value for the coordinate.
363         * @return The minimum value.
364         */
365        public float getMax() {
366            return mMax;
367        }
368
369        /**
370         * Gets the range of the coordinate (difference between maximum and minimum).
371         * @return The range of values.
372         */
373        public float getRange() {
374            return mMax - mMin;
375        }
376
377        /**
378         * Gets the extent of the center flat position with respect to this coordinate.
379         * For example, a flat value of 8 means that the center position is between -8 and +8.
380         * This value is mainly useful for calibrating self-centering devices.
381         * @return The extent of the center flat position.
382         */
383        public float getFlat() {
384            return mFlat;
385        }
386
387        /**
388         * Gets the error tolerance for input device measurements with respect to this coordinate.
389         * For example, a value of 2 indicates that the measured value may be up to +/- 2 units
390         * away from the actual value due to noise and device sensitivity limitations.
391         * @return The error tolerance.
392         */
393        public float getFuzz() {
394            return mFuzz;
395        }
396    }
397
398    public static final Parcelable.Creator<InputDevice> CREATOR
399            = new Parcelable.Creator<InputDevice>() {
400        public InputDevice createFromParcel(Parcel in) {
401            InputDevice result = new InputDevice();
402            result.readFromParcel(in);
403            return result;
404        }
405
406        public InputDevice[] newArray(int size) {
407            return new InputDevice[size];
408        }
409    };
410
411    private void readFromParcel(Parcel in) {
412        mId = in.readInt();
413        mName = in.readString();
414        mSources = in.readInt();
415        mKeyboardType = in.readInt();
416
417        for (;;) {
418            int rangeType = in.readInt();
419            if (rangeType < 0) {
420                break;
421            }
422
423            addMotionRange(rangeType,
424                    in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat());
425        }
426    }
427
428    @Override
429    public void writeToParcel(Parcel out, int flags) {
430        out.writeInt(mId);
431        out.writeString(mName);
432        out.writeInt(mSources);
433        out.writeInt(mKeyboardType);
434
435        for (int i = 0; i <= MOTION_RANGE_LAST; i++) {
436            MotionRange range = mMotionRanges[i];
437            if (range != null) {
438                out.writeInt(i);
439                out.writeFloat(range.mMin);
440                out.writeFloat(range.mMax);
441                out.writeFloat(range.mFlat);
442                out.writeFloat(range.mFuzz);
443            }
444        }
445        out.writeInt(-1);
446    }
447
448    @Override
449    public int describeContents() {
450        return 0;
451    }
452
453    @Override
454    public String toString() {
455        StringBuilder description = new StringBuilder();
456        description.append("Input Device ").append(mId).append(": ").append(mName).append("\n");
457
458        description.append("  Keyboard Type: ");
459        switch (mKeyboardType) {
460            case KEYBOARD_TYPE_NONE:
461                description.append("none");
462                break;
463            case KEYBOARD_TYPE_NON_ALPHABETIC:
464                description.append("non-alphabetic");
465                break;
466            case KEYBOARD_TYPE_ALPHABETIC:
467                description.append("alphabetic");
468                break;
469        }
470        description.append("\n");
471
472        description.append("  Sources:");
473        appendSourceDescriptionIfApplicable(description, SOURCE_KEYBOARD, "keyboard");
474        appendSourceDescriptionIfApplicable(description, SOURCE_DPAD, "dpad");
475        appendSourceDescriptionIfApplicable(description, SOURCE_TOUCHSCREEN, "touchscreen");
476        appendSourceDescriptionIfApplicable(description, SOURCE_MOUSE, "mouse");
477        appendSourceDescriptionIfApplicable(description, SOURCE_TRACKBALL, "trackball");
478        appendSourceDescriptionIfApplicable(description, SOURCE_TOUCHPAD, "touchpad");
479        description.append("\n");
480
481        appendRangeDescriptionIfApplicable(description, MOTION_RANGE_X, "x");
482        appendRangeDescriptionIfApplicable(description, MOTION_RANGE_Y, "y");
483        appendRangeDescriptionIfApplicable(description, MOTION_RANGE_PRESSURE, "pressure");
484        appendRangeDescriptionIfApplicable(description, MOTION_RANGE_SIZE, "size");
485        appendRangeDescriptionIfApplicable(description, MOTION_RANGE_TOUCH_MAJOR, "touchMajor");
486        appendRangeDescriptionIfApplicable(description, MOTION_RANGE_TOUCH_MINOR, "touchMinor");
487        appendRangeDescriptionIfApplicable(description, MOTION_RANGE_TOOL_MAJOR, "toolMajor");
488        appendRangeDescriptionIfApplicable(description, MOTION_RANGE_TOOL_MINOR, "toolMinor");
489        appendRangeDescriptionIfApplicable(description, MOTION_RANGE_ORIENTATION, "orientation");
490
491        return description.toString();
492    }
493
494    private void appendSourceDescriptionIfApplicable(StringBuilder description, int source,
495            String sourceName) {
496        if ((mSources & source) == source) {
497            description.append(" ");
498            description.append(sourceName);
499        }
500    }
501
502    private void appendRangeDescriptionIfApplicable(StringBuilder description,
503            int rangeType, String rangeName) {
504        MotionRange range = mMotionRanges[rangeType];
505        if (range != null) {
506            description.append("  Range[").append(rangeName);
507            description.append("]: min=").append(range.mMin);
508            description.append(" max=").append(range.mMax);
509            description.append(" flat=").append(range.mFlat);
510            description.append(" fuzz=").append(range.mFuzz);
511            description.append("\n");
512        }
513    }
514}
515