001: /*
002: * $RCSfile: SensorEventAgent.java,v $
003: *
004: * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * - Redistribution of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * - Redistribution in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * Neither the name of Sun Microsystems, Inc. or the names of
019: * contributors may be used to endorse or promote products derived
020: * from this software without specific prior written permission.
021: *
022: * This software is provided "AS IS," without a warranty of any
023: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
024: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
025: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
026: * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
027: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
028: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
029: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
030: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
031: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
032: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
033: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
034: * POSSIBILITY OF SUCH DAMAGES.
035: *
036: * You acknowledge that this software is not designed, licensed or
037: * intended for use in the design, construction, operation or
038: * maintenance of any nuclear facility.
039: *
040: * $Revision: 1.4 $
041: * $Date: 2007/02/09 17:20:15 $
042: * $State: Exp $
043: */
044:
045: package com.sun.j3d.utils.behaviors.sensor;
046:
047: import java.util.Iterator;
048: import java.util.List;
049: import java.util.ArrayList;
050: import javax.media.j3d.Sensor;
051: import javax.media.j3d.Transform3D;
052: import com.sun.j3d.utils.timer.J3DTimer;
053:
054: /**
055: * This class works in conjunction with the <code>SensorButtonListener</code>
056: * and <code>SensorReadListener</code> interfaces to support an event-driven
057: * model of sensor interaction. Java 3D defines sensors as delivering
058: * continuous input data which must be polled to retrieve their values, but in
059: * practice it is often convenient to structure application code to respond to
060: * events such as button state transitions.
061: * <p>
062: * Listeners registered with this class are invoked when its
063: * <code>dispatchEvents</code> method is called. This is usually called from
064: * the <code>processStimulus</code> method of a <code>Behavior</code>, but may
065: * also be called directly from the <code>pollAndProcessInput</code> method of
066: * an event-driven implementation of <code>InputDevice</code>. In either case
067: * the device is still polled by the Java 3D input device scheduling thread to
068: * get its current values; however, in the former, <code>dispatchEvents</code>
069: * is called from the behavior scheduler thread regardless of whether any new
070: * events are available, while in the latter, the <code>InputDevice</code>
071: * implementation may choose to call <code>dispatchEvents</code> only if new
072: * events are actually generated.
073: * <p>
074: * Button events are generated by changes in sensor button state, from pressed
075: * to released and vice versa. Button state changes are examined with each
076: * invocation of the <code>dispatchEvents</code> method. Events are
077: * distributed to interested parties through the button listener interface
078: * using the <code>pressed</code> and <code>released</code> callbacks.
079: * <p>
080: * The <code>dragged</code> method is not necessarily called in response to a
081: * motion event generated by a sensor. <code>dispatchEvents</code> will call
082: * <code>dragged</code> whenever any button assigned to the listener is down
083: * and has not changed state since the last time it was called. If
084: * <code>dispatchEvents</code> is called in the <code>processStimulus</code>
085: * of a <code>Behavior</code>, then <code>dragged</code> may be called even if
086: * the sensor value has not changed. This is as a consequence of the core
087: * Java 3D API definition of sensors as continuous devices.
088: * <p>
089: * Like <code>dragged</code>, the <code>read</code> method of
090: * <code>SensorReadListener</code> is not necessarily invoked in response to a
091: * real event. It is called by <code>dispatchEvents</code> whenever a button
092: * listener has not been called for that sensor. This usually means that no
093: * buttons are down, but clients are free to leave a button listener null, or
094: * to explicitly bind a null button listener to a button so that button's
095: * events are ignored. The sensor value has not necessarily changed since the
096: * last <code>read</code> callback.
097: * <p>
098: * A <i>mutual exclusion</i> policy can be applied between button
099: * listeners when they are grouped in an array mapped to the sensor's
100: * buttons. If multiple sensor buttons are held down at the same time,
101: * then a listener in the array is invoked only for the button that was
102: * depressed first. The <code>read</code> callback is separated from the
103: * <code>pressed</code>, <code>released</code>, and <code>dragged</code>
104: * callbacks in a separate interface in order to support this policy.
105: * <p>
106: * The events passed to the listeners are <i>ephemeral</i>; they are only
107: * valid until the listener has returned. This is done to avoid
108: * allocating large numbers of mostly temporary objects, especially for
109: * behaviors that wake up every frame. If a listener needs to retain the
110: * event it must be copied using the <code>SensorEvent(SensorEvent)</code>
111: * constructor.
112: * <p>
113: * It is safe to add and remove listeners in response to a callback.
114: *
115: * @see SensorEvent
116: * @see SensorButtonListener
117: * @see SensorReadListener
118: * @since Java 3D 1.3
119: */
120: public class SensorEventAgent {
121: private long t0 = 0;
122: private Object source = null;
123: private SensorEvent e = new SensorEvent();
124:
125: // List of SensorBinding objects and corresponding array.
126: private List bindingsList = new ArrayList();
127: private SensorBinding[] bindings = new SensorBinding[0];
128:
129: // Indicates that lists must be converted to arrays. Need to do this
130: // to allow listeners to add and remove themselves or other listeners
131: // safely during event dispatch.
132: private boolean listsDirty = false;
133:
134: /**
135: * Create a <code>SensorEventAgent</code> to generate and dispatch
136: * sensor events to registered listeners.
137: *
138: * @param source reference to the originating object for inclusion in
139: * generated <code>SensorEvents</code>; intended to refer to the
140: * instantiating Behavior but may be any reference, or null
141: */
142: public SensorEventAgent(Object source) {
143: this .source = source;
144: }
145:
146: /**
147: * This class contains all the button and read listeners registered
148: * with a sensor.
149: */
150: private static class SensorBinding {
151: Sensor sensor = null;
152: int[] buttons = null;
153: Transform3D read = null;
154:
155: // List of SensorButtonBinding objects and corresponding array.
156: List buttonBindingsList = new ArrayList();
157: SensorButtonBinding[] buttonBindings = new SensorButtonBinding[0];
158:
159: // List of SensorReadListener objects and corresponding array.
160: List readBindingsList = new ArrayList();
161: SensorReadListener[] readBindings = new SensorReadListener[0];
162:
163: SensorBinding(Sensor sensor) {
164: this .sensor = sensor;
165: buttons = new int[sensor.getSensorButtonCount()];
166: read = new Transform3D();
167: }
168:
169: void updateArrays() {
170: buttonBindings = (SensorButtonBinding[]) buttonBindingsList
171: .toArray(new SensorButtonBinding[buttonBindingsList
172: .size()]);
173: readBindings = (SensorReadListener[]) readBindingsList
174: .toArray(new SensorReadListener[readBindingsList
175: .size()]);
176: }
177:
178: public String toString() {
179: String s = new String();
180: s = "sensor " + sensor + "\nbutton listener arrays:\n";
181: for (int i = 0; i < buttonBindingsList.size(); i++)
182: s = s
183: + ((SensorButtonBinding) buttonBindingsList
184: .get(i));
185: s = s + "read listeners:\n";
186: for (int i = 0; i < readBindingsList.size(); i++)
187: s = s
188: + " "
189: + ((SensorReadListener) readBindingsList.get(i))
190: + "\n";
191: return s;
192: }
193: }
194:
195: /**
196: * This class contains an array of SensorButtonListener
197: * implementations, one for each sensor button. This array is used to
198: * support a mutual exclusion callback policy. There may be multiple
199: * instances of this class associated with a single sensor.
200: */
201: private static class SensorButtonBinding {
202: int buttonsHandled = 0;
203: boolean[] prevButtons = null;
204: boolean multiButton = false;
205: SensorButtonListener[] listeners = null;
206:
207: SensorButtonBinding(SensorButtonListener[] listeners,
208: boolean multiButtonEnable) {
209:
210: prevButtons = new boolean[listeners.length];
211: this .listeners = new SensorButtonListener[listeners.length];
212:
213: for (int i = 0; i < listeners.length; i++) {
214: prevButtons[i] = false;
215: this .listeners[i] = listeners[i];
216: }
217:
218: this .multiButton = multiButtonEnable;
219: }
220:
221: public String toString() {
222: String s = new String();
223: s = " length " + listeners.length + ", mutual exclusion "
224: + (!multiButton) + "\n";
225: for (int i = 0; i < listeners.length; i++)
226: s = s
227: + " "
228: + (listeners[i] == null ? "null" : listeners[i]
229: .toString()) + "\n";
230: return s;
231: }
232: }
233:
234: /**
235: * Look up the sensor listeners bound to the given sensor.
236: */
237: private SensorBinding getSensorBinding(Sensor sensor) {
238: for (int i = 0; i < bindingsList.size(); i++) {
239: SensorBinding sb = (SensorBinding) bindingsList.get(i);
240: if (sb.sensor == sensor)
241: return sb;
242: }
243: return null;
244: }
245:
246: /**
247: * Creates a binding of the specified sensor button to the given
248: * <code>SensorButtonListener</code> implementation.
249: *
250: * @param sensor the sensor with the button to be bound
251: * @param button the index of the button to be bound on the specified
252: * sensor; may range from 0 to
253: * <code>(sensor.getSensorButtonCount() - 1)</code>
254: * @param buttonListener the <code>SensorButtonListener</code>
255: * implementation that will be invoked for the sensor's button
256: */
257: public synchronized void addSensorButtonListener(Sensor sensor,
258: int button, SensorButtonListener buttonListener) {
259:
260: if (sensor == null)
261: throw new NullPointerException("\nsensor is null");
262:
263: if (button >= sensor.getSensorButtonCount())
264: throw new ArrayIndexOutOfBoundsException("\nbutton "
265: + button + " >= sensor button count "
266: + sensor.getSensorButtonCount());
267:
268: SensorBinding sb = getSensorBinding(sensor);
269: if (sb == null) {
270: sb = new SensorBinding(sensor);
271: bindingsList.add(sb);
272: }
273:
274: SensorButtonListener[] listeners = new SensorButtonListener[sb.buttons.length];
275:
276: // Assign only the specified button; others remain null.
277: listeners[button] = buttonListener;
278: SensorButtonBinding sbb = new SensorButtonBinding(listeners,
279: true);
280:
281: sb.buttonBindingsList.add(sbb);
282: listsDirty = true;
283: }
284:
285: /**
286: * Creates a binding from all the buttons on the specified sensor to
287: * the given <code>SensorButtonListener</code> implementation. If
288: * multiple sensor buttons are held down at the same time, the press
289: * and release callbacks are called for each button in the order that
290: * they occur. This allows actions to be bound to combinations of
291: * button presses, but is also convenient for listeners that don't
292: * care which button was pressed.
293: *
294: * @param sensor the sensor to be bound
295: * @param buttonListener the <code>SensorButtonListener</code>
296: * implementation that will be called for all button events
297: */
298: public synchronized void addSensorButtonListener(Sensor sensor,
299: SensorButtonListener buttonListener) {
300:
301: if (sensor == null)
302: throw new NullPointerException("\nsensor is null");
303:
304: SensorBinding sb = getSensorBinding(sensor);
305: if (sb == null) {
306: sb = new SensorBinding(sensor);
307: bindingsList.add(sb);
308: }
309:
310: SensorButtonListener[] listeners = new SensorButtonListener[sb.buttons.length];
311:
312: // All buttons are bound to the same listener.
313: for (int i = 0; i < sb.buttons.length; i++)
314: listeners[i] = buttonListener;
315:
316: SensorButtonBinding sbb = new SensorButtonBinding(listeners,
317: true);
318:
319: sb.buttonBindingsList.add(sbb);
320: listsDirty = true;
321: }
322:
323: /**
324: * Creates a binding of the specified sensor to the given array of
325: * <code>SensorButtonListener</code> implementations. The array index
326: * of the listener indicates the index of the sensor button to which
327: * it will be bound.
328: * <p>
329: * This method enforces a <i>mutually exclusive</i> callback policy
330: * among the listeners specified in the array. If multiple sensor
331: * buttons are held down at the same time, callbacks are invoked only
332: * for the button that was depressed first.
333: *
334: * @param sensor the sensor to be bound
335: * @param buttonListeners array of implementations of
336: * <code>SensorButtonListener</code>; array entries may be null or
337: * duplicates but the array length must equal the sensor's button
338: * count
339: */
340: public synchronized void addSensorButtonListeners(Sensor sensor,
341: SensorButtonListener[] buttonListeners) {
342:
343: if (sensor == null)
344: throw new NullPointerException("\nsensor is null");
345:
346: SensorBinding sb = getSensorBinding(sensor);
347: if (sb == null) {
348: sb = new SensorBinding(sensor);
349: bindingsList.add(sb);
350: }
351:
352: if (sb.buttons.length != buttonListeners.length)
353: throw new IllegalArgumentException(
354: "\nbuttonListeners length "
355: + buttonListeners.length
356: + " must equal sensor button count "
357: + sb.buttons.length);
358:
359: SensorButtonBinding sbb = new SensorButtonBinding(
360: buttonListeners, false);
361:
362: sb.buttonBindingsList.add(sbb);
363: listsDirty = true;
364: }
365:
366: /**
367: * Gets the <code>SensorButtonListener</code> implementations bound to
368: * the given sensor and button.
369: *
370: * @param sensor the sensor of interest
371: * @param button the button of interest
372: * @return array of <code>SensorButtonListener</code> implementations
373: * bound to the given sensor and button, or null
374: */
375: public SensorButtonListener[] getSensorButtonListeners(
376: Sensor sensor, int button) {
377: if (sensor == null)
378: throw new NullPointerException("\nsensor is null");
379:
380: if (button >= sensor.getSensorButtonCount())
381: throw new ArrayIndexOutOfBoundsException("\nbutton "
382: + button + " >= sensor button count "
383: + sensor.getSensorButtonCount());
384:
385: SensorBinding sb = getSensorBinding(sensor);
386: if (sb == null)
387: return null;
388:
389: ArrayList listeners = new ArrayList();
390: for (int i = 0; i < sb.buttonBindingsList.size(); i++) {
391: SensorButtonBinding sbb = (SensorButtonBinding) sb.buttonBindingsList
392: .get(i);
393:
394: if (sbb.listeners[button] != null)
395: listeners.add(sbb.listeners[button]);
396: }
397:
398: if (listeners.size() == 0)
399: return null;
400: else
401: return (SensorButtonListener[]) listeners
402: .toArray(new SensorButtonListener[listeners.size()]);
403: }
404:
405: /**
406: * Remove the SensorButtonListener from the given SensorBinding.
407: */
408: private void removeSensorButtonListener(SensorBinding sb,
409: SensorButtonListener listener) {
410:
411: Iterator i = sb.buttonBindingsList.iterator();
412: while (i.hasNext()) {
413: int instanceCount = 0;
414: SensorButtonBinding sbb = (SensorButtonBinding) i.next();
415:
416: for (int j = 0; j < sbb.listeners.length; j++) {
417: if (sbb.listeners[j] == listener)
418: sbb.listeners[j] = null;
419: else if (sbb.listeners[j] != null)
420: instanceCount++;
421: }
422: if (instanceCount == 0) {
423: i.remove();
424: }
425: }
426: listsDirty = true;
427: }
428:
429: /**
430: * Remove the given <code>SensorButtonListener</code> binding from the
431: * specified sensor.
432: *
433: * @param sensor the sensor from which to remove the listener
434: * @param listener the listener to be removed
435: */
436: public synchronized void removeSensorButtonListener(Sensor sensor,
437: SensorButtonListener listener) {
438:
439: if (sensor == null)
440: throw new NullPointerException("\nsensor is null");
441:
442: SensorBinding sb = getSensorBinding(sensor);
443: if (sb == null)
444: return;
445:
446: removeSensorButtonListener(sb, listener);
447: if (sb.buttonBindingsList.size() == 0
448: && sb.readBindingsList.size() == 0)
449: removeSensorBinding(sensor);
450:
451: listsDirty = true;
452: }
453:
454: /**
455: * Remove the given <code>SensorButtonListener</code> from all sensors.
456: *
457: * @param listener the listener to remove
458: */
459: public synchronized void removeSensorButtonListener(
460: SensorButtonListener listener) {
461:
462: Iterator i = bindingsList.iterator();
463: while (i.hasNext()) {
464: SensorBinding sb = (SensorBinding) i.next();
465: removeSensorButtonListener(sb, listener);
466:
467: if (sb.buttonBindingsList.size() == 0
468: && sb.readBindingsList.size() == 0) {
469: i.remove();
470: }
471: }
472: listsDirty = true;
473: }
474:
475: /**
476: * Creates a binding of the specified sensor to the given
477: * <code>SensorReadListener</code>. The read listener is invoked
478: * every time <code>dispatchEvents</code> is called and a button
479: * listener is <i>not</i> invoked.
480: *
481: * @param sensor the sensor to be bound
482: * @param readListener the <code>SensorReadListener</code>
483: * implementation
484: */
485: public synchronized void addSensorReadListener(Sensor sensor,
486: SensorReadListener readListener) {
487:
488: if (sensor == null)
489: throw new NullPointerException("\nsensor is null");
490:
491: SensorBinding sb = getSensorBinding(sensor);
492: if (sb == null) {
493: sb = new SensorBinding(sensor);
494: bindingsList.add(sb);
495: }
496: sb.readBindingsList.add(readListener);
497: listsDirty = true;
498: }
499:
500: /**
501: * Gets the <code>SensorReadListeners</code> bound to the specified
502: * sensor.
503: *
504: * @param sensor the sensor of interest
505: * @return array of <code>SensorReadListeners</code> bound to the
506: * given sensor, or null
507: */
508: public SensorReadListener[] getSensorReadListeners(Sensor sensor) {
509: if (sensor == null)
510: throw new NullPointerException("\nsensor is null");
511:
512: SensorBinding sb = getSensorBinding(sensor);
513: if (sb == null)
514: return null;
515: else if (sb.readBindingsList.size() == 0)
516: return null;
517: else
518: return (SensorReadListener[]) sb.readBindingsList
519: .toArray(new SensorReadListener[sb.readBindingsList
520: .size()]);
521: }
522:
523: /**
524: * Remove the SensorReadListener from the given SensorBinding.
525: */
526: private void removeSensorReadListener(SensorBinding sb,
527: SensorReadListener listener) {
528:
529: Iterator i = sb.readBindingsList.iterator();
530: while (i.hasNext()) {
531: if (((SensorReadListener) i.next()) == listener)
532: i.remove();
533: }
534: listsDirty = true;
535: }
536:
537: /**
538: * Remove the given <code>SensorReadListener</code> binding from the
539: * specified sensor.
540: *
541: * @param sensor the sensor from which to remove the listener
542: * @param listener the listener to be removed
543: */
544: public synchronized void removeSensorReadListener(Sensor sensor,
545: SensorReadListener listener) {
546:
547: if (sensor == null)
548: throw new NullPointerException("\nsensor is null");
549:
550: SensorBinding sb = getSensorBinding(sensor);
551: if (sb == null)
552: return;
553:
554: removeSensorReadListener(sb, listener);
555: if (sb.buttonBindingsList.size() == 0
556: && sb.readBindingsList.size() == 0)
557: removeSensorBinding(sensor);
558:
559: listsDirty = true;
560: }
561:
562: /**
563: * Remove the given <code>SensorReadListener</code> from all sensors.
564: *
565: * @param listener the listener to remove
566: */
567: public synchronized void removeSensorReadListener(
568: SensorReadListener listener) {
569:
570: Iterator i = bindingsList.iterator();
571: while (i.hasNext()) {
572: SensorBinding sb = (SensorBinding) i.next();
573: removeSensorReadListener(sb, listener);
574:
575: if (sb.buttonBindingsList.size() == 0
576: && sb.readBindingsList.size() == 0) {
577: i.remove();
578: }
579: }
580: listsDirty = true;
581: }
582:
583: /**
584: * Remove all sensor listeners bound to the given sensor.
585: */
586: public synchronized void removeSensorBinding(Sensor sensor) {
587: Iterator i = bindingsList.iterator();
588: while (i.hasNext()) {
589: SensorBinding sb = (SensorBinding) i.next();
590: if (sb.sensor == sensor) {
591: i.remove();
592: break;
593: }
594: }
595: listsDirty = true;
596: }
597:
598: /**
599: * Returns an array of references to all sensors that have been bound
600: * to listeners.
601: * @return an array of sensors, or null if no sensors have been bound
602: */
603: public Sensor[] getSensors() {
604: if (bindingsList.size() == 0)
605: return null;
606:
607: Sensor[] s = new Sensor[bindingsList.size()];
608: for (int i = 0; i < bindingsList.size(); i++)
609: s[i] = ((SensorBinding) bindingsList.get(i)).sensor;
610:
611: return s;
612: }
613:
614: /**
615: * Copies binding lists to arrays for event dispatch. This allows
616: * listeners to add or remove themselves or other listeners safely.
617: */
618: private synchronized void updateArrays() {
619: bindings = (SensorBinding[]) bindingsList
620: .toArray(new SensorBinding[bindingsList.size()]);
621:
622: for (int i = 0; i < bindings.length; i++) {
623: bindings[i].updateArrays();
624: }
625: }
626:
627: /**
628: * Reads all sensor button state and dispatches events to registered
629: * button and read listeners. This method is intended to be called from
630: * the <code>processStimulus</code> implementation of a
631: * <code>Behavior</code> or the <code>pollAndProcessInput</code> method of
632: * an event-driven implementation of <code>InputDevice</code>.
633: */
634: public void dispatchEvents() {
635: long t1 = t0;
636: t0 = J3DTimer.getValue();
637:
638: if (listsDirty) {
639: updateArrays();
640: listsDirty = false;
641: }
642:
643: // Loop through all sensor bindings.
644: for (int k = 0; k < bindings.length; k++) {
645: SensorBinding sb = bindings[k];
646: Sensor s = sb.sensor;
647: Transform3D read = sb.read;
648: int[] buttons = sb.buttons;
649: int dragButton = 0;
650: boolean callReadListeners = true;
651: boolean callDraggedListener = false;
652:
653: // Get this sensor's readings.
654: s.getRead(read);
655: s.lastButtons(buttons);
656:
657: // Dispatch button listeners.
658: for (int j = 0; j < sb.buttonBindings.length; j++) {
659: SensorButtonBinding sbb = sb.buttonBindings[j];
660: for (int i = 0; i < buttons.length; i++) {
661: if (sbb.listeners[i] == null)
662: continue;
663:
664: // Check for button release.
665: if (sbb.prevButtons[i]) {
666: if (buttons[i] == 0) {
667: e.set(source, SensorEvent.RELEASED, s,
668: read, buttons, i, t0, t1);
669: sbb.listeners[i].released(e);
670: sbb.prevButtons[i] = false;
671: sbb.buttonsHandled--;
672: } else {
673: callDraggedListener = true;
674: dragButton = i;
675: }
676: callReadListeners = false;
677: }
678: // Check for button press.
679: // Ignore multiple button presses if not enabled;
680: // otherwise, one listener is bound to all buttons.
681: else if (buttons[i] == 1) {
682: if (sbb.buttonsHandled == 0 || sbb.multiButton) {
683: e.set(source, SensorEvent.PRESSED, s, read,
684: buttons, i, t0, t1);
685: sbb.listeners[i].pressed(e);
686: sbb.prevButtons[i] = true;
687: sbb.buttonsHandled++;
688: callReadListeners = false;
689: }
690: }
691: }
692: if (callDraggedListener) {
693: // One drag event even if multiple buttons down.
694: // Called after all pressed() and released() calls.
695: e.set(source, SensorEvent.DRAGGED, s, read,
696: buttons, SensorEvent.NOBUTTON, t0, t1);
697: sbb.listeners[dragButton].dragged(e);
698: }
699: }
700: // Dispatch read listeners.
701: if (callReadListeners) {
702: e.set(source, SensorEvent.READ, s, read, buttons,
703: SensorEvent.NOBUTTON, t0, t1);
704: for (int r = 0; r < sb.readBindings.length; r++) {
705: sb.readBindings[r].read(e);
706: }
707: }
708: }
709: }
710:
711: public String toString() {
712: String s = "SensorEventAgent@"
713: + Integer.toHexString(hashCode());
714: s += "\nsensor bindings:\n\n";
715: for (int i = 0; i < bindingsList.size(); i++) {
716: s += ((SensorBinding) bindingsList.get(i)).toString()
717: + "\n";
718: }
719: return s;
720: }
721: }
|