Fixing up some more focus edge cases.

- Disallow touch while alt-tabbing
- Allow keyboard to focus tab while scrolling
- Cleaning up some old classes that aren’t really being used

Change-Id: Ibabea093afb711b07f398677d25735421b7c7e53
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index ebfacac..39aad99 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -57,14 +57,4 @@
             public static final int SystemServicesProxyMockTaskCount = 100;
         }
     }
-
-    public static class Values {
-        public static class App {
-            public static int AppWidgetHostId = 1024;
-        }
-
-        public static class TaskStackView {
-            public static final int FilterStartDelay = 25;
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index f800785..af6df1d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -32,19 +32,19 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.util.Log;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewStub;
 import android.view.ViewTreeObserver;
-
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationStartedEvent;
+import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
 import com.android.systemui.recents.events.activity.IterateRecentsEvent;
-import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
@@ -57,7 +57,6 @@
 import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent;
-import com.android.systemui.recents.misc.Console;
 import com.android.systemui.recents.misc.DozeTrigger;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -137,8 +136,7 @@
             try {
                 startActivityAsUser(mLaunchIntent, mLaunchOpts.toBundle(), UserHandle.CURRENT);
             } catch (Exception e) {
-                Console.logError(RecentsActivity.this,
-                        getString(R.string.recents_launch_error_message, "Home"));
+                Log.e(TAG, getString(R.string.recents_launch_error_message, "Home"), e);
             }
         }
     }
@@ -345,7 +343,7 @@
 
         // Initialize the widget host (the host id is static and does not change)
         if (!Constants.DebugFlags.App.DisableSearchBar) {
-            mAppWidgetHost = new RecentsAppWidgetHost(this, Constants.Values.App.AppWidgetHostId);
+            mAppWidgetHost = new RecentsAppWidgetHost(this, RecentsAppWidgetHost.HOST_ID);
         }
         mPackageMonitor = new RecentsPackageMonitor();
         mPackageMonitor.register(this);
@@ -357,6 +355,12 @@
         mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
                 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
                 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+        mRecentsView.getViewTreeObserver().addOnEnterAnimationCompleteListener(new ViewTreeObserver.OnEnterAnimationCompleteListener() {
+            @Override
+            public void onEnterAnimationComplete() {
+                System.out.println("ENTER ANIMATION COMPLETE");
+            }
+        });
         mEmptyViewStub = (ViewStub) findViewById(R.id.empty_view_stub);
         mScrimViews = new SystemBarScrimViews(this);
 
@@ -575,10 +579,6 @@
     /**** RecentsView.RecentsViewCallbacks Implementation ****/
 
     @Override
-    public void onTaskViewClicked() {
-    }
-
-    @Override
     public void onTaskLaunchFailed() {
         // Return to Home
         dismissRecentsToHome(true);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
index 9ee6f5b..01ffd2a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -19,7 +19,6 @@
 /**
  * The launch state of the RecentsActivity.
  *
- * TODO: We will be refactoring this out RecentsConfiguration.
  * Current Constraints:
  *  - needed in onStart() before onNewIntent()
  *  - needs to be reset when Recents is hidden
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
index fc96c11..573db98 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
@@ -26,6 +26,8 @@
 /** Our special app widget host for the Search widget */
 public class RecentsAppWidgetHost extends AppWidgetHost {
 
+    public static final int HOST_ID = 1024;
+
     boolean mIsListening;
 
     public RecentsAppWidgetHost(Context context, int hostId) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 675ef2f..c719e46 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.recents;
 
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.ITaskStackListener;
@@ -32,24 +30,23 @@
 import android.os.Handler;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.util.Log;
 import android.util.MutableBoolean;
 import android.view.AppTransitionAnimationSpec;
 import android.view.LayoutInflater;
 import android.view.View;
-
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.SystemUIApplication;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationStartedEvent;
+import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
 import com.android.systemui.recents.events.activity.IterateRecentsEvent;
-import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
-import com.android.systemui.recents.misc.Console;
 import com.android.systemui.recents.misc.ForegroundThread;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.RecentsTaskLoadPlan;
@@ -57,14 +54,16 @@
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskGrouping;
 import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.recents.views.TaskStackView;
 import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
+import com.android.systemui.recents.views.TaskStackView;
 import com.android.systemui.recents.views.TaskViewHeader;
 import com.android.systemui.recents.views.TaskViewTransform;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 
 import java.util.ArrayList;
 
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+
 /**
  * An implementation of the Recents component for the current user.  For secondary users, this can
  * be called remotely from the system user.
@@ -164,7 +163,7 @@
     public RecentsImpl(Context context) {
         mContext = context;
         mHandler = new Handler();
-        mAppWidgetHost = new RecentsAppWidgetHost(mContext, Constants.Values.App.AppWidgetHostId);
+        mAppWidgetHost = new RecentsAppWidgetHost(mContext, RecentsAppWidgetHost.HOST_ID);
         Resources res = mContext.getResources();
         LayoutInflater inflater = LayoutInflater.from(mContext);
 
@@ -249,7 +248,7 @@
                 startRecentsActivity(topTask, isTopTaskHome.value);
             }
         } catch (ActivityNotFoundException e) {
-            Console.logRawError("Failed to launch RecentAppsIntent", e);
+            Log.e(TAG, "Failed to launch RecentsActivity", e);
         }
     }
 
@@ -305,7 +304,7 @@
                 mLastToggleTime = SystemClock.elapsedRealtime();
             }
         } catch (ActivityNotFoundException e) {
-            Console.logRawError("Failed to launch RecentAppsIntent", e);
+            Log.e(TAG, "Failed to launch RecentsActivity", e);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Console.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Console.java
deleted file mode 100644
index 28ac9d3..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Console.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2014 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.systemui.recents.misc;
-
-
-import android.content.ComponentCallbacks2;
-import android.content.Context;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.widget.Toast;
-
-import java.util.HashMap;
-import java.util.Map;
-
-
-public class Console {
-    // Timer
-    public static final Map<Object, Long> mTimeLogs = new HashMap<Object, Long>();
-
-    // Colors
-    public static final String AnsiReset = "\u001B[0m";
-    public static final String AnsiBlack = "\u001B[30m";
-    public static final String AnsiRed = "\u001B[31m";      // SystemUIHandshake
-    public static final String AnsiGreen = "\u001B[32m";    // MeasureAndLayout
-    public static final String AnsiYellow = "\u001B[33m";   // SynchronizeViewsWithModel
-    public static final String AnsiBlue = "\u001B[34m";     // TouchEvents, Search
-    public static final String AnsiPurple = "\u001B[35m";   // Draw
-    public static final String AnsiCyan = "\u001B[36m";     // ClickEvents
-    public static final String AnsiWhite = "\u001B[37m";
-
-    // Console enabled state
-    public static boolean Enabled = false;
-
-    /** Logs a key */
-    public static void log(String key) {
-        log(true, key, "", AnsiReset);
-    }
-
-    /** Logs a conditioned key */
-    public static void log(boolean condition, String key) {
-        if (condition) {
-            log(condition, key, "", AnsiReset);
-        }
-    }
-
-    /** Logs a key in a specific color */
-    public static void log(boolean condition, String key, Object data) {
-        if (condition) {
-            log(condition, key, data, AnsiReset);
-        }
-    }
-
-    /** Logs a key with data in a specific color */
-    public static void log(boolean condition, String key, Object data, String color) {
-        if (condition) {
-            System.out.println(color + key + AnsiReset + " " + data.toString());
-        }
-    }
-
-    /** Logs an error */
-    public static void logError(Context context, String msg) {
-        Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
-        Log.e("Recents", msg);
-    }
-
-    /** Logs a raw error */
-    public static void logRawError(String msg, Exception e) {
-        Log.e("Recents", msg, e);
-    }
-
-    /** Logs a divider bar */
-    public static void logDivider(boolean condition) {
-        if (condition) {
-            System.out.println("==== [" + System.currentTimeMillis() +
-                    "] ============================================================");
-        }
-    }
-
-    /** Starts a time trace */
-    public static void logStartTracingTime(boolean condition, String key) {
-        if (condition) {
-            long curTime = System.currentTimeMillis();
-            mTimeLogs.put(key, curTime);
-            Console.log(condition, "[Recents|" + key + "]",
-                    "started @ " + curTime);
-        }
-    }
-
-    /** Continues a time trace */
-    public static void logTraceTime(boolean condition, String key, String desc) {
-        if (condition) {
-            long timeDiff = System.currentTimeMillis() - mTimeLogs.get(key);
-            Console.log(condition, "[Recents|" + key + "|" + desc + "]",
-                    "+" + timeDiff + "ms");
-        }
-    }
-
-    /** Logs a stack trace */
-    public static void logStackTrace() {
-        logStackTrace("", 99);
-    }
-
-    /** Logs a stack trace to a certain depth */
-    public static void logStackTrace(int depth) {
-        logStackTrace("", depth);
-    }
-
-    /** Logs a stack trace to a certain depth with a key */
-    public static void logStackTrace(String key, int depth) {
-        int offset = 0;
-        StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
-        String tinyStackTrace = "";
-        // Skip over the known stack trace classes
-        for (int i = 0; i < callStack.length; i++) {
-            StackTraceElement el = callStack[i];
-            String className = el.getClassName();
-            if (className.indexOf("dalvik.system.VMStack") == -1 &&
-                className.indexOf("java.lang.Thread") == -1 &&
-                className.indexOf("recents.Console") == -1) {
-                break;
-            } else {
-                offset++;
-            }
-        }
-        // Build the pretty stack trace
-        int start = Math.min(offset + depth, callStack.length);
-        int end = offset;
-        String indent = "";
-        for (int i = start - 1; i >= end; i--) {
-            StackTraceElement el = callStack[i];
-            tinyStackTrace += indent + " -> " + el.getClassName() +
-                    "[" + el.getLineNumber() + "]." + el.getMethodName();
-            if (i > end) {
-                tinyStackTrace += "\n";
-                indent += "  ";
-            }
-        }
-        log(true, key, tinyStackTrace, AnsiRed);
-    }
-
-
-    /** Returns the stringified MotionEvent action */
-    public static String motionEventActionToString(int action) {
-        switch (action) {
-            case MotionEvent.ACTION_DOWN:
-                return "Down";
-            case MotionEvent.ACTION_UP:
-                return "Up";
-            case MotionEvent.ACTION_MOVE:
-                return "Move";
-            case MotionEvent.ACTION_CANCEL:
-                return "Cancel";
-            case MotionEvent.ACTION_POINTER_DOWN:
-                return "Pointer Down";
-            case MotionEvent.ACTION_POINTER_UP:
-                return "Pointer Up";
-            default:
-                return "" + action;
-        }
-    }
-
-    public static String trimMemoryLevelToString(int level) {
-        switch (level) {
-            case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
-                return "UI Hidden";
-            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
-                return "Running Moderate";
-            case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
-                return "Background";
-            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
-                return "Running Low";
-            case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
-                return "Moderate";
-            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
-                return "Critical";
-            case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
-                return "Complete";
-            default:
-                return "" + level;
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java
index c87a901..401b448 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java
@@ -19,6 +19,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
+import android.util.Log;
 
 import java.util.ArrayList;
 
@@ -28,6 +29,8 @@
  */
 public class ReferenceCountedTrigger {
 
+    private static final String TAG = "ReferenceCountedTrigger";
+
     Context mContext;
     int mCount;
     ArrayList<Runnable> mFirstIncRunnables = new ArrayList<Runnable>();
@@ -94,8 +97,7 @@
             if (mErrorRunnable != null) {
                 mErrorRunnable.run();
             } else {
-                new Throwable("Invalid ref count").printStackTrace();
-                Console.logError(mContext, "Invalid ref count");
+                Log.e(TAG, "Invalid ref count");
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 4ee0357..578d2b1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -124,7 +124,7 @@
         mUm = UserManager.get(context);
         mDisplay = mWm.getDefaultDisplay();
         mRecentsPackage = context.getPackageName();
-        mHasFreeformWorkspaceSupport = false && mPm.hasSystemFeature(
+        mHasFreeformWorkspaceSupport = true || mPm.hasSystemFeature(
                 PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT);
 
         // Get the dummy thumbnail width/heights
@@ -775,8 +775,7 @@
                         taskId, INVALID_STACK_ID, options == null ? null : options.toBundle());
                 return true;
             } catch (Exception e) {
-                Console.logError(context,
-                        context.getString(R.string.recents_launch_error_message, taskName));
+                Log.e(TAG, context.getString(R.string.recents_launch_error_message, taskName), e);
             }
         }
         return false;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 495c8fd..6734012 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -17,14 +17,12 @@
 package com.android.systemui.recents.model;
 
 import android.animation.ObjectAnimator;
-import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.ColorDrawable;
-import android.util.Log;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.Recents;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 9a5e141..b131604 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -64,8 +64,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 
 /**
@@ -82,7 +82,6 @@
 
     /** The RecentsView callbacks */
     public interface RecentsViewCallbacks {
-        public void onTaskViewClicked();
         public void onTaskLaunchFailed();
         public void onAllTaskViewsDismissed();
     }
@@ -575,10 +574,6 @@
     public void onTaskViewClicked(final TaskStackView stackView, final TaskView tv,
             final TaskStack stack, final Task task, final boolean lockToTask,
             final boolean boundsValid, final Rect bounds, int destinationStack) {
-        // Notify any callbacks of the launching of a new task
-        if (mCb != null) {
-            mCb.onTaskViewClicked();
-        }
 
         // Upfront the processing of the thumbnail
         TaskViewTransform transform = new TaskViewTransform();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index 7f5c768..51091c3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -31,7 +31,6 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.LinkedList;
 
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index fc3a681..3ef597f7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -34,7 +34,6 @@
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 import com.android.systemui.R;
-import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsActivity;
 import com.android.systemui.recents.RecentsActivityLaunchState;
@@ -228,6 +227,42 @@
         return mImmutableTaskViews;
     }
 
+    /**
+     * Returns the front most task view.
+     *
+     * @param stackTasksOnly if set, will return the front most task view in the stack (by default
+     *                       the front most task view will be freeform since they are placed above
+     *                       stack tasks)
+     */
+    private TaskView getFrontMostTaskView(boolean stackTasksOnly) {
+        List<TaskView> taskViews = getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = taskViewCount - 1; i >= 0; i--) {
+            TaskView tv = taskViews.get(i);
+            Task task = tv.getTask();
+            if (stackTasksOnly && task.isFreeformTask()) {
+                continue;
+            }
+            return tv;
+        }
+        return null;
+    }
+
+    /**
+     * Finds the child view given a specific {@param task}.
+     */
+    public TaskView getChildViewForTask(Task t) {
+        List<TaskView> taskViews = getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = 0; i < taskViewCount; i++) {
+            TaskView tv = taskViews.get(i);
+            if (tv.getTask() == t) {
+                return tv;
+            }
+        }
+        return null;
+    }
+
     /** Resets this TaskStackView for reuse. */
     void reset() {
         // Reset the focused task
@@ -288,19 +323,6 @@
         }
     }
 
-    /** Finds the child view given a specific task. */
-    public TaskView getChildViewForTask(Task t) {
-        List<TaskView> taskViews = getTaskViews();
-        int taskViewCount = taskViews.size();
-        for (int i = 0; i < taskViewCount; i++) {
-            TaskView tv = taskViews.get(i);
-            if (tv.getTask() == t) {
-                return tv;
-            }
-        }
-        return null;
-    }
-
     /** Returns the stack algorithm for this task stack. */
     public TaskStackLayoutAlgorithm getStackAlgorithm() {
         return mLayoutAlgorithm;
@@ -635,13 +657,49 @@
     /**
      * Sets the focused task relative to the currently focused task.
      *
+     * @param stackTasksOnly if set, will ensure that the traversal only goes along stack tasks, and
+     *                       if the currently focused task is not a stack task, will set the focus
+     *                       to the first visible stack task
      * @param animated determines whether to actually draw the highlight along with the change in
      *                            focus.
      */
-    public void setRelativeFocusedTask(boolean forward, boolean animated) {
-        // Find the next index to focus
-        int newIndex = mFocusedTaskIndex + (forward ? -1 : 1);
-        setFocusedTask(newIndex, true, animated);
+    public void setRelativeFocusedTask(boolean forward, boolean stackTasksOnly, boolean animated) {
+        int newIndex = -1;
+        if (mFocusedTaskIndex != -1) {
+            if (stackTasksOnly) {
+                List<Task> tasks =  mStack.getTasks();
+                newIndex = mFocusedTaskIndex;
+                Task task = tasks.get(mFocusedTaskIndex);
+                if (task.isFreeformTask()) {
+                    // Try and focus the front most stack task
+                    TaskView tv = getFrontMostTaskView(stackTasksOnly);
+                    if (tv != null) {
+                        newIndex = mStack.indexOfTask(tv.getTask());
+                    }
+                } else {
+                    // Try the next task if it is a stack task
+                    int tmpNewIndex = mFocusedTaskIndex + (forward ? -1 : 1);
+                    if (0 <= tmpNewIndex && tmpNewIndex < tasks.size()) {
+                        Task t = tasks.get(tmpNewIndex);
+                        if (!t.isFreeformTask()) {
+                            newIndex = tmpNewIndex;
+                        }
+                    }
+                }
+            } else {
+                // No restrictions, lets just move to the new task
+                newIndex = mFocusedTaskIndex + (forward ? -1 : 1);
+            }
+        } else {
+            // We don't have a focused task, so focus the first visible task view
+            TaskView tv = getFrontMostTaskView(stackTasksOnly);
+            if (tv != null) {
+                newIndex = mStack.indexOfTask(tv.getTask());
+            }
+        }
+        if (newIndex != -1) {
+            setFocusedTask(newIndex, true, animated);
+        }
     }
 
     /**
@@ -703,11 +761,11 @@
         }
         switch (action) {
             case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
-                setRelativeFocusedTask(true, false /* animated */);
+                setRelativeFocusedTask(true, false /* stackTasksOnly */, false /* animated */);
                 return true;
             }
             case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
-                setRelativeFocusedTask(false, false /* animated */);
+                setRelativeFocusedTask(false, false /* stackTasksOnly */, false /* animated */);
                 return true;
             }
         }
@@ -1324,11 +1382,11 @@
     }
 
     public final void onBusEvent(FocusNextTaskViewEvent event) {
-        setRelativeFocusedTask(true, true);
+        setRelativeFocusedTask(true, false /* stackTasksOnly */, true /* animated */);
     }
 
     public final void onBusEvent(FocusPreviousTaskViewEvent event) {
-        setRelativeFocusedTask(false, true);
+        setRelativeFocusedTask(false, false /* stackTasksOnly */, true /* animated */);
     }
 
     public final void onBusEvent(DismissFocusedTaskViewEvent event) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java
index a32b242..45f573d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java
@@ -17,7 +17,6 @@
 package com.android.systemui.recents.views;
 
 import com.android.systemui.R;
-import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.model.Task;
 
 import java.util.ArrayList;
@@ -113,7 +112,7 @@
                     tv.prepareTaskTransformForFilterTaskHidden(fromTransform);
                     tv.updateViewPropertiesToTaskTransform(fromTransform, 0);
 
-                    toTransform.startDelay = offset * Constants.Values.TaskStackView.FilterStartDelay;
+                    toTransform.startDelay = offset * 25;
                     childViewTransformsOut.put(tv, toTransform);
 
                     // Use the movement of the new views to calculate the duration of the animation
@@ -166,7 +165,7 @@
                         (int) tv.getTranslationY()));
             }
 
-            toTransform.startDelay = offset * Constants.Values.TaskStackView.FilterStartDelay;
+            toTransform.startDelay = offset * 25;
             childViewTransformsOut.put(tv, toTransform);
             offset++;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 59c9708..81c89a1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -31,6 +31,7 @@
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
 import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
@@ -149,6 +150,11 @@
         if (mSv.getTaskViews().size() == 0) {
             return false;
         }
+        // Short circuit while we are alt-tabbing
+        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+        if (launchState.launchedWithAltTab) {
+            return false;
+        }
 
         final TaskStackLayoutAlgorithm layoutAlgorithm = mSv.mLayoutAlgorithm;
         int action = ev.getAction();
@@ -305,9 +311,11 @@
                     // Find the front most task and scroll the next task to the front
                     float vScroll = ev.getAxisValue(MotionEvent.AXIS_VSCROLL);
                     if (vScroll > 0) {
-                        mSv.setRelativeFocusedTask(true, false /* animated */);
+                        mSv.setRelativeFocusedTask(true, true /* stackTasksOnly */,
+                                false /* animated */);
                     } else {
-                        mSv.setRelativeFocusedTask(false, false /* animated */);
+                        mSv.setRelativeFocusedTask(false, true /* stackTasksOnly */,
+                                false /* animated */);
                     }
                     return true;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index dd1474d..4f4b91a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -29,6 +29,7 @@
 import android.graphics.Point;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
+import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -80,7 +81,6 @@
     boolean mTaskDataLoaded;
     boolean mIsFocused;
     boolean mIsFocusAnimated;
-    boolean mFocusAnimationsEnabled;
     boolean mClipViewInStack;
     AnimateableViewBounds mViewBounds;
 
@@ -642,6 +642,21 @@
         setDim(getDimFromTaskProgress());
     }
 
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        super.dispatchDraw(canvas);
+        if (Constants.DebugFlags.App.EnableFastToggleRecents && mIsFocused) {
+            Paint tmpPaint = new Paint();
+            Rect tmpRect = new Rect();
+            tmpRect.set(0, 0, getWidth(), getHeight());
+            tmpPaint.setColor(0xFFFF0000);
+            tmpPaint.setStrokeWidth(35);
+            tmpPaint.setStyle(Paint.Style.STROKE);
+            canvas.drawRect(tmpRect, tmpPaint);
+        }
+    }
+
     /**** View focus state ****/
 
     /**
@@ -672,6 +687,9 @@
                 clearAccessibilityFocus();
             }
         }
+        if (Constants.DebugFlags.App.EnableFastToggleRecents) {
+            invalidate();
+        }
     }
 
     /**