Home | History | Annotate | Download | only in browse
      1 /*
      2  * Copyright (C) 2013 Google Inc.
      3  * Licensed to The Android Open Source Project.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 package com.android.mail.browse;
     19 
     20 import android.content.Context;
     21 import android.util.AttributeSet;
     22 import android.view.MotionEvent;
     23 import android.widget.ScrollView;
     24 
     25 import com.android.mail.utils.LogUtils;
     26 
     27 /**
     28  * A container that tries to play nice with an internally scrollable {@link Touchable} child view.
     29  * The assumption is that the child view can scroll horizontally, but not vertically, so any
     30  * touch events on that child view should ALSO be sent here so it can simultaneously vertically
     31  * scroll (not the standard either/or behavior).
     32  * <p>
     33  * Touch events on any other child of this ScrollView are intercepted in the standard fashion.
     34  */
     35 public class MessageScrollView extends ScrollView {
     36 
     37     /**
     38      * A View that reports whether onTouchEvent() was recently called.
     39      */
     40     public interface Touchable {
     41         boolean wasTouched();
     42         void clearTouched();
     43     }
     44 
     45     /**
     46      * True when performing "special" interception.
     47      */
     48     private boolean mWantToIntercept;
     49     /**
     50      * Whether to perform the standard touch interception procedure. This is set to true when we
     51      * want to intercept a touch stream from any child OTHER than {@link #mTouchableChild}.
     52      */
     53     private boolean mInterceptNormally;
     54     /**
     55      * The special child that we want to NOT intercept from in the normal way. Instead, this child
     56      * will continue to receive the touch event stream (so it can handle the horizontal component)
     57      * while this parent will additionally handle the events to perform vertical scrolling.
     58      */
     59     private Touchable mTouchableChild;
     60 
     61     public static final String LOG_TAG = "MsgScroller";
     62 
     63     public MessageScrollView(Context c) {
     64         this(c, null);
     65     }
     66 
     67     public MessageScrollView(Context c, AttributeSet attrs) {
     68         super(c, attrs);
     69     }
     70 
     71     public void setInnerScrollableView(Touchable child) {
     72         mTouchableChild = child;
     73     }
     74 
     75     @Override
     76     public boolean onInterceptTouchEvent(MotionEvent ev) {
     77         if (mInterceptNormally) {
     78             LogUtils.d(LOG_TAG, "IN ScrollView.onIntercept, NOW stealing. ev=%s", ev);
     79             return true;
     80         } else if (mWantToIntercept) {
     81             LogUtils.d(LOG_TAG, "IN ScrollView.onIntercept, already stealing. ev=%s", ev);
     82             return false;
     83         }
     84 
     85         mWantToIntercept = super.onInterceptTouchEvent(ev);
     86         LogUtils.d(LOG_TAG, "OUT ScrollView.onIntercept, steal=%s ev=%s", mWantToIntercept, ev);
     87         return false;
     88     }
     89 
     90     @Override
     91     public boolean dispatchTouchEvent(MotionEvent ev) {
     92         final int action = ev.getActionMasked();
     93         switch (action) {
     94             case MotionEvent.ACTION_DOWN:
     95                 LogUtils.d(LOG_TAG, "IN ScrollView.dispatchTouch, clearing flags");
     96                 mWantToIntercept = false;
     97                 mInterceptNormally = false;
     98                 break;
     99         }
    100         if (mTouchableChild != null) {
    101             mTouchableChild.clearTouched();
    102         }
    103         final boolean handled = super.dispatchTouchEvent(ev);
    104         LogUtils.d(LOG_TAG, "OUT ScrollView.dispatchTouch, handled=%s ev=%s", handled, ev);
    105 
    106         if (mWantToIntercept) {
    107             final boolean touchedChild = (mTouchableChild != null && mTouchableChild.wasTouched());
    108             if (touchedChild) {
    109                 // also give the event to this scroll view if the WebView got the event
    110                 // and didn't stop any parent interception
    111                 LogUtils.d(LOG_TAG, "IN extra ScrollView.onTouch, ev=%s", ev);
    112                 onTouchEvent(ev);
    113             } else {
    114                 mInterceptNormally = true;
    115                 mWantToIntercept = false;
    116             }
    117         }
    118 
    119         return handled;
    120     }
    121 
    122 }
    123