am 97808b86: Merge "better scrolling in JS-less single-message conversation view" into jb-ub-mail-ur9

* commit '97808b864982d9b1bf81ba7e56162d73bc2357ea':
  better scrolling in JS-less single-message conversation view
diff --git a/res/layout/secure_conversation_view.xml b/res/layout/secure_conversation_view.xml
index da1dae3..26b4920 100644
--- a/res/layout/secure_conversation_view.xml
+++ b/res/layout/secure_conversation_view.xml
@@ -18,7 +18,7 @@
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
-    <ScrollView android:id="@+id/scroll_view"
+    <com.android.mail.browse.MessageScrollView android:id="@+id/scroll_view"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
         <LinearLayout
@@ -37,18 +37,18 @@
                 android:layout_height="wrap_content"
                 android:layout_below="@id/conv_header" />
             <!-- base WebView layer -->
-            <WebView
+            <com.android.mail.browse.MessageWebView
                 android:id="@+id/webview"
                 android:layout_width="match_parent"
                 android:layout_height="0dp"
-                android:layout_weight="1.0"/>
+                android:layout_weight="1.0" />
             <include layout="@layout/conversation_message_footer"
                 android:id="@+id/message_footer"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:visibility="gone" />
         </LinearLayout>
-    </ScrollView>
+    </com.android.mail.browse.MessageScrollView>
 
     <include layout="@layout/conversation_load_spinner"/>
 
diff --git a/src/com/android/mail/browse/MessageScrollView.java b/src/com/android/mail/browse/MessageScrollView.java
new file mode 100644
index 0000000..250fbd0
--- /dev/null
+++ b/src/com/android/mail/browse/MessageScrollView.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2013 Google Inc.
+ * Licensed to The Android Open Source Project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mail.browse;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.ScrollView;
+
+import com.android.mail.utils.LogUtils;
+
+/**
+ * A container that tries to play nice with an internally scrollable {@link Touchable} child view.
+ * The assumption is that the child view can scroll horizontally, but not vertically, so any
+ * touch events on that child view should ALSO be sent here so it can simultaneously vertically
+ * scroll (not the standard either/or behavior).
+ * <p>
+ * Touch events on any other child of this ScrollView are intercepted in the standard fashion.
+ */
+public class MessageScrollView extends ScrollView {
+
+    /**
+     * A View that reports whether onTouchEvent() was recently called.
+     */
+    public interface Touchable {
+        boolean wasTouched();
+        void clearTouched();
+    }
+
+    /**
+     * True when performing "special" interception.
+     */
+    private boolean mWantToIntercept;
+    /**
+     * Whether to perform the standard touch interception procedure. This is set to true when we
+     * want to intercept a touch stream from any child OTHER than {@link #mTouchableChild}.
+     */
+    private boolean mInterceptNormally;
+    /**
+     * The special child that we want to NOT intercept from in the normal way. Instead, this child
+     * will continue to receive the touch event stream (so it can handle the horizontal component)
+     * while this parent will additionally handle the events to perform vertical scrolling.
+     */
+    private Touchable mTouchableChild;
+
+    public static final String LOG_TAG = "MsgScroller";
+
+    public MessageScrollView(Context c) {
+        this(c, null);
+    }
+
+    public MessageScrollView(Context c, AttributeSet attrs) {
+        super(c, attrs);
+    }
+
+    public void setInnerScrollableView(Touchable child) {
+        mTouchableChild = child;
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (mInterceptNormally) {
+            LogUtils.d(LOG_TAG, "IN ScrollView.onIntercept, NOW stealing. ev=%s", ev);
+            return true;
+        } else if (mWantToIntercept) {
+            LogUtils.d(LOG_TAG, "IN ScrollView.onIntercept, already stealing. ev=%s", ev);
+            return false;
+        }
+
+        mWantToIntercept = super.onInterceptTouchEvent(ev);
+        LogUtils.d(LOG_TAG, "OUT ScrollView.onIntercept, steal=%s ev=%s", mWantToIntercept, ev);
+        return false;
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        final int action = ev.getActionMasked();
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                LogUtils.d(LOG_TAG, "IN ScrollView.dispatchTouch, clearing flags");
+                mWantToIntercept = false;
+                mInterceptNormally = false;
+                break;
+        }
+        if (mTouchableChild != null) {
+            mTouchableChild.clearTouched();
+        }
+        final boolean handled = super.dispatchTouchEvent(ev);
+        LogUtils.d(LOG_TAG, "OUT ScrollView.dispatchTouch, handled=%s ev=%s", handled, ev);
+
+        if (mWantToIntercept) {
+            final boolean touchedChild = (mTouchableChild != null && mTouchableChild.wasTouched());
+            if (touchedChild) {
+                // also give the event to this scroll view if the WebView got the event
+                // and didn't stop any parent interception
+                LogUtils.d(LOG_TAG, "IN extra ScrollView.onTouch, ev=%s", ev);
+                onTouchEvent(ev);
+            } else {
+                mInterceptNormally = true;
+                mWantToIntercept = false;
+            }
+        }
+
+        return handled;
+    }
+
+}
diff --git a/src/com/android/mail/browse/MessageWebView.java b/src/com/android/mail/browse/MessageWebView.java
new file mode 100644
index 0000000..253a16b
--- /dev/null
+++ b/src/com/android/mail/browse/MessageWebView.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2013 Google Inc.
+ * Licensed to The Android Open Source Project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mail.browse;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.webkit.WebView;
+
+import com.android.mail.utils.LogUtils;
+
+/**
+ * A WebView designed to live within a {@link MessageScrollView}.
+ */
+public class MessageWebView extends WebView implements MessageScrollView.Touchable {
+
+    private boolean mTouched;
+
+    public MessageWebView(Context c) {
+        this(c, null);
+    }
+
+    public MessageWebView(Context c, AttributeSet attrs) {
+        super(c, attrs);
+    }
+
+    @Override
+    public boolean wasTouched() {
+        return mTouched;
+    }
+
+    @Override
+    public void clearTouched() {
+        mTouched = false;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        mTouched = true;
+        final boolean handled = super.onTouchEvent(event);
+        LogUtils.d(MessageScrollView.LOG_TAG,"OUT WebView.onTouch, returning handled=%s ev=%s",
+                handled, event);
+        return handled;
+    }
+
+}
diff --git a/src/com/android/mail/ui/SecureConversationViewFragment.java b/src/com/android/mail/ui/SecureConversationViewFragment.java
index eebec55..12b7f00 100644
--- a/src/com/android/mail/ui/SecureConversationViewFragment.java
+++ b/src/com/android/mail/ui/SecureConversationViewFragment.java
@@ -39,6 +39,8 @@
 import com.android.mail.browse.MessageFooterView;
 import com.android.mail.browse.MessageHeaderView;
 import com.android.mail.browse.MessageHeaderView.MessageHeaderViewCallbacks;
+import com.android.mail.browse.MessageScrollView;
+import com.android.mail.browse.MessageWebView;
 import com.android.mail.providers.Account;
 import com.android.mail.providers.Conversation;
 import com.android.mail.providers.Message;
@@ -50,12 +52,12 @@
 public class SecureConversationViewFragment extends AbstractConversationViewFragment implements
         MessageHeaderViewCallbacks {
     private static final String LOG_TAG = LogTag.getLogTag();
-    private WebView mWebView;
+    private MessageWebView mWebView;
     private ConversationViewHeader mConversationHeaderView;
     private MessageHeaderView mMessageHeaderView;
     private MessageFooterView mMessageFooterView;
     private ConversationMessage mMessage;
-    private ScrollView mScrollView;
+    private MessageScrollView mScrollView;
 
     private final WebViewClient mWebViewClient = new AbstractConversationWebViewClient() {
         @Override
@@ -113,12 +115,12 @@
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
         View rootView = inflater.inflate(R.layout.secure_conversation_view, container, false);
-        mScrollView = (ScrollView) rootView.findViewById(R.id.scroll_view);
+        mScrollView = (MessageScrollView) rootView.findViewById(R.id.scroll_view);
         mConversationHeaderView = (ConversationViewHeader) rootView.findViewById(R.id.conv_header);
         mMessageHeaderView = (MessageHeaderView) rootView.findViewById(R.id.message_header);
         mMessageFooterView = (MessageFooterView) rootView.findViewById(R.id.message_footer);
         instantiateProgressIndicators(rootView);
-        mWebView = (WebView) rootView.findViewById(R.id.webview);
+        mWebView = (MessageWebView) rootView.findViewById(R.id.webview);
         mWebView.setWebViewClient(mWebViewClient);
         mWebView.setFocusable(false);
         final WebSettings settings = mWebView.getSettings();
@@ -130,6 +132,8 @@
         settings.setBuiltInZoomControls(true);
         settings.setDisplayZoomControls(false);
 
+        mScrollView.setInnerScrollableView(mWebView);
+
         return rootView;
     }