• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
wasTouched()41         boolean wasTouched();
clearTouched()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 
MessageScrollView(Context c)63     public MessageScrollView(Context c) {
64         this(c, null);
65     }
66 
MessageScrollView(Context c, AttributeSet attrs)67     public MessageScrollView(Context c, AttributeSet attrs) {
68         super(c, attrs);
69     }
70 
setInnerScrollableView(Touchable child)71     public void setInnerScrollableView(Touchable child) {
72         mTouchableChild = child;
73     }
74 
75     @Override
onInterceptTouchEvent(MotionEvent ev)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
dispatchTouchEvent(MotionEvent ev)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