title: Awkward touch event propagation between views
body: <p>I have a <code>Gallery</code> full of <code>ImageView</code>s, and the <code>ImageView</code>s are pinch-zoomable and translatable. My goal is that once an <code>ImageView</code> can no longer translate to the left/right, the <code>Gallery</code> will scroll. So sometimes the <code>ImageView</code> needs to handle the touch event, sometimes the <code>Gallery</code> needs to handle the touch event. I have logic in my <code>ImageView</code>'s <code>onTouchEvent</code> method for when I want the hand-off to occur, but I'm getting unexpected results. I'll explain the problem after I show my code:</p>
  
  <pre><code>// PinchZoomImageView.java
  
  @Override
  public boolean onTouchEvent( MotionEvent event ) {
  
      Log.i( "PinchZoomImageView", "IM GETTING TOUCHED!" );
  
      if ( isPassThroughTouchEvent() ) {
          Log.i( "PinchZoomImageView", "IM RETURNING FALSE!" );
          return false;
      }
  
      getScaleDetector().onTouchEvent( event );
  
      switch (event.getAction() &amp; MotionEvent.ACTION_MASK) {
          case MotionEvent.ACTION_DOWN: {
              final float x = event.getX();
              final float y = event.getY();
  
              setLastTouchX( x );
              setLastTouchY( y );
              setActivePointerId( event.getPointerId( 0 ) );
  
              break;
          }
  
          case MotionEvent.ACTION_MOVE: {
              final int pointerIndex = event.findPointerIndex( getActivePointerId() );
              final float x = event.getX( pointerIndex );
              final float y = event.getY( pointerIndex );
  
              // Only move if the ScaleGestureDetector isn't processing a gesture.
              if ( !getScaleDetector().isInProgress() ) {
                  if ( isDetectMovementX() ) {
                      final float dx = x - getLastTouchX();
                      setPosX( getPosX() + dx );
                  }
  
                  if ( isDetectMovementY() ) {
                      final float dy = y - getLastTouchY();
                      setPosY( getPosY() + dy );
                  }
  
                  invalidate();
              }
  
              setLastTouchX( x );
              setLastTouchY( y );
  
              if ( isAtXBound() &amp;&amp; !isPassThroughTouchEvent() ) {
  
                  setPassThroughTouchEvent( true );
              }
  
              break;
          }
  
          case MotionEvent.ACTION_UP: {
              setActivePointerId( INVALID_POINTER_ID );
              break;
          }
  
          case MotionEvent.ACTION_CANCEL: {
              setActivePointerId( INVALID_POINTER_ID );
              break;
          }
  
          case MotionEvent.ACTION_POINTER_UP: {
              final int pointerIndex = ( event.getAction() &amp; MotionEvent.ACTION_POINTER_INDEX_MASK ) &gt;&gt; MotionEvent.ACTION_POINTER_INDEX_SHIFT;
              final int pointerId = event.getPointerId( pointerIndex );
              if ( pointerId == getActivePointerId() ) {
                  // This was our active pointer going up. Choose a new
                  // active pointer and adjust accordingly.
                  final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                  setLastTouchX( event.getX( newPointerIndex ) );
                  setLastTouchY( event.getY( newPointerIndex ) );
                  setActivePointerId( event.getPointerId( newPointerIndex ) );
              }
              break;
          }
      }
  
      return true;
  }
  </code></pre>
  
  <p>And here's my <code>Gallery</code>. I overwrote <code>onTouchEvent</code> just to show when it was receiving touch events.</p>
  
  <pre><code>// SwipeGallery.java
  
  @Override
  public boolean onTouchEvent( MotionEvent event ) {
  
      Log.i( "SwipeGallery", "IM GETTING TOUCHED!" );
      return super.onTouchEvent( event );
  }
  </code></pre>
  
  <p>So when I load up the activity, i attempt to swipe from right to left. The logic to pass-through the motion event is immediately triggered, but here's my log output.</p>
  
  <pre><code>08-02 10:04:47.097: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
  08-02 10:04:47.179: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
  08-02 10:04:47.179: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
  08-02 10:04:47.179: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
  08-02 10:04:47.230: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
  08-02 10:04:47.230: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
  08-02 10:04:47.230: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
  08-02 10:04:47.230: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
  08-02 10:04:47.245: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
  08-02 10:04:47.245: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
  08-02 10:04:47.261: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
  08-02 10:04:47.261: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
  08-02 10:04:47.277: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
  08-02 10:04:47.277: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
  08-02 10:04:47.296: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
  08-02 10:04:47.296: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
  08-02 10:04:47.312: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
  08-02 10:04:47.312: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
  08-02 10:04:47.327: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
  08-02 10:04:47.327: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
  08-02 10:04:47.343: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
  08-02 10:04:47.343: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
  08-02 10:04:47.360: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
  08-02 10:04:47.360: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
  ....etc.
  </code></pre>
  
  <p>The SECOND time I swipe right to left, I get this:</p>
  
  <pre><code>08-02 10:27:31.573: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
  08-02 10:27:31.573: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
  08-02 10:27:31.573: INFO/SwipeGallery(17189): IM GETTING TOUCHED!
  08-02 10:27:31.636: INFO/SwipeGallery(17189): IM GETTING TOUCHED!
  08-02 10:27:31.636: INFO/SwipeGallery(17189): IM GETTING TOUCHED!
  08-02 10:27:31.683: INFO/SwipeGallery(17189): IM GETTING TOUCHED!
  08-02 10:27:31.933: INFO/SwipeGallery(17189): IM GETTING TOUCHED!
  08-02 10:27:31.964: INFO/SwipeGallery(17189): IM GETTING TOUCHED!
  08-02 10:27:31.999: INFO/SwipeGallery(17189): IM GETTING TOUCHED!
  08-02 10:27:32.034: INFO/SwipeGallery(17189): IM GETTING TOUCHED!
  </code></pre>
  
  <p>This pattern of "1st motion event the imageview always handles, 2nd motion event the gallery always handles" continues on forever (A new imageview gets made for each position in the gallery which is why <code>isPassThroughTouchEvent()</code> returns false the 3rd, 5th, etc time). So what exactly am I missing here? I thought returning false would propagate the touch event until it was handled, but the <code>Gallery</code> won't take it the first time, but it does the second? This makes no sense to me. Anyone have any ideas? Thanks.</p>