Revision: 9989
Author:   [email protected]
Date:     Wed Apr 13 11:00:31 2011
Log:      Cherry picking r9988 into releases/2.3.

http://code.google.com/p/google-web-toolkit/source/detail?r=9989

Modified:
 /releases/2.3/user/src/com/google/gwt/touch/client/TouchScroller.java
 /releases/2.3/user/test/com/google/gwt/touch/client/TouchScrollTest.java

=======================================
--- /releases/2.3/user/src/com/google/gwt/touch/client/TouchScroller.java Tue Mar 22 11:44:40 2011 +++ /releases/2.3/user/src/com/google/gwt/touch/client/TouchScroller.java Wed Apr 13 11:00:31 2011
@@ -30,11 +30,14 @@
 import com.google.gwt.event.dom.client.TouchMoveHandler;
 import com.google.gwt.event.dom.client.TouchStartEvent;
 import com.google.gwt.event.dom.client.TouchStartHandler;
+import com.google.gwt.event.logical.shared.ResizeEvent;
+import com.google.gwt.event.logical.shared.ResizeHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwt.touch.client.Momentum.State;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.Event.NativePreviewEvent;
 import com.google.gwt.user.client.Event.NativePreviewHandler;
+import com.google.gwt.user.client.Window;
 import com.google.gwt.user.client.ui.HasScrolling;

 import java.util.ArrayList;
@@ -99,6 +102,7 @@
     private final Point initialPosition = getWidgetScrollPosition();
     private int lastElapsedMillis = 0;
     private State state;
+    private HandlerRegistration windowResizeHandler;

     /**
      * Construct a {@link MomentumCommand}.
@@ -107,6 +111,18 @@
      */
     public MomentumCommand(Point endVelocity) {
       state = momentum.createState(initialPosition, endVelocity);
+
+      /**
+ * If the user resizes the window (which happens on orientation change of + * a mobile device), cancel the momentum. The scrollable widget may be + * resized, which will cause its content to reflow and invalidates the
+       * current scrolling position.
+       */
+      windowResizeHandler = Window.addResizeHandler(new ResizeHandler() {
+        public void onResize(ResizeEvent event) {
+          finish();
+        }
+      });
     }

     public boolean execute() {
@@ -115,6 +131,7 @@
        * disabled.
        */
       if (this != momentumCommand) {
+        finish();
         return false;
       }

@@ -127,9 +144,9 @@
       // Calculate the new state.
       boolean notDone = momentum.updateState(state);

-      // Momementum is finished, so the user is free to click.
+      // Momentum is finished, so the user is free to click.
       if (!notDone) {
-        setBustNextClick(false);
+        finish();
       }

       /*
@@ -139,6 +156,20 @@
       setWidgetScrollPosition(state.getPosition());
       return notDone;
     }
+
+    /**
+     * Finish and cleanup this momentum command.
+     */
+    private void finish() {
+      if (windowResizeHandler != null) {
+        windowResizeHandler.removeHandler();
+        windowResizeHandler = null;
+      }
+      if (this == momentumCommand) {
+        momentumCommand = null;
+        setBustNextClick(false);
+      }
+    }
   }

   /**
@@ -493,9 +524,6 @@
     if (!touching) {
       return;
     }
-
-    // Prevent native scrolling.
-    event.preventDefault();

     // Check if we should start dragging.
     Touch touch = getTouchFromEvent(event);
@@ -507,11 +535,60 @@
       double absDiffX = Math.abs(diff.getX());
       double absDiffY = Math.abs(diff.getY());
if (absDiffX > MIN_TRACKING_FOR_DRAG || absDiffY > MIN_TRACKING_FOR_DRAG) {
+        /*
+         * Check if we should defer to native scrolling. If the scrollable
+ * widget is already scrolled as far as it will go, then we don't want
+         * to prevent scrolling of the document.
+         *
+         * We cannot prevent native scrolling in only one direction (ie. we
+ * cannot allow native horizontal scrolling but prevent native vertical + * scrolling), so we make a best guess based on the direction of the
+         * drag.
+         */
+        if (absDiffX > absDiffY) {
+          /*
+ * The user scrolled primarily in the horizontal direction, so check
+           * if we should defer left/right scrolling to the document.
+           */
+          int hPosition = widget.getHorizontalScrollPosition();
+          int hMin = widget.getMinimumHorizontalScrollPosition();
+          int hMax = widget.getMaximumHorizontalScrollPosition();
+          if (diff.getX() < 0 && hMax <= hPosition) {
+            // Already scrolled to the right.
+            cancelAll();
+            return;
+          } else if (diff.getX() > 0 && hMin >= hPosition) {
+            // Already scrolled to the left.
+            cancelAll();
+            return;
+          }
+        } else {
+          /*
+ * The user scrolled primarily in the vertical direction, so check if
+           * we should defer up/down scrolling to the document.
+           */
+          int vPosition = widget.getVerticalScrollPosition();
+          int vMin = widget.getMinimumVerticalScrollPosition();
+          int vMax = widget.getMaximumVerticalScrollPosition();
+          if (diff.getY() < 0 && vMax <= vPosition) {
+            // Already scrolled to the bottom.
+            cancelAll();
+            return;
+          } else if (diff.getY() > 0 && vMin >= vPosition) {
+            // Already scrolled to the top.
+            cancelAll();
+            return;
+          }
+        }
+
         // Start dragging.
         dragging = true;
         onDragStart(event);
       }
     }
+
+    // Prevent native document level scrolling.
+    event.preventDefault();

     if (dragging) {
       // Continue dragging.
@@ -648,8 +725,6 @@

   /**
    * Get the scroll position of the widget.
-   *
-   * @param position the current scroll position
    */
   private Point getWidgetScrollPosition() {
return new Point(widget.getHorizontalScrollPosition(), widget.getVerticalScrollPosition());
@@ -669,7 +744,7 @@
             event.getNativeEvent().preventDefault();
             setBustNextClick(false);
           }
-        };
+        }
       });
     } else if (!doBust && bustClickHandler != null) {
       bustClickHandler.removeHandler();
=======================================
--- /releases/2.3/user/test/com/google/gwt/touch/client/TouchScrollTest.java Tue Mar 22 11:44:40 2011 +++ /releases/2.3/user/test/com/google/gwt/touch/client/TouchScrollTest.java Wed Apr 13 11:00:31 2011
@@ -16,6 +16,7 @@
 package com.google.gwt.touch.client;

 import com.google.gwt.core.client.Duration;
+import com.google.gwt.core.client.Scheduler.RepeatingCommand;
 import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.dom.client.Touch;
 import com.google.gwt.event.dom.client.TouchEvent;
@@ -56,9 +57,9 @@
      */
     public CustomScrollPanel() {
       this.minVerticalScrollPosition = 0;
-      this.maxVerticalScrollPosition = Integer.MAX_VALUE;
+      this.maxVerticalScrollPosition = 5000;
       this.minHorizontalScrollPosition = 0;
-      this.maxHorizontalScrollPosition = Integer.MAX_VALUE;
+      this.maxHorizontalScrollPosition = 5000;
     }

     @Override
@@ -206,7 +207,7 @@
     CustomTouchEvent event = new CustomTouchEvent();
     event.setNativeEvent(createNativeTouchEvent());
     return event;
-  };
+  }

   /**
    * Create a mock TouchMoveEvent for the specified x and y coordinate.
@@ -218,7 +219,7 @@
   private static TouchEvent<?> createTouchMoveEvent(int x, int y) {
     // TouchScroller doesn't care about the actual event subclass.
     return createTouchStartEvent(x, y);
-  };
+  }

   /**
* Create a mock {@link TouchStartEvent} for the specified x and y coordinate.
@@ -233,7 +234,7 @@
     nativeEvent.getTouches().push(createTouch(x, y));
     event.setNativeEvent(nativeEvent);
     return event;
-  };
+  }

   private CustomTouchScroller scroller;
   private CustomScrollPanel scrollPanel;
@@ -276,6 +277,22 @@
assertNull("TouchScroll created, but touch is not supported", scroller);
     }
   }
+
+  public void testDeferToNativeScrollingBottom() {
+ testDeferToNativeScrolling(0, scrollPanel.getMaximumVerticalScrollPosition(), 0, -100);
+  }
+
+  public void testDeferToNativeScrollingLeft() {
+    testDeferToNativeScrolling(0, 0, 100, 0);
+  }
+
+  public void testDeferToNativeScrollingRight() {
+ testDeferToNativeScrolling(scrollPanel.getMaximumHorizontalScrollPosition(), 0, -100, 0);
+  }
+
+  public void testDeferToNativeScrollingTop() {
+    testDeferToNativeScrolling(0, 0, 0, 100);
+  }

   /**
    * Test that touch events correctly initiate drag events.
@@ -295,21 +312,21 @@
     assertFalse(scroller.isDragging());

     // Move, but not enough to drag.
-    scroller.onTouchMove(createTouchMoveEvent(1, 0));
+    scroller.onTouchMove(createTouchMoveEvent(-1, 0));
     scroller.assertOnDragStartCalled(false);
     scroller.assertOnDragMoveCalled(false);
     assertTrue(scroller.isTouching());
     assertFalse(scroller.isDragging());

     // Move.
-    scroller.onTouchMove(createTouchMoveEvent(100, 0));
+    scroller.onTouchMove(createTouchMoveEvent(-100, 0));
     scroller.assertOnDragStartCalled(true);
     scroller.assertOnDragMoveCalled(true);
     assertTrue(scroller.isTouching());
     assertTrue(scroller.isDragging());

     // Move again.
-    scroller.onTouchMove(createTouchMoveEvent(200, 0));
+    scroller.onTouchMove(createTouchMoveEvent(-200, 0));
     scroller.assertOnDragStartCalled(false); // drag already started.
     scroller.assertOnDragMoveCalled(true);
     assertTrue(scroller.isTouching());
@@ -323,6 +340,39 @@
     assertFalse(scroller.isTouching());
     assertFalse(scroller.isDragging());
   }
+
+  /**
+   * Test that when momentum ends, the momentum command is set to null (and
+   * isMomentumActive() returns false).
+   */
+  public void testMomentumEnd() {
+    // Use a short lived momentum.
+    scroller.setMomentum(new DefaultMomentum() {
+      @Override
+      public boolean updateState(State state) {
+        // Immediately end momentum.
+        return false;
+      }
+    });
+
+    // Start a drag sequence.
+    double millis = Duration.currentTimeMillis();
+ scroller.getRecentTouchPosition().setTemporalPoint(new Point(0, 0), millis); + scroller.getLastTouchPosition().setTemporalPoint(new Point(100, 100), millis + 100);
+
+    // End the drag sequence.
+    scroller.onDragEnd(createTouchEndEvent());
+    scroller.assertOnDragEndCalled(true);
+    assertFalse(scroller.isTouching());
+    assertFalse(scroller.isDragging());
+    assertTrue(scroller.isMomentumActive());
+
+    // Force momentum to run, which causes it to end.
+    getMomentumCommand(scroller).execute();
+    assertFalse(scroller.isTouching());
+    assertFalse(scroller.isDragging());
+    assertFalse(scroller.isMomentumActive());
+  }

   public void testOnDragEnd() {
     // Start a drag sequence.
@@ -486,12 +536,14 @@
   protected void gwtSetUp() throws Exception {
     // Create and attach a widget that has scrolling.
     scrollPanel = new CustomScrollPanel();
-    scrollPanel.setTouchScrollingDisabled(true);
     scrollPanel.setPixelSize(500, 500);
     Label content = new Label("Content");
     content.setPixelSize(10000, 10000);
     RootPanel.get().add(scrollPanel);

+    // Disabled touch scrolling because we will add our own scroller.
+    scrollPanel.setTouchScrollingDisabled(true);
+
     // Add scrolling support.
     scroller = new CustomTouchScroller(scrollPanel);
   }
@@ -511,4 +563,42 @@
     scrollPanel = null;
     scroller = null;
   }
-}
+
+  /**
+   * Get the momentum command from the specified {@link TouchScroller}.
+   */
+ private native RepeatingCommand getMomentumCommand(TouchScroller scroller) /*-{ + return [email protected]::momentumCommand;
+  }-*/;
+
+  /**
+   * Test that {@link TouchScroller} defers to native scrolling if the
+   * scrollable widget is already scrolled as far as it can go.
+   *
+   * @param hStart the starting horizontal scroll position
+   * @param vStart the starting vertical scroll position
+   * @param xEnd the ending x touch coordinate
+   * @param yEnd the ending y touch coordinate
+   */
+ private void testDeferToNativeScrolling(int hStart, int vStart, int xEnd, int yEnd) {
+    // Disable momentum for this test.
+    scroller.setMomentum(null);
+
+    // Scroll to the left.
+    scrollPanel.setHorizontalScrollPosition(hStart);
+    scrollPanel.setVerticalScrollPosition(vStart);
+
+    // Start touching.
+    scroller.onTouchStart(createTouchStartEvent(0, 0));
+    scroller.assertOnDragStartCalled(false);
+    assertTrue(scroller.isTouching());
+    assertFalse(scroller.isDragging());
+
+    // Move to the left.
+    scroller.onTouchMove(createTouchMoveEvent(xEnd, yEnd));
+    scroller.assertOnDragStartCalled(false);
+    scroller.assertOnDragMoveCalled(false);
+    assertFalse(scroller.isTouching());
+    assertFalse(scroller.isDragging());
+  }
+}

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to