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