Merge "Making the security checks and policy changes only when launching custom shortcuts. This prevents launcher specific intents to unknowingly leak data." into ub-launcher3-calgary
diff --git a/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java b/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java
index a680169..fd0045e 100644
--- a/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java
+++ b/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java
@@ -27,7 +27,6 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.view.MotionEvent;
-import android.view.VelocityTracker;
 import android.view.ViewConfiguration;
 
 import com.android.launcher3.util.Thunk;
@@ -293,7 +292,7 @@
     /**
      * Returns whether the specified points are near the scroll bar bounds.
      */
-    private boolean isNearThumb(int x, int y) {
+    public boolean isNearThumb(int x, int y) {
         mTmpRect.set(mThumbOffset.x, mThumbOffset.y, mThumbOffset.x + mThumbWidth,
                 mThumbOffset.y + mThumbHeight);
         mTmpRect.inset(mTouchInset, mTouchInset);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index b981b55..85ba57c 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -45,6 +45,7 @@
 import android.os.Parcelable;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.Property;
 import android.util.SparseArray;
 import android.view.MotionEvent;
 import android.view.View;
@@ -1386,18 +1387,52 @@
         // TODO(adamcohen): figure out a final effect here. We may need to recommend
         // different effects based on device performance. On at least one relatively high-end
         // device I've tried, translating the launcher causes things to get quite laggy.
-        setTranslationAndAlpha(getPageIndicator(), transX, alpha);
-        setTranslationAndAlpha(getChildAt(getCurrentPage()), transX, alpha);
-        setTranslationAndAlpha(mLauncher.getHotseat(), transX, alpha);
+        setWorkspaceTranslation(TRANSLATION_X, transX, alpha);
+        setHotseatTranslation(TRANSLATION_X, transX, alpha);
+    }
+
+    /**
+     * Moves the workspace UI in the provided direction.
+     * @param direction either {@link #TRANSLATION_X} or {@link #TRANSLATION_Y}
+     * @param translation the amound of shift.
+     * @param alpha the alpha for the workspace page
+     */
+    public void setWorkspaceTranslation(
+            Property<View, Float> direction, float translation, float alpha) {
+        View currentChild = getChildAt(getCurrentPage());
+        if (currentChild != null) {
+            direction.set(currentChild, translation);
+            currentChild.setAlpha(alpha);
+        }
 
         // When the animation finishes, reset all pages, just in case we missed a page.
-        if (transX == 0) {
+        if (Float.compare(translation, 0) == 0) {
             for (int i = getChildCount() - 1; i >= 0; i--) {
-                setTranslationAndAlpha(getChildAt(i), 0, alpha);
+                View child = getChildAt(i);
+                direction.set(child, translation);
+                child.setAlpha(alpha);
             }
         }
     }
 
+    /**
+     * Moves the Hotseat UI in the provided direction.
+     * @param direction either {@link #TRANSLATION_X} or {@link #TRANSLATION_Y}
+     * @param translation the amound of shift.
+     * @param alpha the alpha for the hotseat page
+     */
+    public void setHotseatTranslation(
+            Property<View, Float> direction, float translation, float alpha) {
+        View pageIndicator = getPageIndicator();
+        if (pageIndicator != null) {
+            direction.set(pageIndicator, translation);
+            pageIndicator.setAlpha(alpha);
+        }
+
+        direction.set(mLauncher.getHotseat(), translation);
+        mLauncher.getHotseat().setAlpha(alpha);
+    }
+
     @Override
     protected Matrix getPageShiftMatrix() {
         if (Float.compare(mOverlayTranslation, 0) != 0) {
@@ -1410,13 +1445,6 @@
         return super.getPageShiftMatrix();
     }
 
-    private void setTranslationAndAlpha(View v, float transX, float alpha) {
-        if (v != null) {
-            v.setTranslationX(transX);
-            v.setAlpha(alpha);
-        }
-    }
-
     @Override
     protected void getEdgeVerticalPostion(int[] pos) {
         View child = getChildAt(getPageCount() - 1);
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 2c9f810..a74c4c5 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -257,9 +257,24 @@
         mAppsRecyclerView.scrollToTop();
     }
 
-    public boolean isScrollAtTop() {
-        return ((LinearLayoutManager) mAppsRecyclerView.getLayoutManager())
-                .findFirstVisibleItemPosition() == 1;
+    /**
+     * Returns whether the view itself will handle the touch event or not.
+     */
+    public boolean shouldContainerScroll(float x, float y) {
+        int[] point = new int[2];
+        point[0] = (int) x;
+        point[1] = (int) y;
+        Utilities.mapCoordInSelfToDescendent(mAppsRecyclerView, this, point);
+
+        // if the MotionEvent is inside the thumb, container should not be pulled down.
+        if (mAppsRecyclerView.getScrollBar().isNearThumb(point[0], point[1])){
+             return false;
+        }
+        // If scroller is at the very top, then it's okay for the container to be pulled down.
+        if (Float.compare(0f, mAppsRecyclerView.getScrollBar().getThumbOffset().y) == 0) {
+            return true;
+        }
+        return false;
     }
     /**
      * Focuses the search field and begins an app search.
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 53a517c..d70ee47 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -9,15 +9,14 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
 
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.Hotseat;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAnimUtils;
 import com.android.launcher3.PagedView;
+import com.android.launcher3.Workspace;
 import com.android.launcher3.util.TouchController;
 
 /**
@@ -38,13 +37,13 @@
      private final Interpolator mAccelInterpolator = new AccelerateInterpolator(1f);
 
     private static final float ANIMATION_DURATION = 2000;
-    private static final float FINAL_ALPHA = .6f;
+    private static final float FINAL_ALPHA = .65f;
 
     private AllAppsContainerView mAppsView;
+    private Workspace mWorkspace;
     private Hotseat mHotseat;
     private Drawable mHotseatBackground;
     private float mHotseatAlpha;
-    private View mWorkspaceCurPage;
 
     private final Launcher mLauncher;
     private final VerticalPullDetector mDetector;
@@ -59,6 +58,7 @@
     private float mCurY;
 
     private AnimatorSet mCurrentAnimation;
+    private boolean mNoIntercept;
 
     public AllAppsTransitionController(Launcher launcher) {
         mLauncher = launcher;
@@ -69,12 +69,20 @@
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         init();
-        if (mLauncher.getWorkspace().isInOverviewMode() ||
-                mLauncher.isWidgetsViewVisible()) {
-            return false;
-        }
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            mDetector.setAllAppsState(mLauncher.isAllAppsVisible(), mAppsView.isScrollAtTop());
+            mNoIntercept = false;
+            if (mLauncher.getWorkspace().isInOverviewMode() || mLauncher.isWidgetsViewVisible()) {
+                mNoIntercept = true;
+            }
+            if (mLauncher.isAllAppsVisible() &&
+                    !mAppsView.shouldContainerScroll(ev.getX(), ev.getY())) {
+                mNoIntercept = true;
+            }
+        }
+        if (mNoIntercept) {
+            return false;
+        } else {
+            mDetector.setScrollDirectionDown(mLauncher.isAllAppsVisible());
         }
         mDetector.onTouchEvent(ev);
         return mDetector.mScrolling;
@@ -91,6 +99,7 @@
         }
         mAppsView = mLauncher.getAppsView();
         mHotseat = mLauncher.getHotseat();
+        mWorkspace = mLauncher.getWorkspace();
 
         if (mHotseatBackground == null) {
             mHotseatBackground = mHotseat.getBackground();
@@ -110,9 +119,6 @@
      * @param start {@code true} if start of new drag.
      */
     public void preparePull(boolean start) {
-        // TODO: create a method inside workspace to fetch this easily.
-        mWorkspaceCurPage = mLauncher.getWorkspace().getChildAt(
-                mLauncher.getWorkspace().getNextPage());
         mHotseat.setVisibility(View.VISIBLE);
         mHotseat.bringToFront();
         if (start) {
@@ -130,10 +136,13 @@
                     setProgress(mTranslation);
                 }
             } else {
-                mLauncher.getWorkspace().onLauncherTransitionPrepare(mLauncher, false, false);
-                mWorkspaceCurPage.setVisibility(View.VISIBLE);
-                ((CellLayout) mWorkspaceCurPage).getShortcutsAndWidgets().setVisibility(View.VISIBLE);
-                ((CellLayout) mWorkspaceCurPage).getShortcutsAndWidgets().setAlpha(1f);
+                // TODO: get rid of this workaround to override state change by workspace transition
+                mWorkspace.onLauncherTransitionPrepare(mLauncher, false, false);
+                View child = ((CellLayout) mWorkspace.getChildAt(mWorkspace.getNextPage()))
+                        .getShortcutsAndWidgets();
+                child.setVisibility(View.VISIBLE);
+                child.setAlpha(1f);
+
                 mAppsView.setSearchBarVisible(false);
                 setLightStatusBar(false);
             }
@@ -175,8 +184,10 @@
         mAppsView.getRevealView().setAlpha(Math.min(FINAL_ALPHA, Math.max(mHotseatAlpha, alpha)));
         mAppsView.getContentView().setAlpha(alpha);
         mAppsView.setTranslationY(progress);
-        setTransAndAlpha(mWorkspaceCurPage, -mTranslation + progress, mAccelInterpolator.getInterpolation(workspaceHotseatAlpha));
-        setTransAndAlpha(mHotseat, -mTranslation + progress, workspaceHotseatAlpha);
+        mWorkspace.setWorkspaceTranslation(View.TRANSLATION_Y, -mTranslation + progress,
+                mAccelInterpolator.getInterpolation(workspaceHotseatAlpha));
+        mWorkspace.setHotseatTranslation(
+                View.TRANSLATION_Y, -mTranslation + progress, workspaceHotseatAlpha);
     }
 
     public float getProgress() {
@@ -187,13 +198,6 @@
         return ((mTranslation - progress)/mTranslation);
     }
 
-    private void setTransAndAlpha(View v, float transY, float alpha) {
-        if (v != null) {
-            v.setTranslationY(transY);
-            v.setAlpha(alpha);
-        }
-    }
-
     @Override
     public void onScrollEnd(float velocity, boolean fling) {
         if (mAppsView == null) {
diff --git a/src/com/android/launcher3/allapps/VerticalPullDetector.java b/src/com/android/launcher3/allapps/VerticalPullDetector.java
index 12d414e..0c3698d 100644
--- a/src/com/android/launcher3/allapps/VerticalPullDetector.java
+++ b/src/com/android/launcher3/allapps/VerticalPullDetector.java
@@ -14,9 +14,7 @@
     private static final boolean DBG = false;
 
     private float mTouchSlop;
-
-    private boolean mAllAppsVisible;
-    private boolean mAllAppsScrollAtTop;
+    private boolean mScrollDown; // if false, only scroll up will be reported.
 
     /**
      * The minimum release velocity in pixels per millisecond that triggers fling..
@@ -32,20 +30,20 @@
     /* Scroll state, this is set to true during dragging and animation. */
     boolean mScrolling;
 
-    float mDownX;
-    float mDownY;
-    float mDownMillis;
+    private float mDownX;
+    private float mDownY;
+    private float mDownMillis;
 
-    float mLastY;
-    float mLastMillis;
+    private float mLastY;
+    private float mLastMillis;
 
-    float mVelocity;
-    float mLastDisplacement;
-    float mDisplacementY;
-    float mDisplacementX;
+    private float mVelocity;
+    private float mLastDisplacement;
+    private float mDisplacementY;
+    private float mDisplacementX;
 
     /* scroll started during previous animation */
-    boolean mSubtractSlop = true;
+    private boolean mSubtractSlop = true;
 
     /* Client of this gesture detector can register a callback. */
     Listener mListener;
@@ -67,20 +65,19 @@
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
     }
 
-    public void setAllAppsState(boolean allAppsVisible, boolean scrollAtTop) {
-        mAllAppsVisible = allAppsVisible;
-        mAllAppsScrollAtTop = scrollAtTop;
+    public void setScrollDirectionDown(boolean scrollDown) {
+        mScrollDown = scrollDown;
     }
 
     private boolean shouldScrollStart() {
         float deltaY = Math.abs(mDisplacementY);
         float deltaX = Math.max(Math.abs(mDisplacementX), 1);
-        if (mAllAppsVisible && mDisplacementY > mTouchSlop && mAllAppsScrollAtTop) {
+        if (mScrollDown && mDisplacementY > mTouchSlop) {
             if (deltaY > deltaX) {
                 return true;
             }
         }
-        if (!mAllAppsVisible && mDisplacementY < -mTouchSlop) {
+        if (!mScrollDown && mDisplacementY < -mTouchSlop) {
             if (deltaY > deltaX) {
                 return true;
             }
@@ -140,6 +137,7 @@
 
     private boolean reportScrollStart(boolean recatch) {
         mListener.onScrollStart(!recatch);
+        mSubtractSlop = !recatch;
         if (DBG) {
             Log.d(TAG, "onScrollStart recatch:" + recatch);
         }
@@ -153,11 +151,15 @@
                 Log.d(TAG, String.format("onScroll disp=%.1f, velocity=%.1f",
                         mDisplacementY, mVelocity));
             }
-            if (mDisplacementY > 0) {
-                return mListener.onScroll(mDisplacementY - mTouchSlop, mVelocity);
-            } else {
-                return mListener.onScroll(mDisplacementY + mTouchSlop, mVelocity);
+            float subtractDisplacement = 0f;
+            if (mSubtractSlop) {
+                if (mDisplacementY > 0) {
+                    subtractDisplacement = mTouchSlop;
+                } else {
+                    subtractDisplacement = -mTouchSlop;
+                }
             }
+            return mListener.onScroll(mDisplacementY - subtractDisplacement, mVelocity);
         }
         return true;
     }