Working around overscroll issues in AllApps.

- For the time being, we are going to do custom drawing to ensure that we get the touch
  events in the right order, while still allowing the recycler view to draw the overscroll
  effect on top of the prediction bar.

Bug: 21335369
Change-Id: I6bf64e5c1e9aa634a953223a5decf74942e4fb57
diff --git a/res/layout/all_apps_container.xml b/res/layout/all_apps_container.xml
index 0b624e6..0221a56 100644
--- a/res/layout/all_apps_container.xml
+++ b/res/layout/all_apps_container.xml
@@ -27,6 +27,7 @@
     <!-- DO NOT CHANGE THE ID -->
     <com.android.launcher3.allapps.AllAppsRecyclerView
         android:id="@+id/apps_list_view"
+        android:theme="@style/Theme.Light.CustomOverscroll"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_gravity="center_horizontal|top"
diff --git a/res/layout/widgets_view.xml b/res/layout/widgets_view.xml
index 161c268..755634f 100644
--- a/res/layout/widgets_view.xml
+++ b/res/layout/widgets_view.xml
@@ -40,6 +40,7 @@
         <!-- DO NOT CHANGE THE ID -->
         <com.android.launcher3.widget.WidgetsRecyclerView
             android:id="@+id/widgets_list_view"
+            android:theme="@style/Theme.Dark.CustomOverscroll"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:layout_gravity="center"
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 1496da9..7d60cbe 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -18,6 +18,13 @@
 -->
 
 <resources>
+    <style name="Theme.Light.CustomOverscroll" parent="@android:style/Theme.DeviceDefault">
+        <item name="android:colorEdgeEffect">@color/folder_edge_effect_color</item>
+    </style>
+
+    <style name="Theme.Dark.CustomOverscroll" parent="@android:style/Theme.DeviceDefault">
+        <item name="android:colorEdgeEffect">@color/workspace_edge_effect_color</item>
+    </style>
 
     <style name="Icon">
         <item name="android:layout_width">match_parent</item>
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index a17f0e3..c83c6cf 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -16,10 +16,12 @@
 package com.android.launcher3.allapps;
 
 import android.content.Context;
+import android.graphics.Canvas;
 import android.os.Bundle;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.util.AttributeSet;
+import android.view.ContextThemeWrapper;
 import android.view.View;
 import com.android.launcher3.BaseRecyclerView;
 import com.android.launcher3.BaseRecyclerViewFastScrollBar;
@@ -70,8 +72,9 @@
     public AllAppsRecyclerView(Context context, AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr);
-        mLauncher = (Launcher) context;
-        setOverScrollMode(View.OVER_SCROLL_NEVER);
+        // We have a theme on this view, so we need to coerce the base activity context from that
+        ContextThemeWrapper ctx = (ContextThemeWrapper) context;
+        mLauncher = (Launcher) ctx.getBaseContext();
     }
 
     /**
@@ -125,6 +128,18 @@
         return 0;
     }
 
+    /**
+     * We need to override the draw to ensure that we don't draw the overscroll effect beyond the
+     * background bounds.
+     */
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        canvas.clipRect(mBackgroundPadding.left, mBackgroundPadding.top,
+                getWidth() - mBackgroundPadding.right,
+                getHeight() - mBackgroundPadding.bottom);
+        super.dispatchDraw(canvas);
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerViewContainerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerViewContainerView.java
index 8a8afde..1c51ab7 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerViewContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerViewContainerView.java
@@ -17,7 +17,9 @@
 
 import android.content.Context;
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
 import android.util.AttributeSet;
+import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import com.android.launcher3.BubbleTextView;
@@ -25,6 +27,7 @@
 import com.android.launcher3.ClickShadowView;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
 
 /**
  * A container for RecyclerView to allow for the click shadow view to be shown behind an icon that
@@ -34,6 +37,7 @@
         implements BubbleTextShadowHandler {
 
     private final ClickShadowView mTouchFeedbackView;
+    private View mPredictionBarView;
 
     public AllAppsRecyclerViewContainerView(Context context) {
         this(context, null);
@@ -57,6 +61,13 @@
     }
 
     @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        mPredictionBarView = findViewById(R.id.prediction_bar);
+    }
+
+    @Override
     public void setPressedIcon(BubbleTextView icon, Bitmap background) {
         if (icon == null || background == null) {
             mTouchFeedbackView.setBitmap(null);
@@ -66,4 +77,33 @@
             mTouchFeedbackView.animateShadow();
         }
     }
+
+    /**
+     * This allows us to have custom drawing order, while keeping touch handling in correct z-order.
+     */
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        final long drawingTime = getDrawingTime();
+
+        // Draw the click feedback first (since it is always on the bottom)
+        if (mTouchFeedbackView != null && mTouchFeedbackView.getVisibility() == View.VISIBLE) {
+            drawChild(canvas, mTouchFeedbackView, drawingTime);
+        }
+
+        // Then draw the prediction bar, since it needs to be "under" the recycler view to get the
+        // right edge effect to be drawn over it
+        if (mPredictionBarView != null && mPredictionBarView.getVisibility() == View.VISIBLE) {
+            drawChild(canvas, mPredictionBarView, drawingTime);
+        }
+
+        // Draw the remaining views
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View v = getChildAt(i);
+            if (v != mTouchFeedbackView && v != mPredictionBarView &&
+                    v.getVisibility() == View.VISIBLE) {
+                drawChild(canvas, v, drawingTime);
+            }
+        }
+    }
 }
diff --git a/src/com/android/launcher3/widget/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
index 3101f33..61e63cd 100644
--- a/src/com/android/launcher3/widget/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
@@ -17,6 +17,7 @@
 package com.android.launcher3.widget;
 
 import android.content.Context;
+import android.graphics.Canvas;
 import android.graphics.Color;
 import android.support.v7.widget.LinearLayoutManager;
 import android.util.AttributeSet;
@@ -73,6 +74,18 @@
     public void setWidgets(WidgetsModel widgets) {
         mWidgets = widgets;
     }
+    
+    /**
+     * We need to override the draw to ensure that we don't draw the overscroll effect beyond the
+     * background bounds.
+     */
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        canvas.clipRect(mBackgroundPadding.left, mBackgroundPadding.top,
+                getWidth() - mBackgroundPadding.right,
+                getHeight() - mBackgroundPadding.bottom);
+        super.dispatchDraw(canvas);
+    }
 
     /**
      * Maps the touch (from 0..1) to the adapter position that should be visible.