Merge "Set contentDescription on caret" into ub-launcher3-calgary-polish
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index c738480..f9424d4 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -25,6 +25,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.support.v4.content.ContextCompat;
 import android.support.v4.graphics.ColorUtils;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
@@ -69,7 +70,7 @@
         mLauncher = (Launcher) context;
         mHasVerticalHotseat = mLauncher.getDeviceProfile().isVerticalBarLayout();
         mBackgroundColor = ColorUtils.setAlphaComponent(
-                context.getColor(R.color.all_apps_container_color), 0);
+                ContextCompat.getColor(context, R.color.all_apps_container_color), 0);
         mBackground = new ColorDrawable(mBackgroundColor);
         setBackground(mBackground);
     }
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index cf4a43b..0bb8cbf 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -76,7 +76,6 @@
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.graphics.DragPreviewProvider;
-import com.android.launcher3.logging.UserEventDispatcher;
 import com.android.launcher3.shortcuts.DeepShortcutManager;
 import com.android.launcher3.shortcuts.ShortcutsContainerListener;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -85,6 +84,7 @@
 import com.android.launcher3.util.LongArrayMap;
 import com.android.launcher3.util.MultiStateAlphaController;
 import com.android.launcher3.util.Thunk;
+import com.android.launcher3.util.VerticalFlingDetector;
 import com.android.launcher3.util.WallpaperOffsetInterpolator;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
@@ -594,7 +594,18 @@
         }
         // Add the first page
         CellLayout firstPage = insertNewWorkspaceScreen(Workspace.FIRST_SCREEN_ID, 0);
-
+        final VerticalFlingDetector detector = new VerticalFlingDetector(mLauncher){
+            @Override
+            public boolean onTouch(View v, MotionEvent ev) {
+                if (shouldConsumeTouch(v)) return true;
+                if (super.onTouch(v, ev)) {
+                    mLauncher.startSearch("", false, null, false);
+                }
+                return false;
+            }
+        };
+        firstPage.setOnTouchListener(detector);
+        firstPage.setOnInterceptTouchListener(detector);
         // Always add a QSB on the first screen.
         if (qsb == null) {
             // In transposed layout, we add the QSB in the Grid. As workspace does not touch the
@@ -686,7 +697,6 @@
         // created CellLayout.
         CellLayout newScreen = (CellLayout) mLauncher.getLayoutInflater().inflate(
                         R.layout.workspace_screen, this, false /* attachToRoot */);
-
         newScreen.setOnLongClickListener(mLongClickListener);
         newScreen.setOnClickListener(mLauncher);
         newScreen.setSoundEffectsEnabled(false);
@@ -1172,6 +1182,10 @@
     @SuppressLint("ClickableViewAccessibility")
     @Override
     public boolean onTouch(View v, MotionEvent event) {
+        return shouldConsumeTouch(v);
+    }
+
+    private boolean shouldConsumeTouch(View v) {
         return (workspaceInModalState() || !isFinishedSwitchingState())
                 || (!workspaceInModalState() && indexOfChild(v) != mCurrentPage);
     }
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 5888230..9fcc6a4 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -6,6 +6,7 @@
 import android.animation.AnimatorSet;
 import android.animation.ArgbEvaluator;
 import android.animation.ObjectAnimator;
+import android.support.v4.content.ContextCompat;
 import android.support.v4.view.animation.FastOutSlowInInterpolator;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -101,7 +102,7 @@
                 R.dimen.all_apps_bezel_swipe_height);
 
         mEvaluator = new ArgbEvaluator();
-        mAllAppsBackgroundColor = l.getColor(R.color.all_apps_container_color);
+        mAllAppsBackgroundColor = ContextCompat.getColor(l, R.color.all_apps_container_color);
     }
 
     @Override
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
index 747c21b..fb9d2f7 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
@@ -226,11 +226,6 @@
     public void setActiveMarker(int activePage) {
         if (mActivePage != activePage) {
             mActivePage = activePage;
-
-            // Simulate a scroll change
-            int totalScroll = mNumPages - 1;
-            int currentScroll = mIsRtl ? (totalScroll - mActivePage) : mActivePage;
-            setScroll(currentScroll, totalScroll);
         }
     }
 
diff --git a/src/com/android/launcher3/util/TransformingTouchDelegate.java b/src/com/android/launcher3/util/TransformingTouchDelegate.java
index da1de5e..3197ba9 100644
--- a/src/com/android/launcher3/util/TransformingTouchDelegate.java
+++ b/src/com/android/launcher3/util/TransformingTouchDelegate.java
@@ -33,6 +33,10 @@
 
     private final RectF mBounds;
 
+    private final RectF mTouchCheckBounds;
+    private float mTouchExtension;
+    private boolean mWasTouchOutsideBounds;
+
     private View mDelegateView;
     private boolean mDelegateTargeted;
 
@@ -41,10 +45,22 @@
 
         mDelegateView = delegateView;
         mBounds = new RectF();
+        mTouchCheckBounds = new RectF();
     }
 
     public void setBounds(int left, int top, int right, int bottom) {
         mBounds.set(left, top, right, bottom);
+        updateTouchBounds();
+    }
+
+    public void extendTouchBounds(float extension) {
+        mTouchExtension = extension;
+        updateTouchBounds();
+    }
+
+    private void updateTouchBounds() {
+        mTouchCheckBounds.set(mBounds);
+        mTouchCheckBounds.inset(-mTouchExtension, -mTouchExtension);
     }
 
     public void setDelegateView(View view) {
@@ -62,8 +78,9 @@
         boolean sendToDelegate = false;
         switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
-                mDelegateTargeted = mBounds.contains(event.getX(), event.getY());
+                mDelegateTargeted = mTouchCheckBounds.contains(event.getX(), event.getY());
                 if (mDelegateTargeted) {
+                    mWasTouchOutsideBounds = !mBounds.contains(event.getX(), event.getY());
                     sendToDelegate = true;
                 }
                 break;
@@ -78,9 +95,15 @@
         }
         boolean handled = false;
         if (sendToDelegate) {
-            event.offsetLocation(-mBounds.left, -mBounds.top);
+            float x = event.getX();
+            float y = event.getY();
+            if (mWasTouchOutsideBounds) {
+                event.setLocation(mBounds.centerX(), mBounds.centerY());
+            } else {
+                event.offsetLocation(-mBounds.left, -mBounds.top);
+            }
             handled = mDelegateView.dispatchTouchEvent(event);
-            event.offsetLocation(mBounds.left, mBounds.top);
+            event.setLocation(x, y);
         }
         return handled;
     }
diff --git a/src/com/android/launcher3/util/VerticalFlingDetector.java b/src/com/android/launcher3/util/VerticalFlingDetector.java
new file mode 100644
index 0000000..5f2b3f3
--- /dev/null
+++ b/src/com/android/launcher3/util/VerticalFlingDetector.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016 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.launcher3.util;
+
+import android.content.Context;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+
+public class VerticalFlingDetector implements View.OnTouchListener {
+
+    private static final float CUSTOM_SLOP_MULTIPLIER = 2.2f;
+    private static final int SEC_IN_MILLIS = 1000;
+
+    private VelocityTracker mVelocityTracker;
+    private float mMinimumFlingVelocity;
+    private float mMaximumFlingVelocity;
+    private float mDownX, mDownY;
+    private boolean mShouldCheckFling;
+    private double mCustomTouchSlop;
+
+    public VerticalFlingDetector(Context context) {
+        ViewConfiguration vc = ViewConfiguration.get(context);
+        mMinimumFlingVelocity = vc.getScaledMinimumFlingVelocity();
+        mMaximumFlingVelocity = vc.getScaledMaximumFlingVelocity();
+        mCustomTouchSlop = CUSTOM_SLOP_MULTIPLIER * vc.getScaledTouchSlop();
+    }
+
+    @Override
+    public boolean onTouch(View v, MotionEvent ev) {
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+        mVelocityTracker.addMovement(ev);
+        switch (ev.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                mDownX = ev.getX();
+                mDownY = ev.getY();
+                mShouldCheckFling = false;
+                break;
+            case MotionEvent.ACTION_MOVE:
+                if (mShouldCheckFling) {
+                    break;
+                }
+                if (Math.abs(ev.getY() - mDownY) > mCustomTouchSlop &&
+                        Math.abs(ev.getY() - mDownY) > Math.abs(ev.getX() - mDownX)) {
+                    mShouldCheckFling = true;
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+                if (mShouldCheckFling) {
+                    mVelocityTracker.computeCurrentVelocity(SEC_IN_MILLIS, mMaximumFlingVelocity);
+                    // only when fling is detected in down direction
+                    if (mVelocityTracker.getYVelocity() > mMinimumFlingVelocity) {
+                        cleanUp();
+                        return true;
+                    }
+                }
+                // fall through.
+            case MotionEvent.ACTION_CANCEL:
+                cleanUp();
+        }
+        return false;
+    }
+
+    private void cleanUp() {
+        mVelocityTracker.recycle();
+        mVelocityTracker = null;
+    }
+}