blob: cb23c45581435fede5b9217eb3155672368b2901 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 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 com.android.server;
18
19import android.util.Log;
20import android.view.Display;
21import android.view.MotionEvent;
22import android.view.Surface;
23import android.view.WindowManagerPolicy;
24
25public class InputDevice {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070026 static final boolean DEBUG_POINTERS = false;
27
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028 /** Amount that trackball needs to move in order to generate a key event. */
29 static final int TRACKBALL_MOVEMENT_THRESHOLD = 6;
30
Dianne Hackborn9822d2b2009-07-20 17:33:15 -070031 /** Maximum number of pointers we will track and report. */
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070032 static final int MAX_POINTERS = 10;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -070033
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034 final int id;
35 final int classes;
36 final String name;
37 final AbsoluteInfo absX;
38 final AbsoluteInfo absY;
39 final AbsoluteInfo absPressure;
40 final AbsoluteInfo absSize;
41
Dianne Hackborn9822d2b2009-07-20 17:33:15 -070042 long mKeyDownTime = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043 int mMetaKeysState = 0;
44
45 final MotionState mAbs = new MotionState(0, 0);
46 final MotionState mRel = new MotionState(TRACKBALL_MOVEMENT_THRESHOLD,
47 TRACKBALL_MOVEMENT_THRESHOLD);
48
49 static class MotionState {
50 int xPrecision;
51 int yPrecision;
52 float xMoveScale;
53 float yMoveScale;
54 MotionEvent currentMove = null;
55 boolean changed = false;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -070056 long mDownTime = 0;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070057
58 // The currently assigned pointer IDs, corresponding to the last data.
59 int[] mPointerIds = new int[MAX_POINTERS];
60
61 // This is the last generated pointer data, ordered to match
62 // mPointerIds.
63 int mLastNumPointers = 0;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -070064 final int[] mLastData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070065
66 // This is the next set of pointer data being generated. It is not
67 // in any known order, and will be propagated in to mLastData
68 // as part of mapping it to the appropriate pointer IDs.
69 // Note that we have one extra sample of data here, to help clients
70 // avoid doing bounds checking.
71 int mNextNumPointers = 0;
72 final int[] mNextData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS)
73 + MotionEvent.NUM_SAMPLE_DATA];
74
75 // Temporary data structures for doing the pointer ID mapping.
76 final int[] mLast2Next = new int[MAX_POINTERS];
77 final int[] mNext2Last = new int[MAX_POINTERS];
78 final long[] mNext2LastDistance = new long[MAX_POINTERS];
79
80 // Temporary data structure for generating the final motion data.
Dianne Hackborn9822d2b2009-07-20 17:33:15 -070081 final float[] mReportData = new float[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070083 // This is not used here, but can be used by callers for state tracking.
84 int mAddingPointerOffset = 0;
85 final boolean[] mDown = new boolean[MAX_POINTERS];
86
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 MotionState(int mx, int my) {
88 xPrecision = mx;
89 yPrecision = my;
90 xMoveScale = mx != 0 ? (1.0f/mx) : 1.0f;
91 yMoveScale = my != 0 ? (1.0f/my) : 1.0f;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070092 for (int i=0; i<MAX_POINTERS; i++) {
93 mPointerIds[i] = i;
94 }
95 }
96
97 private boolean assignPointer(int nextIndex, boolean allowOverlap) {
98 final int lastNumPointers = mLastNumPointers;
99 final int[] next2Last = mNext2Last;
100 final long[] next2LastDistance = mNext2LastDistance;
101 final int[] last2Next = mLast2Next;
102 final int[] lastData = mLastData;
103 final int[] nextData = mNextData;
104 final int id = nextIndex * MotionEvent.NUM_SAMPLE_DATA;
105
106 if (DEBUG_POINTERS) Log.v("InputDevice", "assignPointer: nextIndex="
107 + nextIndex + " dataOff=" + id);
108 final int x1 = nextData[id + MotionEvent.SAMPLE_X];
109 final int y1 = nextData[id + MotionEvent.SAMPLE_Y];
110
111 long bestDistance = -1;
112 int bestIndex = -1;
113 for (int j=0; j<lastNumPointers; j++) {
114 if (!allowOverlap && last2Next[j] < 0) {
115 continue;
116 }
117 final int jd = j * MotionEvent.NUM_SAMPLE_DATA;
118 final int xd = lastData[jd + MotionEvent.SAMPLE_X] - x1;
119 final int yd = lastData[jd + MotionEvent.SAMPLE_Y] - y1;
120 final long distance = xd*(long)xd + yd*(long)yd;
121 if (j == 0 || distance < bestDistance) {
122 bestDistance = distance;
123 bestIndex = j;
124 }
125 }
126
127 if (DEBUG_POINTERS) Log.v("InputDevice", "New index " + nextIndex
128 + " best old index=" + bestIndex + " (distance="
129 + bestDistance + ")");
130 next2Last[nextIndex] = bestIndex;
131 next2LastDistance[nextIndex] = bestDistance;
132
133 if (bestIndex < 0) {
134 return true;
135 }
136
137 if (last2Next[bestIndex] == -1) {
138 last2Next[bestIndex] = nextIndex;
139 return false;
140 }
141
142 if (DEBUG_POINTERS) Log.v("InputDevice", "Old index " + bestIndex
143 + " has multiple best new pointers!");
144
145 last2Next[bestIndex] = -2;
146 return true;
147 }
148
149 private int updatePointerIdentifiers() {
150 final int[] lastData = mLastData;
151 final int[] nextData = mNextData;
152 final int nextNumPointers = mNextNumPointers;
153 final int lastNumPointers = mLastNumPointers;
154
155 if (nextNumPointers == 1 && lastNumPointers == 1) {
156 System.arraycopy(nextData, 0, lastData, 0,
157 MotionEvent.NUM_SAMPLE_DATA);
158 return -1;
159 }
160
161 // Clear our old state.
162 final int[] last2Next = mLast2Next;
163 for (int i=0; i<lastNumPointers; i++) {
164 last2Next[i] = -1;
165 }
166
167 if (DEBUG_POINTERS) Log.v("InputDevice",
168 "Update pointers: lastNumPointers=" + lastNumPointers
169 + " nextNumPointers=" + nextNumPointers);
170
171 // Figure out the closes new points to the previous points.
172 final int[] next2Last = mNext2Last;
173 final long[] next2LastDistance = mNext2LastDistance;
174 boolean conflicts = false;
175 for (int i=0; i<nextNumPointers; i++) {
176 conflicts |= assignPointer(i, true);
177 }
178
179 // Resolve ambiguities in pointer mappings, when two or more
180 // new pointer locations find their best previous location is
181 // the same.
182 if (conflicts) {
183 if (DEBUG_POINTERS) Log.v("InputDevice", "Resolving conflicts");
184
185 for (int i=0; i<lastNumPointers; i++) {
186 if (last2Next[i] != -2) {
187 continue;
188 }
189
190 // Note that this algorithm is far from perfect. Ideally
191 // we should do something like the one described at
192 // http://portal.acm.org/citation.cfm?id=997856
193
194 if (DEBUG_POINTERS) Log.v("InputDevice",
195 "Resolving last index #" + i);
196
197 int numFound;
198 do {
199 numFound = 0;
200 long worstDistance = 0;
201 int worstJ = -1;
202 for (int j=0; j<nextNumPointers; j++) {
203 if (next2Last[j] != i) {
204 continue;
205 }
206 numFound++;
207 if (worstDistance < next2LastDistance[j]) {
208 worstDistance = next2LastDistance[j];
209 worstJ = j;
210 }
211 }
212
213 if (worstJ >= 0) {
214 if (DEBUG_POINTERS) Log.v("InputDevice",
215 "Worst new pointer: " + worstJ
216 + " (distance=" + worstDistance + ")");
217 if (assignPointer(worstJ, false)) {
218 // In this case there is no last pointer
219 // remaining for this new one!
220 next2Last[worstJ] = -1;
221 }
222 }
223 } while (numFound > 2);
224 }
225 }
226
227 int retIndex = -1;
228
229 if (lastNumPointers < nextNumPointers) {
230 // We have one or more new pointers that are down. Create a
231 // new pointer identifier for one of them.
232 if (DEBUG_POINTERS) Log.v("InputDevice", "Adding new pointer");
233 int nextId = 0;
234 int i=0;
235 while (i < lastNumPointers) {
236 if (mPointerIds[i] > nextId) {
237 // Found a hole, insert the pointer here.
238 if (DEBUG_POINTERS) Log.v("InputDevice",
239 "Inserting new pointer at hole " + i);
240 System.arraycopy(mPointerIds, i, mPointerIds,
241 i+1, lastNumPointers-i);
242 System.arraycopy(lastData, i*MotionEvent.NUM_SAMPLE_DATA,
243 lastData, (i+1)*MotionEvent.NUM_SAMPLE_DATA,
244 (lastNumPointers-i)*MotionEvent.NUM_SAMPLE_DATA);
245 break;
246 }
247 i++;
248 nextId++;
249 }
250
251 if (DEBUG_POINTERS) Log.v("InputDevice",
252 "New pointer id " + nextId + " at index " + i);
253
254 mLastNumPointers++;
255 retIndex = i;
256 mPointerIds[i] = nextId;
257
258 // And assign this identifier to the first new pointer.
259 for (int j=0; j<nextNumPointers; j++) {
260 if (next2Last[j] < 0) {
261 if (DEBUG_POINTERS) Log.v("InputDevice",
262 "Assigning new id to new pointer index " + j);
263 next2Last[j] = i;
264 break;
265 }
266 }
267 }
268
269 // Propagate all of the current data into the appropriate
270 // location in the old data to match the pointer ID that was
271 // assigned to it.
272 for (int i=0; i<nextNumPointers; i++) {
273 int lastIndex = next2Last[i];
274 if (lastIndex >= 0) {
275 if (DEBUG_POINTERS) Log.v("InputDevice",
276 "Copying next pointer index " + i
277 + " to last index " + lastIndex);
278 System.arraycopy(nextData, i*MotionEvent.NUM_SAMPLE_DATA,
279 lastData, lastIndex*MotionEvent.NUM_SAMPLE_DATA,
280 MotionEvent.NUM_SAMPLE_DATA);
281 }
282 }
283
284 if (lastNumPointers > nextNumPointers) {
285 // One or more pointers has gone up. Find the first one,
286 // and adjust accordingly.
287 if (DEBUG_POINTERS) Log.v("InputDevice", "Removing old pointer");
288 for (int i=0; i<lastNumPointers; i++) {
289 if (last2Next[i] == -1) {
290 if (DEBUG_POINTERS) Log.v("InputDevice",
291 "Removing old pointer at index " + i);
292 retIndex = i;
293 break;
294 }
295 }
296 }
297
298 return retIndex;
299 }
300
301 void removeOldPointer(int index) {
302 final int lastNumPointers = mLastNumPointers;
303 if (index >= 0 && index < lastNumPointers) {
304 System.arraycopy(mPointerIds, index+1, mPointerIds,
305 index, lastNumPointers-index-1);
306 System.arraycopy(mLastData, (index+1)*MotionEvent.NUM_SAMPLE_DATA,
307 mLastData, (index)*MotionEvent.NUM_SAMPLE_DATA,
308 (lastNumPointers-index-1)*MotionEvent.NUM_SAMPLE_DATA);
309 mLastNumPointers--;
310 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311 }
312
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700313 MotionEvent generateAbsMotion(InputDevice device, long curTime,
314 long curTimeNano, Display display, int orientation,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 int metaState) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700316
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700317 if (mNextNumPointers <= 0 && mLastNumPointers <= 0) {
318 return null;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700319 }
320
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700321 final int lastNumPointers = mLastNumPointers;
322 final int nextNumPointers = mNextNumPointers;
323 if (mNextNumPointers > MAX_POINTERS) {
324 Log.w("InputDevice", "Number of pointers " + mNextNumPointers
325 + " exceeded maximum of " + MAX_POINTERS);
326 mNextNumPointers = MAX_POINTERS;
327 }
328
329 int upOrDownPointer = updatePointerIdentifiers();
330
331 final float[] reportData = mReportData;
332 final int[] rawData = mLastData;
333
334 final int numPointers = mLastNumPointers;
335
336 if (DEBUG_POINTERS) Log.v("InputDevice", "Processing "
337 + numPointers + " pointers (going from " + lastNumPointers
338 + " to " + nextNumPointers + ")");
339
340 for (int i=0; i<numPointers; i++) {
341 final int pos = i * MotionEvent.NUM_SAMPLE_DATA;
342 reportData[pos + MotionEvent.SAMPLE_X] = rawData[pos + MotionEvent.SAMPLE_X];
343 reportData[pos + MotionEvent.SAMPLE_Y] = rawData[pos + MotionEvent.SAMPLE_Y];
344 reportData[pos + MotionEvent.SAMPLE_PRESSURE] = rawData[pos + MotionEvent.SAMPLE_PRESSURE];
345 reportData[pos + MotionEvent.SAMPLE_SIZE] = rawData[pos + MotionEvent.SAMPLE_SIZE];
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700346 }
347
348 int action;
349 int edgeFlags = 0;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700350 if (nextNumPointers != lastNumPointers) {
351 if (nextNumPointers > lastNumPointers) {
352 if (lastNumPointers == 0) {
353 action = MotionEvent.ACTION_DOWN;
354 mDownTime = curTime;
355 } else {
356 action = MotionEvent.ACTION_POINTER_DOWN
357 | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT);
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700358 }
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700359 } else {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700360 if (numPointers == 1) {
361 action = MotionEvent.ACTION_UP;
362 } else {
363 action = MotionEvent.ACTION_POINTER_UP
364 | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT);
365 }
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700366 }
367 currentMove = null;
368 } else {
369 action = MotionEvent.ACTION_MOVE;
370 }
371
372 final int dispW = display.getWidth()-1;
373 final int dispH = display.getHeight()-1;
374 int w = dispW;
375 int h = dispH;
376 if (orientation == Surface.ROTATION_90
377 || orientation == Surface.ROTATION_270) {
378 int tmp = w;
379 w = h;
380 h = tmp;
381 }
382
383 final AbsoluteInfo absX = device.absX;
384 final AbsoluteInfo absY = device.absY;
385 final AbsoluteInfo absPressure = device.absPressure;
386 final AbsoluteInfo absSize = device.absSize;
387 for (int i=0; i<numPointers; i++) {
388 final int j = i * MotionEvent.NUM_SAMPLE_DATA;
389
390 if (absX != null) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700391 reportData[j + MotionEvent.SAMPLE_X] =
392 ((reportData[j + MotionEvent.SAMPLE_X]-absX.minValue)
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700393 / absX.range) * w;
394 }
395 if (absY != null) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700396 reportData[j + MotionEvent.SAMPLE_Y] =
397 ((reportData[j + MotionEvent.SAMPLE_Y]-absY.minValue)
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700398 / absY.range) * h;
399 }
400 if (absPressure != null) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700401 reportData[j + MotionEvent.SAMPLE_PRESSURE] =
402 ((reportData[j + MotionEvent.SAMPLE_PRESSURE]-absPressure.minValue)
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700403 / (float)absPressure.range);
404 }
405 if (absSize != null) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700406 reportData[j + MotionEvent.SAMPLE_SIZE] =
407 ((reportData[j + MotionEvent.SAMPLE_SIZE]-absSize.minValue)
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700408 / (float)absSize.range);
409 }
410
411 switch (orientation) {
412 case Surface.ROTATION_90: {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700413 final float temp = reportData[MotionEvent.SAMPLE_X];
414 reportData[j + MotionEvent.SAMPLE_X] = reportData[j + MotionEvent.SAMPLE_Y];
415 reportData[j + MotionEvent.SAMPLE_Y] = w-temp;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700416 break;
417 }
418 case Surface.ROTATION_180: {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700419 reportData[j + MotionEvent.SAMPLE_X] = w-reportData[j + MotionEvent.SAMPLE_X];
420 reportData[j + MotionEvent.SAMPLE_Y] = h-reportData[j + MotionEvent.SAMPLE_Y];
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700421 break;
422 }
423 case Surface.ROTATION_270: {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700424 final float temp = reportData[i + MotionEvent.SAMPLE_X];
425 reportData[j + MotionEvent.SAMPLE_X] = h-reportData[j + MotionEvent.SAMPLE_Y];
426 reportData[j + MotionEvent.SAMPLE_Y] = temp;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700427 break;
428 }
429 }
430 }
431
432 // We only consider the first pointer when computing the edge
433 // flags, since they are global to the event.
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700434 if (action == MotionEvent.ACTION_DOWN) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700435 if (reportData[MotionEvent.SAMPLE_X] <= 0) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700436 edgeFlags |= MotionEvent.EDGE_LEFT;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700437 } else if (reportData[MotionEvent.SAMPLE_X] >= dispW) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700438 edgeFlags |= MotionEvent.EDGE_RIGHT;
439 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700440 if (reportData[MotionEvent.SAMPLE_Y] <= 0) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700441 edgeFlags |= MotionEvent.EDGE_TOP;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700442 } else if (reportData[MotionEvent.SAMPLE_Y] >= dispH) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700443 edgeFlags |= MotionEvent.EDGE_BOTTOM;
444 }
445 }
446
447 if (currentMove != null) {
448 if (false) Log.i("InputDevice", "Adding batch x="
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700449 + reportData[MotionEvent.SAMPLE_X]
450 + " y=" + reportData[MotionEvent.SAMPLE_Y]
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700451 + " to " + currentMove);
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700452 currentMove.addBatch(curTime, reportData, metaState);
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700453 if (WindowManagerPolicy.WATCH_POINTER) {
454 Log.i("KeyInputQueue", "Updating: " + currentMove);
455 }
456 return null;
457 }
458
459 MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700460 curTimeNano, action, numPointers, mPointerIds, reportData,
461 metaState, xPrecision, yPrecision, device.id, edgeFlags);
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700462 if (action == MotionEvent.ACTION_MOVE) {
463 currentMove = me;
464 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700465
466 if (nextNumPointers < lastNumPointers) {
467 removeOldPointer(upOrDownPointer);
468 }
469
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700470 return me;
471 }
472
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700473 boolean hasMore() {
474 return mLastNumPointers != mNextNumPointers;
475 }
476
477 void finish() {
478 mNextNumPointers = mAddingPointerOffset = 0;
479 mNextData[MotionEvent.SAMPLE_PRESSURE] = 0;
480 }
481
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700482 MotionEvent generateRelMotion(InputDevice device, long curTime,
483 long curTimeNano, int orientation, int metaState) {
484
485 final float[] scaled = mReportData;
486
487 // For now we only support 1 pointer with relative motions.
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700488 scaled[MotionEvent.SAMPLE_X] = mNextData[MotionEvent.SAMPLE_X];
489 scaled[MotionEvent.SAMPLE_Y] = mNextData[MotionEvent.SAMPLE_Y];
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700490 scaled[MotionEvent.SAMPLE_PRESSURE] = 1.0f;
491 scaled[MotionEvent.SAMPLE_SIZE] = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492 int edgeFlags = 0;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700493
494 int action;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700495 if (mNextNumPointers != mLastNumPointers) {
496 mNextData[MotionEvent.SAMPLE_X] =
497 mNextData[MotionEvent.SAMPLE_Y] = 0;
498 if (mNextNumPointers > 0 && mLastNumPointers == 0) {
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700499 action = MotionEvent.ACTION_DOWN;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700500 mDownTime = curTime;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700501 } else if (mNextNumPointers == 0) {
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700502 action = MotionEvent.ACTION_UP;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700503 } else {
504 action = MotionEvent.ACTION_MOVE;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700505 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700506 mLastNumPointers = mNextNumPointers;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700507 currentMove = null;
508 } else {
509 action = MotionEvent.ACTION_MOVE;
510 }
511
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700512 scaled[MotionEvent.SAMPLE_X] *= xMoveScale;
513 scaled[MotionEvent.SAMPLE_Y] *= yMoveScale;
514 switch (orientation) {
515 case Surface.ROTATION_90: {
516 final float temp = scaled[MotionEvent.SAMPLE_X];
517 scaled[MotionEvent.SAMPLE_X] = scaled[MotionEvent.SAMPLE_Y];
518 scaled[MotionEvent.SAMPLE_Y] = -temp;
519 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 }
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700521 case Surface.ROTATION_180: {
522 scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_X];
523 scaled[MotionEvent.SAMPLE_Y] = -scaled[MotionEvent.SAMPLE_Y];
524 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800525 }
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700526 case Surface.ROTATION_270: {
527 final float temp = scaled[MotionEvent.SAMPLE_X];
528 scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_Y];
529 scaled[MotionEvent.SAMPLE_Y] = temp;
530 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 }
532 }
533
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700534 if (currentMove != null) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700535 if (false) Log.i("InputDevice", "Adding batch x="
536 + scaled[MotionEvent.SAMPLE_X]
537 + " y=" + scaled[MotionEvent.SAMPLE_Y]
538 + " to " + currentMove);
539 currentMove.addBatch(curTime, scaled, metaState);
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700540 if (WindowManagerPolicy.WATCH_POINTER) {
541 Log.i("KeyInputQueue", "Updating: " + currentMove);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 }
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700543 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 }
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700545
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700546 MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700547 curTimeNano, action, 1, mPointerIds, scaled, metaState,
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700548 xPrecision, yPrecision, device.id, edgeFlags);
549 if (action == MotionEvent.ACTION_MOVE) {
550 currentMove = me;
551 }
552 return me;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 }
554 }
555
556 static class AbsoluteInfo {
557 int minValue;
558 int maxValue;
559 int range;
560 int flat;
561 int fuzz;
562 };
563
564 InputDevice(int _id, int _classes, String _name,
565 AbsoluteInfo _absX, AbsoluteInfo _absY,
566 AbsoluteInfo _absPressure, AbsoluteInfo _absSize) {
567 id = _id;
568 classes = _classes;
569 name = _name;
570 absX = _absX;
571 absY = _absY;
572 absPressure = _absPressure;
573 absSize = _absSize;
574 }
575};