Bug 796886 - Tapping anywhere in main layout should close tabs panel on phones (r=mfinkle)
authorLucas Rocha <lucasr@mozilla.com>
Sat, 13 Oct 2012 00:23:20 +0100
changeset 110255 4e3c9bd6bd60783bd927eb7214c99f7807c83750
parent 110254 bbcf489988a470c5b41dc207b7b6ad6c9db3bd4c
child 110256 d16548ef9acccf64c85c32195f76a3a3aa11ecf2
push id16427
push userlrocha@mozilla.com
push dateMon, 15 Oct 2012 10:48:55 +0000
treeherdermozilla-inbound@d16548ef9acc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle
bugs796886
milestone19.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 796886 - Tapping anywhere in main layout should close tabs panel on phones (r=mfinkle)
mobile/android/base/AboutHomeContent.java.in
mobile/android/base/BrowserApp.java
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoViewsFactory.java
mobile/android/base/resources/layout-xlarge-v11/gecko_app.xml.in
mobile/android/base/resources/layout/gecko_app.xml.in
--- a/mobile/android/base/AboutHomeContent.java.in
+++ b/mobile/android/base/AboutHomeContent.java.in
@@ -89,17 +89,16 @@ public class AboutHomeContent extends Sc
 
     private AboutHomePromoBox mPromoBox;
     private AboutHomePromoBox.Type mPrelimPromoBoxType;
     protected AboutHomeSection mAddons;
     protected AboutHomeSection mLastTabs;
     protected AboutHomeSection mRemoteTabs;
 
     private View.OnClickListener mRemoteTabClickListener;
-    private OnInterceptTouchListener mOnInterceptTouchListener;
 
     public interface UriLoadCallback {
         public void callback(String uriSpec);
     }
 
     public interface VoidCallback {
         public void callback();
     }
@@ -342,34 +341,16 @@ public class AboutHomeContent extends Sc
             mTopSitesAdapter.notifyDataSetChanged();
 
         removeAllViews(); // We must remove the currently inflated view to allow for reinflation.
         inflate();
         mTopSitesGrid.setAdapter(mTopSitesAdapter); // mTopSitesGrid is a new instance (from loadTopSites()).
         update(AboutHomeContent.UpdateFlags.ALL); // Refresh all elements.
     }
 
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent event) {
-        if (mOnInterceptTouchListener != null && mOnInterceptTouchListener.onInterceptTouchEvent(this, event))
-            return true;
-        return super.onInterceptTouchEvent(event);
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        if (mOnInterceptTouchListener != null && mOnInterceptTouchListener.onTouch(this, event))
-            return true;
-        return super.onTouchEvent(event);
-    }
-
-    public void setOnInterceptTouchListener(OnInterceptTouchListener listener) {
-        mOnInterceptTouchListener = listener;
-    }
-
     private String readFromZipFile(String filename) {
         ZipFile zip = null;
         String str = null;
         try {
             InputStream fileStream = null;
             File applicationPackage = new File(mActivity.getApplication().getPackageResourcePath());
             zip = new ZipFile(applicationPackage);
             if (zip == null)
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -19,24 +19,26 @@ import android.app.AlertDialog;
 import android.content.DialogInterface;
 import android.content.SharedPreferences;
 import android.content.Intent;
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.Interpolator;
 import android.widget.LinearLayout;
 import android.widget.Toast;
 
 import dalvik.system.DexClassLoader;
 
@@ -203,16 +205,18 @@ abstract public class BrowserApp extends
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         LinearLayout actionBar = (LinearLayout) getActionBarLayout();
         mMainLayout.addView(actionBar, 0);
 
+        ((GeckoApp.MainLayout) mMainLayout).setOnInterceptTouchListener(new HideTabsTouchListener());
+
         mBrowserToolbar = new BrowserToolbar(this);
         mBrowserToolbar.from(actionBar);
 
         if (mTabsPanel != null)
             mTabsPanel.setTabsLayoutChangeListener(this);
 
         mFindInPageBar = (FindInPageBar) findViewById(R.id.find_in_page);
 
@@ -670,28 +674,72 @@ abstract public class BrowserApp extends
                             Tabs.getInstance().loadUrl(url);
                         }
                     });
                     mAboutHomeContent.setLoadCompleteCallback(new AboutHomeContent.VoidCallback() {
                          public void callback() {
                              mAboutHomeStartupTimer.stop();
                          }
                     });
-                    mAboutHomeContent.setOnInterceptTouchListener(new ContentTouchListener());
                 } else {
                     mAboutHomeContent.update(EnumSet.of(AboutHomeContent.UpdateFlags.TOP_SITES,
                                                         AboutHomeContent.UpdateFlags.REMOTE_TABS));
                 }
                 mAboutHomeContent.setVisibility(View.VISIBLE);
             } else {
                 findViewById(R.id.abouthome_content).setVisibility(View.GONE);
             }
         } 
     }
 
+    private class HideTabsTouchListener implements OnInterceptTouchListener {
+        private boolean mIsHidingTabs = false;
+
+        @Override
+        public boolean onInterceptTouchEvent(View view, MotionEvent event) {
+            // We need to account for scroll state for the touched view otherwise
+            // tapping on an "empty" part of the view will still be considered a
+            // valid touch event.
+            if (view.getScrollX() != 0 || view.getScrollY() != 0) {
+                Rect rect = new Rect();
+                view.getHitRect(rect);
+                rect.offset(-view.getScrollX(), -view.getScrollY());
+
+                int[] viewCoords = new int[2];
+                view.getLocationOnScreen(viewCoords);
+
+                int x = (int) event.getRawX() - viewCoords[0];
+                int y = (int) event.getRawY() - viewCoords[1];
+
+                if (!rect.contains(x, y))
+                    return false;
+            }
+
+            // If the tab tray is showing, hide the tab tray and don't send the event to content.
+            if (event.getActionMasked() == MotionEvent.ACTION_DOWN && autoHideTabs()) {
+                mIsHidingTabs = true;
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public boolean onTouch(View view, MotionEvent event) {
+            if (mIsHidingTabs) {
+                // Keep consuming events until the gesture finishes.
+                int action = event.getActionMasked();
+                if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+                    mIsHidingTabs = false;
+                }
+                return true;
+            }
+            return false;
+        }
+    }
+
     private void addAddonMenuItem(final int id, final String label, final String icon) {
         if (mMenu == null) {
             if (mAddonMenuItemsCache == null)
                 mAddonMenuItemsCache = new Vector<MenuItemInfo>();
 
             mAddonMenuItemsCache.add(new MenuItemInfo(id, label, icon));
             return;
         }
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -2534,27 +2534,29 @@ abstract public class GeckoApp
 
     public void notifyCheckUpdateResult(boolean result) {
         GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Update:CheckResult", result ? "true" : "false"));
     }
 
     protected void connectGeckoLayerClient() {
         mLayerView.getLayerClient().notifyGeckoReady();
 
-        mLayerView.getTouchEventHandler().setOnTouchListener(new ContentTouchListener() {
+        mLayerView.getTouchEventHandler().setOnTouchListener(new OnInterceptTouchListener() {
             private PointF initialPoint = null;
 
             @Override
+            public boolean onInterceptTouchEvent(View view, MotionEvent event) {
+                return false;
+            }
+
+            @Override
             public boolean onTouch(View view, MotionEvent event) {
                 if (event == null)
                     return true;
 
-                if (super.onTouch(view, event))
-                    return true;
-
                 int action = event.getAction();
                 PointF point = new PointF(event.getX(), event.getY());
                 if ((action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
                     initialPoint = point;
                 }
 
                 if (initialPoint != null && (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_MOVE) {
                     if (PointUtils.subtract(point, initialPoint).length() < PanZoomController.PAN_THRESHOLD) {
@@ -2567,40 +2569,40 @@ abstract public class GeckoApp
                 }
 
                 GeckoAppShell.sendEventToGecko(GeckoEvent.createMotionEvent(event));
                 return true;
             }
         });
     }
 
-    protected class ContentTouchListener implements OnInterceptTouchListener {
-        private boolean mIsHidingTabs = false;
-
-        @Override
-        public boolean onInterceptTouchEvent(View view, MotionEvent event) {
-            // If the tab tray is showing, hide the tab tray and don't send the event to content.
-            if (event.getActionMasked() == MotionEvent.ACTION_DOWN && autoHideTabs()) {
-                mIsHidingTabs = true;
-                return true;
-            }
-            return false;
+    public static class MainLayout extends LinearLayout {
+        private OnInterceptTouchListener mOnInterceptTouchListener;
+
+        public MainLayout(Context context, AttributeSet attrs) {
+            super(context, attrs);
+            mOnInterceptTouchListener = null;
+        }
+
+        public void setOnInterceptTouchListener(OnInterceptTouchListener listener) {
+            mOnInterceptTouchListener = listener;
         }
 
         @Override
-        public boolean onTouch(View view, MotionEvent event) {
-            if (mIsHidingTabs) {
-                // Keep consuming events until the gesture finishes.
-                int action = event.getActionMasked();
-                if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
-                    mIsHidingTabs = false;
-                }
+        public boolean onInterceptTouchEvent(MotionEvent event) {
+            if (mOnInterceptTouchListener != null && mOnInterceptTouchListener.onInterceptTouchEvent(this, event))
                 return true;
-            }
-            return false;
+            return super.onInterceptTouchEvent(event);
+        }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent event) {
+            if (mOnInterceptTouchListener != null && mOnInterceptTouchListener.onTouch(this, event))
+                return true;
+            return super.onTouchEvent(event);
         }
     }
 
     public boolean linkerExtract() {
         return false;
     }
 
     private class FullScreenHolder extends FrameLayout {
--- a/mobile/android/base/GeckoViewsFactory.java
+++ b/mobile/android/base/GeckoViewsFactory.java
@@ -47,16 +47,18 @@ public final class GeckoViewsFactory imp
             else if (TextUtils.equals(viewName, "AboutHomeSection"))
                 return new AboutHomeSection(context, attrs);
             else if (TextUtils.equals(viewName, "AwesomeBarTabs"))
                 return new AwesomeBarTabs(context, attrs);
             else if (TextUtils.equals(viewName, "BrowserToolbarBackground"))
                 return new BrowserToolbarBackground(context, attrs);
             else if (TextUtils.equals(viewName, "FormAssistPopup"))
                 return new FormAssistPopup(context, attrs);
+            else if (TextUtils.equals(viewName, "GeckoApp$MainLayout"))
+                return new GeckoApp.MainLayout(context, attrs);
             else if (TextUtils.equals(viewName, "LinkTextView"))
                 return new LinkTextView(context, attrs);
             else if (TextUtils.equals(viewName, "FindInPageBar"))
                 return new FindInPageBar(context, attrs);
             else if (TextUtils.equals(viewName, "MenuButton"))
                 return new MenuButton(context, attrs);
             else if (TextUtils.equals(viewName, "TabsButton"))
                 return new TabsButton(context, attrs);
--- a/mobile/android/base/resources/layout-xlarge-v11/gecko_app.xml.in
+++ b/mobile/android/base/resources/layout-xlarge-v11/gecko_app.xml.in
@@ -10,18 +10,19 @@
                 android:layout_height="fill_parent">
 
    <org.mozilla.gecko.TabsPanel android:id="@+id/tabs_panel"
                                 android:layout_width="200dip"
                                 android:layout_height="fill_parent"
                                 android:background="@drawable/tabs_tray_bg_repeat"
                                 gecko:sidebar="true"/>
 
-   <LinearLayout android:id="@+id/main_layout"
-                 style="@style/Screen.Transparent">
+   <view class="org.mozilla.gecko.GeckoApp$MainLayout"
+         android:id="@+id/main_layout"
+         style="@style/Screen.Transparent">
  
         <!-- BrowserToolbar will be added dynamically -->
         
         <RelativeLayout android:id="@+id/gecko_layout"
                         android:layout_width="fill_parent"
                         android:layout_height="fill_parent"
                         android:layout_weight="1">
 
@@ -36,11 +37,11 @@
 
         <org.mozilla.gecko.FindInPageBar android:id="@+id/find_in_page"
                                          android:layout_width="fill_parent"
                                          android:layout_height="wrap_content"
                                          android:layout_gravity="bottom"
                                          style="@style/FindBar"
                                          android:visibility="gone"/>
 
-    </LinearLayout>
+    </view>
 
 </RelativeLayout>
--- a/mobile/android/base/resources/layout/gecko_app.xml.in
+++ b/mobile/android/base/resources/layout/gecko_app.xml.in
@@ -10,18 +10,19 @@
                 android:layout_height="fill_parent">
 
    <org.mozilla.gecko.TabsPanel android:id="@+id/tabs_panel"
                                 android:layout_width="fill_parent"
                                 android:layout_height="fill_parent"
                                 android:background="@drawable/tabs_tray_bg_repeat"
                                 gecko:sidebar="false"/>
 
-   <LinearLayout android:id="@+id/main_layout"
-                 style="@style/Screen.Transparent">
+   <view class="org.mozilla.gecko.GeckoApp$MainLayout"
+         android:id="@+id/main_layout"
+         style="@style/Screen.Transparent">
  
         <!-- BrowserToolbar will be added dynamically -->
 
         <RelativeLayout android:id="@+id/gecko_layout"
                         android:layout_width="fill_parent"
                         android:layout_height="fill_parent"
                         android:layout_weight="1">
 
@@ -36,11 +37,11 @@
 
         <org.mozilla.gecko.FindInPageBar android:id="@+id/find_in_page"
                                          android:layout_width="fill_parent"
                                          android:layout_height="wrap_content"
                                          android:layout_gravity="bottom"
                                          style="@style/FindBar"
                                          android:visibility="gone"/>
 
-    </LinearLayout>
+    </view>
 
 </RelativeLayout>