Merge "Stop populating RemoteViews in Notifications."
diff --git a/api/current.txt b/api/current.txt
index 48e175a..15cc347 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -22161,6 +22161,7 @@
     field public static final int GL_ACTIVE_PROGRAM = 33369; // 0x8259
     field public static final int GL_ACTIVE_RESOURCES = 37621; // 0x92f5
     field public static final int GL_ACTIVE_VARIABLES = 37637; // 0x9305
+    field public static final int GL_ALL_BARRIER_BITS = -1; // 0xffffffff
     field public static final int GL_ALL_SHADER_BITS = -1; // 0xffffffff
     field public static final int GL_ARRAY_SIZE = 37627; // 0x92fb
     field public static final int GL_ARRAY_STRIDE = 37630; // 0x92fe
@@ -22184,6 +22185,7 @@
     field public static final int GL_DISPATCH_INDIRECT_BUFFER_BINDING = 37103; // 0x90ef
     field public static final int GL_DRAW_INDIRECT_BUFFER = 36671; // 0x8f3f
     field public static final int GL_DRAW_INDIRECT_BUFFER_BINDING = 36675; // 0x8f43
+    field public static final int GL_ELEMENT_ARRAY_BARRIER_BIT = 2; // 0x2
     field public static final int GL_FRAGMENT_SHADER_BIT = 2; // 0x2
     field public static final int GL_FRAMEBUFFER_BARRIER_BIT = 1024; // 0x400
     field public static final int GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS = 37652; // 0x9314
@@ -22273,6 +22275,7 @@
     field public static final int GL_SAMPLE_MASK = 36433; // 0x8e51
     field public static final int GL_SAMPLE_MASK_VALUE = 36434; // 0x8e52
     field public static final int GL_SAMPLE_POSITION = 36432; // 0x8e50
+    field public static final int GL_SHADER_IMAGE_ACCESS_BARRIER_BIT = 32; // 0x20
     field public static final int GL_SHADER_STORAGE_BARRIER_BIT = 8192; // 0x2000
     field public static final int GL_SHADER_STORAGE_BLOCK = 37606; // 0x92e6
     field public static final int GL_SHADER_STORAGE_BUFFER = 37074; // 0x90d2
@@ -22318,6 +22321,7 @@
     field public static final int GL_UNSIGNED_INT_IMAGE_3D = 36964; // 0x9064
     field public static final int GL_UNSIGNED_INT_IMAGE_CUBE = 36966; // 0x9066
     field public static final int GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE = 37130; // 0x910a
+    field public static final int GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT = 1; // 0x1
     field public static final int GL_VERTEX_ATTRIB_BINDING = 33492; // 0x82d4
     field public static final int GL_VERTEX_ATTRIB_RELATIVE_OFFSET = 33493; // 0x82d5
     field public static final int GL_VERTEX_BINDING_BUFFER = 36687; // 0x8f4f
diff --git a/api/system-current.txt b/api/system-current.txt
index 4872337..a9a8753 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -24106,6 +24106,7 @@
     field public static final int GL_ACTIVE_PROGRAM = 33369; // 0x8259
     field public static final int GL_ACTIVE_RESOURCES = 37621; // 0x92f5
     field public static final int GL_ACTIVE_VARIABLES = 37637; // 0x9305
+    field public static final int GL_ALL_BARRIER_BITS = -1; // 0xffffffff
     field public static final int GL_ALL_SHADER_BITS = -1; // 0xffffffff
     field public static final int GL_ARRAY_SIZE = 37627; // 0x92fb
     field public static final int GL_ARRAY_STRIDE = 37630; // 0x92fe
@@ -24129,6 +24130,7 @@
     field public static final int GL_DISPATCH_INDIRECT_BUFFER_BINDING = 37103; // 0x90ef
     field public static final int GL_DRAW_INDIRECT_BUFFER = 36671; // 0x8f3f
     field public static final int GL_DRAW_INDIRECT_BUFFER_BINDING = 36675; // 0x8f43
+    field public static final int GL_ELEMENT_ARRAY_BARRIER_BIT = 2; // 0x2
     field public static final int GL_FRAGMENT_SHADER_BIT = 2; // 0x2
     field public static final int GL_FRAMEBUFFER_BARRIER_BIT = 1024; // 0x400
     field public static final int GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS = 37652; // 0x9314
@@ -24218,6 +24220,7 @@
     field public static final int GL_SAMPLE_MASK = 36433; // 0x8e51
     field public static final int GL_SAMPLE_MASK_VALUE = 36434; // 0x8e52
     field public static final int GL_SAMPLE_POSITION = 36432; // 0x8e50
+    field public static final int GL_SHADER_IMAGE_ACCESS_BARRIER_BIT = 32; // 0x20
     field public static final int GL_SHADER_STORAGE_BARRIER_BIT = 8192; // 0x2000
     field public static final int GL_SHADER_STORAGE_BLOCK = 37606; // 0x92e6
     field public static final int GL_SHADER_STORAGE_BUFFER = 37074; // 0x90d2
@@ -24263,6 +24266,7 @@
     field public static final int GL_UNSIGNED_INT_IMAGE_3D = 36964; // 0x9064
     field public static final int GL_UNSIGNED_INT_IMAGE_CUBE = 36966; // 0x9066
     field public static final int GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE = 37130; // 0x910a
+    field public static final int GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT = 1; // 0x1
     field public static final int GL_VERTEX_ATTRIB_BINDING = 33492; // 0x82d4
     field public static final int GL_VERTEX_ATTRIB_RELATIVE_OFFSET = 33493; // 0x82d5
     field public static final int GL_VERTEX_BINDING_BUFFER = 36687; // 0x8f4f
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 3f8e311..2960cdc 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -283,7 +283,7 @@
             } else if (args.length == 2) {
                 if (args[0].equalsIgnoreCase("-p")) {
                     validCommand = true;
-                    return displayPackageFilePath(args[1], UserHandle.USER_OWNER);
+                    return displayPackageFilePath(args[1], UserHandle.USER_SYSTEM);
                 }
             }
             return 1;
@@ -767,7 +767,7 @@
     }
 
     private int runPath() {
-        int userId = UserHandle.USER_OWNER;
+        int userId = UserHandle.USER_SYSTEM;
         String option = nextOption();
         if (option != null && option.equals("--user")) {
             String optionData = nextOptionData();
@@ -1650,7 +1650,7 @@
     }
 
     private int runClear() {
-        int userId = UserHandle.USER_OWNER;
+        int userId = UserHandle.USER_SYSTEM;
         String option = nextOption();
         if (option != null && option.equals("--user")) {
             String optionData = nextOptionData();
@@ -1722,7 +1722,7 @@
     }
 
     private int runSetEnabledSetting(int state) {
-        int userId = UserHandle.USER_OWNER;
+        int userId = UserHandle.USER_SYSTEM;
         String option = nextOption();
         if (option != null && option.equals("--user")) {
             String optionData = nextOptionData();
@@ -1771,7 +1771,7 @@
     }
 
     private int runSetHiddenSetting(boolean state) {
-        int userId = UserHandle.USER_OWNER;
+        int userId = UserHandle.USER_SYSTEM;
         String option = nextOption();
         if (option != null && option.equals("--user")) {
             String optionData = nextOptionData();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 11effd0..a1f9743 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6277,6 +6277,15 @@
         */
        public static final String FORCE_ALLOW_ON_EXTERNAL = "force_allow_on_external";
 
+        /**
+         * Whether any activity can be resized. When this is true, any
+         * activity, regardless of manifest values, can be resized for multi-window.
+         * (0 = false, 1 = true)
+         * @hide
+         */
+        public static final String DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES
+                = "force_resizable_activities";
+
        /**
         * Whether user has enabled development settings.
         */
diff --git a/opengl/java/android/opengl/GLES31.java b/opengl/java/android/opengl/GLES31.java
index 3cbaa60..805930e 100644
--- a/opengl/java/android/opengl/GLES31.java
+++ b/opengl/java/android/opengl/GLES31.java
@@ -24,9 +24,14 @@
 
     public static final int GL_VERTEX_SHADER_BIT                            = 0x00000001;
     public static final int GL_FRAGMENT_SHADER_BIT                          = 0x00000002;
+    public static final int GL_COMPUTE_SHADER_BIT                           = 0x00000020;
+    public static final int GL_ALL_SHADER_BITS                              = -1; // 0xFFFFFFFF
+
+    public static final int GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT              = 0x00000001;
+    public static final int GL_ELEMENT_ARRAY_BARRIER_BIT                    = 0x00000002;
     public static final int GL_UNIFORM_BARRIER_BIT                          = 0x00000004;
     public static final int GL_TEXTURE_FETCH_BARRIER_BIT                    = 0x00000008;
-    public static final int GL_COMPUTE_SHADER_BIT                           = 0x00000020;
+    public static final int GL_SHADER_IMAGE_ACCESS_BARRIER_BIT              = 0x00000020;
     public static final int GL_COMMAND_BARRIER_BIT                          = 0x00000040;
     public static final int GL_PIXEL_BUFFER_BARRIER_BIT                     = 0x00000080;
     public static final int GL_TEXTURE_UPDATE_BARRIER_BIT                   = 0x00000100;
@@ -35,7 +40,8 @@
     public static final int GL_TRANSFORM_FEEDBACK_BARRIER_BIT               = 0x00000800;
     public static final int GL_ATOMIC_COUNTER_BARRIER_BIT                   = 0x00001000;
     public static final int GL_SHADER_STORAGE_BARRIER_BIT                   = 0x00002000;
-    public static final int GL_ALL_SHADER_BITS                              = -1; // 0xFFFFFFFF
+    public static final int GL_ALL_BARRIER_BITS                             = -1; // 0xFFFFFFFF
+
 
     public static final int GL_TEXTURE_WIDTH                                = 0x1000;
     public static final int GL_TEXTURE_HEIGHT                               = 0x1001;
diff --git a/packages/DocumentsUI/testing/TestDocumentsProvider/Android.mk b/packages/DocumentsUI/testing/TestDocumentsProvider/Android.mk
deleted file mode 100644
index 8baadba..0000000
--- a/packages/DocumentsUI/testing/TestDocumentsProvider/Android.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := TestDocumentsProvider
-LOCAL_CERTIFICATE := platform
-LOCAL_MODULE_TAGS := tests
-#LOCAL_SDK_VERSION := current
-
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_PACKAGE)
diff --git a/packages/DocumentsUI/testing/TestDocumentsProvider/AndroidManifest.xml b/packages/DocumentsUI/testing/TestDocumentsProvider/AndroidManifest.xml
deleted file mode 100644
index 66988a1..0000000
--- a/packages/DocumentsUI/testing/TestDocumentsProvider/AndroidManifest.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.documentsui.testing">
-    <application>
-        <provider android:name="TestDocumentsProvider"
-                android:authorities="com.android.documentsui.testing"
-                android:exported="true"
-                android:grantUriPermissions="true"
-                android:permission="android.permission.MANAGE_DOCUMENTS">
-            <intent-filter>
-                <action android:name="android.content.action.DOCUMENTS_PROVIDER" />
-            </intent-filter>
-        </provider>
-    </application>
-</manifest>
diff --git a/packages/DocumentsUI/testing/TestDocumentsProvider/src/com/android/documentsui/testing/TestDocumentsProvider.java b/packages/DocumentsUI/testing/TestDocumentsProvider/src/com/android/documentsui/testing/TestDocumentsProvider.java
deleted file mode 100644
index 63ff0de..0000000
--- a/packages/DocumentsUI/testing/TestDocumentsProvider/src/com/android/documentsui/testing/TestDocumentsProvider.java
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * Copyright (C) 2015 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.documentsui.testing;
-
-import android.database.Cursor;
-import android.database.MatrixCursor;
-import android.database.MatrixCursor.RowBuilder;
-import android.os.AsyncTask;
-import android.os.CancellationSignal;
-import android.os.ParcelFileDescriptor;
-import android.provider.DocumentsContract.Document;
-import android.provider.DocumentsContract.Root;
-import android.provider.DocumentsProvider;
-import android.util.Log;
-
-import java.io.ByteArrayOutputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class TestDocumentsProvider extends DocumentsProvider {
-    private static final String TAG = "TestDocumentsProvider";
-
-    private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
-            Root.COLUMN_ROOT_ID,
-            Root.COLUMN_FLAGS,
-            Root.COLUMN_ICON,
-            Root.COLUMN_TITLE,
-            Root.COLUMN_DOCUMENT_ID, Root.COLUMN_AVAILABLE_BYTES,
-    };
-
-    private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] {
-            Document.COLUMN_DOCUMENT_ID,
-            Document.COLUMN_MIME_TYPE,
-            Document.COLUMN_DISPLAY_NAME,
-            Document.COLUMN_LAST_MODIFIED,
-            Document.COLUMN_FLAGS,
-            Document.COLUMN_SIZE,
-    };
-
-    private static String[] resolveRootProjection(String[] projection) {
-        return projection != null ? projection : DEFAULT_ROOT_PROJECTION;
-    }
-
-    private static String[] resolveDocumentProjection(String[] projection) {
-        return projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION;
-    }
-
-    @Override
-    public boolean onCreate() {
-        resetRoots();
-        return true;
-    }
-
-    @Override
-    public Cursor queryRoots(String[] projection) throws FileNotFoundException {
-        final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
-
-        RowBuilder row = result.newRow();
-        row.add(Root.COLUMN_ROOT_ID, "local");
-        row.add(Root.COLUMN_FLAGS, Root.FLAG_LOCAL_ONLY);
-        row.add(Root.COLUMN_TITLE, "TEST-Local");
-        row.add(Root.COLUMN_SUMMARY, "TEST-LocalSummary");
-        row.add(Root.COLUMN_DOCUMENT_ID, "doc:local");
-
-        row = result.newRow();
-        row.add(Root.COLUMN_ROOT_ID, "create");
-        row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_IS_CHILD);
-        row.add(Root.COLUMN_TITLE, "TEST-Create");
-        row.add(Root.COLUMN_DOCUMENT_ID, "doc:create");
-
-        return result;
-    }
-
-    private Map<String, Doc> mDocs = new HashMap<>();
-
-    private Doc mLocalRoot;
-    private Doc mCreateRoot;
-
-    private Doc buildDoc(String docId, String displayName, String mimeType) {
-        final Doc doc = new Doc();
-        doc.docId = docId;
-        doc.displayName = displayName;
-        doc.mimeType = mimeType;
-        mDocs.put(doc.docId, doc);
-        return doc;
-    }
-
-    public void resetRoots() {
-        Log.d(TAG, "resetRoots()");
-
-        mDocs.clear();
-
-        mLocalRoot = buildDoc("doc:local", null, Document.MIME_TYPE_DIR);
-
-        mCreateRoot = buildDoc("doc:create", null, Document.MIME_TYPE_DIR);
-        mCreateRoot.flags = Document.FLAG_DIR_SUPPORTS_CREATE;
-
-        {
-            Doc file1 = buildDoc("doc:file1", "FILE1", "mime1/file1");
-            file1.contents = "fileone".getBytes();
-            file1.flags = Document.FLAG_SUPPORTS_WRITE;
-            mLocalRoot.children.add(file1);
-            mCreateRoot.children.add(file1);
-        }
-
-        {
-            Doc file2 = buildDoc("doc:file2", "FILE2", "mime2/file2");
-            file2.contents = "filetwo".getBytes();
-            file2.flags = Document.FLAG_SUPPORTS_WRITE;
-            mLocalRoot.children.add(file2);
-            mCreateRoot.children.add(file2);
-        }
-
-        Doc dir1 = buildDoc("doc:dir1", "DIR1", Document.MIME_TYPE_DIR);
-        mLocalRoot.children.add(dir1);
-
-        {
-            Doc file3 = buildDoc("doc:file3", "FILE3", "mime3/file3");
-            file3.contents = "filethree".getBytes();
-            file3.flags = Document.FLAG_SUPPORTS_WRITE;
-            dir1.children.add(file3);
-        }
-
-        Doc dir2 = buildDoc("doc:dir2", "DIR2", Document.MIME_TYPE_DIR);
-        mCreateRoot.children.add(dir2);
-
-        {
-            Doc file4 = buildDoc("doc:file4", "FILE4", "mime4/file4");
-            file4.contents = "filefour".getBytes();
-            file4.flags = Document.FLAG_SUPPORTS_WRITE;
-            dir2.children.add(file4);
-        }
-    }
-
-    private static class Doc {
-        public String docId;
-        public int flags;
-        public String displayName;
-        public long size;
-        public String mimeType;
-        public long lastModified;
-        public byte[] contents;
-        public List<Doc> children = new ArrayList<>();
-
-        public void include(MatrixCursor result) {
-            final RowBuilder row = result.newRow();
-            row.add(Document.COLUMN_DOCUMENT_ID, docId);
-            row.add(Document.COLUMN_DISPLAY_NAME, displayName);
-            row.add(Document.COLUMN_SIZE, size);
-            row.add(Document.COLUMN_MIME_TYPE, mimeType);
-            row.add(Document.COLUMN_FLAGS, flags);
-            row.add(Document.COLUMN_LAST_MODIFIED, lastModified);
-        }
-    }
-
-    @Override
-    public boolean isChildDocument(String parentDocumentId, String documentId) {
-        for (Doc doc : mDocs.get(parentDocumentId).children) {
-            if (doc.docId.equals(documentId)) {
-                return true;
-            }
-            if (Document.MIME_TYPE_DIR.equals(doc.mimeType)) {
-                return isChildDocument(doc.docId, documentId);
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public String createDocument(String parentDocumentId, String mimeType, String displayName)
-            throws FileNotFoundException {
-        final String docId = "doc:" + System.currentTimeMillis();
-        final Doc doc = buildDoc(docId, displayName, mimeType);
-        doc.flags = Document.FLAG_SUPPORTS_WRITE | Document.FLAG_SUPPORTS_RENAME;
-        mDocs.get(parentDocumentId).children.add(doc);
-        return docId;
-    }
-
-    @Override
-    public String renameDocument(String documentId, String displayName)
-            throws FileNotFoundException {
-        mDocs.get(documentId).displayName = displayName;
-        return null;
-    }
-
-    @Override
-    public void deleteDocument(String documentId) throws FileNotFoundException {
-        mDocs.remove(documentId);
-        for (Doc doc : mDocs.values()) {
-            doc.children.remove(documentId);
-        }
-    }
-
-    @Override
-    public Cursor queryDocument(String documentId, String[] projection)
-            throws FileNotFoundException {
-        final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
-        mDocs.get(documentId).include(result);
-        return result;
-    }
-
-    @Override
-    public Cursor queryChildDocuments(String parentDocumentId, String[] projection,
-            String sortOrder) throws FileNotFoundException {
-        final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
-        for (Doc doc : mDocs.get(parentDocumentId).children) {
-            doc.include(result);
-        }
-        return result;
-    }
-
-    @Override
-    public ParcelFileDescriptor openDocument(String documentId, String mode,
-            CancellationSignal signal) throws FileNotFoundException {
-        final Doc doc = mDocs.get(documentId);
-        if (doc == null) {
-            throw new FileNotFoundException();
-        }
-        final ParcelFileDescriptor[] pipe;
-        try {
-            pipe = ParcelFileDescriptor.createPipe();
-        } catch (IOException e) {
-            throw new IllegalStateException(e);
-        }
-        if (mode.contains("w")) {
-            new AsyncTask<Void, Void, Void>() {
-                @Override
-                protected Void doInBackground(Void... params) {
-                    synchronized (doc) {
-                        try {
-                            final InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(
-                                    pipe[0]);
-                            doc.contents = readFullyNoClose(is);
-                            is.close();
-                            doc.notifyAll();
-                        } catch (IOException e) {
-                            Log.w(TAG, "Failed to stream", e);
-                        }
-                    }
-                    return null;
-                }
-            }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
-            return pipe[1];
-        } else {
-            new AsyncTask<Void, Void, Void>() {
-                @Override
-                protected Void doInBackground(Void... params) {
-                    synchronized (doc) {
-                        try {
-                            final OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(
-                                    pipe[1]);
-                            while (doc.contents == null) {
-                                doc.wait();
-                            }
-                            os.write(doc.contents);
-                            os.close();
-                        } catch (IOException e) {
-                            Log.w(TAG, "Failed to stream", e);
-                        } catch (InterruptedException e) {
-                            Log.w(TAG, "Interuppted", e);
-                        }
-                    }
-                    return null;
-                }
-            }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
-            return pipe[0];
-        }
-    }
-
-    private static byte[] readFullyNoClose(InputStream in) throws IOException {
-        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
-        byte[] buffer = new byte[1024];
-        int count;
-        while ((count = in.read(buffer)) != -1) {
-            bytes.write(buffer, 0, count);
-        }
-        return bytes.toByteArray();
-    }
-}
diff --git a/packages/DocumentsUI/tests/Android.mk b/packages/DocumentsUI/tests/Android.mk
index cf486b1..2a540d4 100644
--- a/packages/DocumentsUI/tests/Android.mk
+++ b/packages/DocumentsUI/tests/Android.mk
@@ -17,4 +17,3 @@
 
 include $(BUILD_PACKAGE)
 
-include $(LOCAL_PATH)/../testing/TestDocumentsProvider/Android.mk
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index bae8017..07c59a9 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -136,7 +136,7 @@
     <integer name="touch_acceptance_delay">700</integer>
 
     <!-- The duration in seconds to wait before the dismiss buttons are shown. -->
-    <integer name="recents_task_bar_dismiss_delay_seconds">1</integer>
+    <integer name="recents_task_bar_dismiss_delay_seconds">1000</integer>
 
     <!-- The min animation duration for animating views that are currently visible. -->
     <integer name="recents_filter_animate_current_views_duration">250</integer>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 3a5680d..7c86f96 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -999,9 +999,7 @@
     <!-- Screen pinning dialog title. -->
     <string name="screen_pinning_title">Screen is pinned</string>
     <!-- Screen pinning dialog description. -->
-    <string name="screen_pinning_description">This keeps it in view until you unpin. Touch and hold Back and Overview at the same time to unpin.</string>
-    <!-- Screen pinning dialog description when in accessibility mode. -->
-    <string name="screen_pinning_description_accessible">This keeps it in view until you unpin. Touch and hold Overview to unpin.</string>
+    <string name="screen_pinning_description">This keeps it in view until you unpin. Touch and hold Back to unpin.</string>
     <!-- Screen pinning positive response. -->
     <string name="screen_pinning_positive">Got it</string>
     <!-- Screen pinning negative response. -->
diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
index 1d0bfe7..9a4cd93 100644
--- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
@@ -27,4 +27,9 @@
     void cancelPreloadingRecents();
     void showNextAffiliatedTask();
     void showPrevAffiliatedTask();
+
+    /**
+     * Docks the top-most task and opens recents.
+     */
+    void dockTopTask();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index cdb6b93..6668df9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -37,6 +37,8 @@
             public static final boolean EnableTaskFiltering = false;
             // Enables dismiss-all
             public static final boolean EnableDismissAll = false;
+            // Enables fast-toggling
+            public static final boolean EnableFastToggleRecents = false;
             // Enables the thumbnail alpha on the front-most task
             public static final boolean EnableThumbnailAlphaOnFrontmost = false;
             // This disables the search bar integration
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index c216f97..9400108 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -284,6 +284,11 @@
     }
 
     @Override
+    public void dockTopTask() {
+        mImpl.dockTopTask();
+    }
+
+    @Override
     public void showNextAffiliatedTask() {
         mImpl.showNextAffiliatedTask();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index c416967..0adad85 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -32,6 +32,7 @@
 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;
@@ -41,16 +42,21 @@
 import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationStartedEvent;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
+import com.android.systemui.recents.events.activity.IterateRecentsEvent;
 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.events.ui.DismissTaskEvent;
+import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
 import com.android.systemui.recents.events.ui.ResizeTaskEvent;
 import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
 import com.android.systemui.recents.events.ui.UserInteractionEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
+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;
 import com.android.systemui.recents.model.RecentsPackageMonitor;
@@ -69,6 +75,9 @@
  */
 public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks {
 
+    private final static String TAG = "RecentsActivity";
+    private final static boolean DEBUG = false;
+
     public final static int EVENT_BUS_PRIORITY = Recents.EVENT_BUS_PRIORITY + 1;
 
     RecentsConfiguration mConfig;
@@ -96,6 +105,14 @@
     // Runnable to be executed after we paused ourselves
     Runnable mAfterPauseRunnable;
 
+    // The trigger to automatically launch the current task
+    DozeTrigger mIterateTrigger = new DozeTrigger(500, new Runnable() {
+        @Override
+        public void run() {
+            boolean dismissed = dismissRecentsToFocusedTask(false);
+        }
+    });
+
     /**
      * A common Runnable to finish Recents either by calling finish() (with a custom animation) or
      * launching Home with some ActivityOptions.  Generally we always launch home when we exit
@@ -244,7 +261,24 @@
         MetricsLogger.histogram(this, "overview_task_count", taskCount);
     }
 
-    /** Dismisses recents if we are already visible and the intent is to toggle the recents view */
+    /**
+     * Dismisses recents if we are already visible and the intent is to toggle the recents view.
+     */
+    boolean dismissRecentsToFocusedTask(boolean checkFilteredStackState) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+            // If we currently have filtered stacks, then unfilter those first
+            if (checkFilteredStackState &&
+                    mRecentsView.unfilterFilteredStacks()) return true;
+            // If we have a focused Task, launch that Task now
+            if (mRecentsView.launchFocusedTask()) return true;
+        }
+        return false;
+    }
+
+    /**
+     * Dismisses recents if we are already visible and the intent is to toggle the recents view.
+     */
     boolean dismissRecentsToFocusedTaskOrHome(boolean checkFilteredStackState) {
         RecentsActivityLaunchState launchState = mConfig.getLaunchState();
         SystemServicesProxy ssp = Recents.getSystemServices();
@@ -390,6 +424,11 @@
             mRecentsView.post(mAfterPauseRunnable);
             mAfterPauseRunnable = null;
         }
+
+        if (Constants.DebugFlags.App.EnableFastToggleRecents) {
+            // Stop the fast-toggle dozer
+            mIterateTrigger.stopDozing();
+        }
     }
 
     @Override
@@ -467,22 +506,27 @@
                 if (event.getRepeatCount() <= 0 || hasRepKeyTimeElapsed) {
                     // Focus the next task in the stack
                     final boolean backward = event.isShiftPressed();
-                    mRecentsView.focusNextTask(!backward);
+                    if (backward) {
+                        EventBus.getDefault().send(new FocusPreviousTaskViewEvent());
+                    } else {
+                        EventBus.getDefault().send(new FocusNextTaskViewEvent());
+                    }
                     mLastTabKeyEventTime = SystemClock.elapsedRealtime();
                 }
                 return true;
             }
             case KeyEvent.KEYCODE_DPAD_UP: {
-                mRecentsView.focusNextTask(true);
+                EventBus.getDefault().send(new FocusNextTaskViewEvent());
                 return true;
             }
             case KeyEvent.KEYCODE_DPAD_DOWN: {
-                mRecentsView.focusNextTask(false);
+                EventBus.getDefault().send(new FocusPreviousTaskViewEvent());
                 return true;
             }
             case KeyEvent.KEYCODE_DEL:
             case KeyEvent.KEYCODE_FORWARD_DEL: {
-                mRecentsView.dismissFocusedTask();
+                EventBus.getDefault().send(new DismissFocusedTaskViewEvent());
+
                 // Keep track of deletions by keyboard
                 MetricsLogger.histogram(this, "overview_task_dismissed_source",
                         Constants.Metrics.DismissSourceKeyboard);
@@ -542,6 +586,16 @@
         dismissRecentsToFocusedTaskOrHome(true /* checkFilteredStackState */);
     }
 
+    public final void onBusEvent(IterateRecentsEvent event) {
+        // Focus the next task
+        EventBus.getDefault().send(new FocusNextTaskViewEvent());
+        mIterateTrigger.poke();
+    }
+
+    public final void onBusEvent(UserInteractionEvent event) {
+        mIterateTrigger.stopDozing();
+    }
+
     public final void onBusEvent(HideRecentsEvent event) {
         if (event.triggeredFromAltTab) {
             // If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app
@@ -558,7 +612,7 @@
         // Try and start the enter animation (or restart it on configuration changed)
         ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null);
         ViewAnimation.TaskViewEnterContext ctx = new ViewAnimation.TaskViewEnterContext(t);
-        mRecentsView.startEnterRecentsAnimation(ctx);
+        ctx.postAnimationTrigger.increment();
         if (mSearchWidgetInfo != null) {
             ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
                 @Override
@@ -570,6 +624,20 @@
                 }
             });
         }
+        ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
+            @Override
+            public void run() {
+                // If we are not launching with alt-tab and fast-toggle is enabled, then start
+                // the dozer now
+                RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+                if (Constants.DebugFlags.App.EnableFastToggleRecents &&
+                        !launchState.launchedWithAltTab) {
+                    mIterateTrigger.startDozing();
+                }
+            }
+        });
+        mRecentsView.startEnterRecentsAnimation(ctx);
+        ctx.postAnimationTrigger.decrement();
     }
 
     public final void onBusEvent(AppWidgetProviderChangedEvent event) {
@@ -589,7 +657,7 @@
         MetricsLogger.count(this, "overview_app_info", 1);
     }
 
-    public final void onBusEvent(DismissTaskEvent event) {
+    public final void onBusEvent(DismissTaskViewEvent event) {
         // Remove any stored data from the loader
         RecentsTaskLoader loader = Recents.getTaskLoader();
         loader.deleteTaskData(event.task, false);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
index e2e0e918..76b666f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -56,7 +56,7 @@
 
     /** Returns whether the status bar scrim should be animated when shown for the first time. */
     public boolean shouldAnimateStatusBarScrim() {
-        return launchedFromHome;
+        return true;
     }
 
     /** Returns whether the status bar scrim should be visible. */
@@ -72,6 +72,6 @@
     /** Returns whether the nav bar scrim should be visible. */
     public boolean hasNavBarScrim() {
         // Only show the scrim if we have recent tasks, and if the nav bar is not transposed
-        return !launchedWithNoRecentTasks && mConfig.hasTransposedNavBar;
+        return !launchedWithNoRecentTasks && !mConfig.hasTransposedNavBar;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 07c7897..2c8937a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -40,6 +40,7 @@
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationStartedEvent;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
+import com.android.systemui.recents.events.activity.IterateRecentsEvent;
 import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
@@ -265,26 +266,38 @@
         mTriggeredFromAltTab = false;
 
         try {
-            // If the user has toggled it too quickly, then just eat up the event here (it's better
-            // than showing a janky screenshot).
-            // NOTE: Ideally, the screenshot mechanism would take the window transform into account
-            if ((SystemClock.elapsedRealtime() - mLastToggleTime) < sMinToggleDelay) {
-                return;
-            }
-
-            // If Recents is the front most activity, then we should just communicate with it
-            // directly to launch the first task or dismiss itself
             SystemServicesProxy ssp = Recents.getSystemServices();
             ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
             MutableBoolean isTopTaskHome = new MutableBoolean(true);
             if (topTask != null && ssp.isRecentsTopMost(topTask, isTopTaskHome)) {
-                // Notify recents to toggle itself
-                EventBus.getDefault().post(new ToggleRecentsEvent());
-                mLastToggleTime = SystemClock.elapsedRealtime();
+                if (Constants.DebugFlags.App.EnableFastToggleRecents) {
+                    // Notify recents to move onto the next task
+                    EventBus.getDefault().post(new IterateRecentsEvent());
+                } else {
+                    // If the user has toggled it too quickly, then just eat up the event here (it's
+                    // better than showing a janky screenshot).
+                    // NOTE: Ideally, the screenshot mechanism would take the window transform into
+                    // account
+                    if ((SystemClock.elapsedRealtime() - mLastToggleTime) < sMinToggleDelay) {
+                        return;
+                    }
+
+                    EventBus.getDefault().post(new ToggleRecentsEvent());
+                    mLastToggleTime = SystemClock.elapsedRealtime();
+                }
                 return;
             } else {
+                // If the user has toggled it too quickly, then just eat up the event here (it's
+                // better than showing a janky screenshot).
+                // NOTE: Ideally, the screenshot mechanism would take the window transform into
+                // account
+                if ((SystemClock.elapsedRealtime() - mLastToggleTime) < sMinToggleDelay) {
+                    return;
+                }
+
                 // Otherwise, start the recents activity
                 startRecentsActivity(topTask, isTopTaskHome.value);
+                mLastToggleTime = SystemClock.elapsedRealtime();
             }
         } catch (ActivityNotFoundException e) {
             Console.logRawError("Failed to launch RecentAppsIntent", e);
@@ -405,6 +418,16 @@
         showRelativeAffiliatedTask(false);
     }
 
+    public void dockTopTask() {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
+        if (topTask != null && !ssp.isInHomeStack(topTask.id)) {
+            ssp.moveTaskToDockedStack(topTask.id,
+                    ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT);
+            showRecents(false /* triggeredFromAltTab */);
+        }
+    }
+
     /**
      * Returns the preloaded load plan and invalidates it.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
index 31ee8ad..28299d3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
@@ -234,14 +234,6 @@
         dismissAllowingStateLoss();
         mRecentsActivity.dismissRecentsToHomeWithoutTransitionAnimation();
 
-        // In debug mode, we force all task to be resizeable regardless of the
-        // current app configuration.
-        for (int i = additionalTasks; i >= 0; --i) {
-            if (mTasks[i] != null) {
-                ssp.setTaskResizeable(mTasks[i].key.id);
-            }
-        }
-
         // Show tasks as they might not be currently visible - beginning with the oldest so that
         // the focus ends on the selected one.
         for (int i = additionalTasks; i >= 0; --i) {
@@ -277,8 +269,7 @@
         if (mTasks[0].key.stackId != DOCKED_STACK_ID) {
             int taskId = mTasks[0].key.id;
             SystemServicesProxy ssp = Recents.getSystemServices();
-            ssp.setTaskResizeable(taskId);
-            ssp.dockTask(taskId, createMode);
+            ssp.startTaskInDockedMode(taskId, createMode);
             mRecentsView.launchTask(mTasks[0], null, DOCKED_STACK_ID);
         } else {
             Toast.makeText(getContext(), "Already docked", Toast.LENGTH_SHORT);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 231843e..10075bc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -214,11 +214,8 @@
                         .setVisibility(View.INVISIBLE);
             }
 
-            final int description = mAccessibilityService.isEnabled()
-                    ? R.string.screen_pinning_description_accessible
-                    : R.string.screen_pinning_description;
             ((TextView) mLayout.findViewById(R.id.screen_pinning_description))
-                    .setText(description);
+                    .setText(R.string.screen_pinning_description);
             final int backBgVisibility =
                     mAccessibilityService.isEnabled() ? View.INVISIBLE : View.VISIBLE;
             mLayout.findViewById(R.id.screen_pinning_back_bg).setVisibility(backBgVisibility);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
index fec0fc5..deae4c8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
@@ -200,7 +200,8 @@
  */
 public class EventBus extends BroadcastReceiver {
 
-    public static final String TAG = "EventBus";
+    private static final String TAG = "EventBus";
+    private static final boolean DEBUG_TRACE_ALL = false;
 
     /**
      * An event super class that allows us to track internal event state across subscriber
@@ -277,9 +278,6 @@
     // The default priority of all subscribers
     private static final int DEFAULT_SUBSCRIBER_PRIORITY = 1;
 
-    // Used for debugging everything
-    private static final boolean DEBUG_TRACE_ALL = false;
-
     // Orders the handlers by priority and registration time
     private static final Comparator<EventHandler> EVENT_HANDLER_COMPARATOR = new Comparator<EventHandler>() {
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/IterateRecentsEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/IterateRecentsEvent.java
new file mode 100644
index 0000000..f7b2706
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/IterateRecentsEvent.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 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.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent when the user taps on the Overview button to iterate to the next item in the
+ * Recents list.
+ */
+public class IterateRecentsEvent extends EventBus.Event {
+    // Simple event
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java
similarity index 89%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskEvent.java
rename to packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java
index 12e5d3d..968890a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java
@@ -23,12 +23,12 @@
 /**
  * This is sent when a {@link TaskView} has been dismissed.
  */
-public class DismissTaskEvent extends EventBus.Event {
+public class DismissTaskViewEvent extends EventBus.Event {
 
     public final Task task;
     public final TaskView taskView;
 
-    public DismissTaskEvent(Task task, TaskView taskView) {
+    public DismissTaskViewEvent(Task task, TaskView taskView) {
         this.task = task;
         this.taskView = taskView;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/DismissFocusedTaskViewEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/DismissFocusedTaskViewEvent.java
new file mode 100644
index 0000000..9f3e9d5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/DismissFocusedTaskViewEvent.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 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.events.ui.focus;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Dismisses the currently focused task view.
+ */
+public class DismissFocusedTaskViewEvent extends EventBus.Event {
+    // Simple event
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java
new file mode 100644
index 0000000..171ab5e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 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.events.ui.focus;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Focuses the next task view in the stack.
+ */
+public class FocusNextTaskViewEvent extends EventBus.Event {
+    // Simple event
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusPreviousTaskViewEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusPreviousTaskViewEvent.java
new file mode 100644
index 0000000..22469e7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusPreviousTaskViewEvent.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 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.events.ui.focus;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Focuses the previous task view in the stack.
+ */
+public class FocusPreviousTaskViewEvent extends EventBus.Event {
+    // Simple event
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
index 735f79f..336d2db 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
@@ -19,8 +19,8 @@
 import android.os.Handler;
 
 /**
- * A dozer is a class that fires a trigger after it falls asleep.  You can occasionally poke it to
- * wake it up, but it will fall asleep if left untouched.
+ * A dozer is a class that fires a trigger after it falls asleep.
+ * You can occasionally poke the trigger to wake it up, but it will fall asleep if left untouched.
  */
 public class DozeTrigger {
 
@@ -28,7 +28,7 @@
 
     boolean mIsDozing;
     boolean mHasTriggered;
-    int mDozeDurationSeconds;
+    int mDozeDurationMilliseconds;
     Runnable mSleepRunnable;
 
     // Sleep-runnable
@@ -41,9 +41,9 @@
         }
     };
 
-    public DozeTrigger(int dozeDurationSeconds, Runnable sleepRunnable) {
+    public DozeTrigger(int dozeDurationMilliseconds, Runnable sleepRunnable) {
         mHandler = new Handler();
-        mDozeDurationSeconds = dozeDurationSeconds;
+        mDozeDurationMilliseconds = dozeDurationMilliseconds;
         mSleepRunnable = sleepRunnable;
     }
 
@@ -69,7 +69,7 @@
     /** Poke this dozer to wake it up for a little bit. */
     void forcePoke() {
         mHandler.removeCallbacks(mDozeRunnable);
-        mHandler.postDelayed(mDozeRunnable, mDozeDurationSeconds * 1000);
+        mHandler.postDelayed(mDozeRunnable, mDozeDurationMilliseconds);
         mIsDozing = true;
     }
 
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 a51e475..221af15 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -266,17 +266,6 @@
         return null;
     }
 
-    /** Allow a task to resize. */
-    public void setTaskResizeable(int taskId) {
-        if (mIam == null) return;
-
-        try {
-            mIam.setTaskResizeable(taskId, true);
-        } catch (RemoteException e) {
-            e.printStackTrace();
-        }
-    }
-
     /**
      * Resizes the given task to the new bounds.
      */
@@ -290,8 +279,8 @@
         }
     }
 
-    /** Docks a task to the side of the screen. */
-    public void dockTask(int taskId, int createMode) {
+    /** Docks a task to the side of the screen and starts it. */
+    public void startTaskInDockedMode(int taskId, int createMode) {
         if (mIam == null) return;
 
         try {
@@ -301,6 +290,17 @@
         }
     }
 
+    /** Docks an already resumed task to the side of the screen. */
+    public void moveTaskToDockedStack(int taskId, int createMode) {
+        if (mIam == null) return;
+
+        try {
+            mIam.moveTaskToDockedStack(taskId, createMode, true /* onTop */);
+        } catch (RemoteException e) {
+            e.printStackTrace();
+        }
+    }
+
     /** Returns the focused stack id. */
     public int getFocusedStack() {
         if (mIam == null) return -1;
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 7f618e3..d5d0713 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -49,7 +49,7 @@
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
-import com.android.systemui.recents.events.ui.DismissTaskEvent;
+import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragDockStateChangedEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
@@ -69,6 +69,7 @@
 public class RecentsView extends FrameLayout implements TaskStackView.TaskStackViewCallbacks {
 
     private static final String TAG = "RecentsView";
+    private static final boolean DEBUG = false;
 
     private static final boolean ADD_HEADER_BITMAP = true;
 
@@ -404,22 +405,6 @@
         return super.verifyDrawable(who);
     }
 
-    /** Focuses the next task in the first stack view */
-    public void focusNextTask(boolean forward) {
-        // Get the first stack view
-        if (mTaskStackView != null) {
-            mTaskStackView.focusNextTask(forward, true);
-        }
-    }
-
-    /** Dismisses the focused task. */
-    public void dismissFocusedTask() {
-        // Get the first stack view
-        if (mTaskStackView != null) {
-            mTaskStackView.dismissFocusedTask();
-        }
-    }
-
     /** Unfilters any filtered stacks */
     public boolean unfilterFilteredStacks() {
         if (mStacks != null) {
@@ -562,7 +547,7 @@
         // Disable any focused state before we draw the header
         // Upfront the processing of the thumbnail
         if (tv.isFocusedTask()) {
-            tv.unsetFocusedTask();
+            tv.setFocusedState(false, false /* animated */, false /* requestViewFocus */);
         }
         TaskViewTransform transform = new TaskViewTransform();
         transform = stackView.getStackAlgorithm().getStackTransform(tv.mTask, stackScroll,
@@ -682,7 +667,7 @@
                     } else {
                         // Dismiss the task and return the user to home if we fail to
                         // launch the task
-                        EventBus.getDefault().send(new DismissTaskEvent(task, tv));
+                        EventBus.getDefault().send(new DismissTaskViewEvent(task, tv));
                         if (mCb != null) {
                             mCb.onTaskLaunchFailed();
                         }
@@ -800,8 +785,7 @@
                 // Dock the new task if we are hovering over a valid dock state
                 if (event.dockState != TaskStack.DockState.NONE) {
                     SystemServicesProxy ssp = Recents.getSystemServices();
-                    ssp.setTaskResizeable(event.task.key.id);
-                    ssp.dockTask(event.task.key.id, event.dockState.createMode);
+                    ssp.startTaskInDockedMode(event.task.key.id, event.dockState.createMode);
                     launchTask(event.task, null, INVALID_STACK_ID);
                 }
             }
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 5928854..757e695 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -23,6 +23,8 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.os.Bundle;
+import android.os.SystemService;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -30,6 +32,7 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 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;
@@ -37,8 +40,11 @@
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.PackagesChangedEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
-import com.android.systemui.recents.events.ui.DismissTaskEvent;
+import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
 import com.android.systemui.recents.events.ui.UserInteractionEvent;
+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.DozeTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.Utilities;
@@ -60,6 +66,9 @@
         TaskView.TaskViewCallbacks, TaskStackViewScroller.TaskStackViewScrollerCallbacks,
         ViewPool.ViewPoolConsumer<TaskView, Task> {
 
+    private final static String TAG = "TaskStackView";
+    private final static boolean DEBUG = false;
+
     /** The TaskView callbacks */
     interface TaskStackViewCallbacks {
         public void onTaskViewClicked(TaskStackView stackView, TaskView tv, TaskStack stack, Task t,
@@ -80,14 +89,12 @@
     ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<>();
     DozeTrigger mUIDozeTrigger;
     int mFocusedTaskIndex = -1;
-    int mPrevAccessibilityFocusedIndex = -1;
     // Optimizations
     int mStackViewsAnimationDuration;
     boolean mStackViewsDirty = true;
     boolean mStackViewsClipDirty = true;
     boolean mAwaitingFirstLayout = true;
     boolean mStartEnterAnimationRequestedAfterLayout;
-    boolean mStartEnterAnimationCompleted;
     ViewAnimation.TaskViewEnterContext mStartEnterAnimationContext;
 
     Rect mTaskStackBounds = new Rect();
@@ -219,7 +226,6 @@
         mStackViewsDirty = true;
         mStackViewsClipDirty = true;
         mAwaitingFirstLayout = true;
-        mPrevAccessibilityFocusedIndex = -1;
         if (mUIDozeTrigger != null) {
             mUIDozeTrigger.stopDozing();
             mUIDozeTrigger.resetTrigger();
@@ -332,8 +338,6 @@
     /** Synchronizes the views with the model */
     boolean synchronizeStackViewsWithModel() {
         if (mStackViewsDirty) {
-            SystemServicesProxy ssp = Recents.getSystemServices();
-
             // Get all the task transforms
             ArrayList<Task> tasks = mStack.getTasks();
             float stackScroll = mStackScroller.getStackScroll();
@@ -344,8 +348,9 @@
             // Return all the invisible children to the pool
             mTmpTaskViewMap.clear();
             List<TaskView> taskViews = getTaskViews();
+            boolean wasLastFocusedTaskAnimated = false;
+            int lastFocusedTaskIndex = -1;
             int taskViewCount = taskViews.size();
-            boolean reaquireAccessibilityFocus = false;
             for (int i = taskViewCount - 1; i >= 0; i--) {
                 TaskView tv = taskViews.get(i);
                 Task task = tv.getTask();
@@ -353,8 +358,12 @@
                 if (visibleRange[1] <= taskIndex && taskIndex <= visibleRange[0]) {
                     mTmpTaskViewMap.put(task, tv);
                 } else {
+                    if (tv.isFocusedTask()) {
+                        wasLastFocusedTaskAnimated = tv.isFocusAnimated();
+                        lastFocusedTaskIndex = taskIndex;
+                        resetFocusedTask();
+                    }
                     mViewPool.returnViewToPool(tv);
-                    reaquireAccessibilityFocus |= (i == mPrevAccessibilityFocusedIndex);
                 }
             }
 
@@ -385,21 +394,14 @@
                 // Animate the task into place
                 tv.updateViewPropertiesToTaskTransform(mCurrentTaskTransforms.get(taskIndex),
                         mStackViewsAnimationDuration, mRequestUpdateClippingListener);
+            }
 
-                // Request accessibility focus on the next view if we removed the task
-                // that previously held accessibility focus
-                if (reaquireAccessibilityFocus) {
-                    taskViews = getTaskViews();
-                    taskViewCount = taskViews.size();
-                    if (taskViewCount > 0 && ssp.isTouchExplorationEnabled() &&
-                            mPrevAccessibilityFocusedIndex != -1) {
-                        TaskView atv = taskViews.get(taskViewCount - 1);
-                        int indexOfTask = mStack.indexOfTask(atv.getTask());
-                        if (mPrevAccessibilityFocusedIndex != indexOfTask) {
-                            tv.requestAccessibilityFocus();
-                            mPrevAccessibilityFocusedIndex = indexOfTask;
-                        }
-                    }
+            // Update the focus if the previous focused task was returned to the view pool
+            if (lastFocusedTaskIndex != -1) {
+                if (lastFocusedTaskIndex < visibleRange[1]) {
+                    setFocusedTask(visibleRange[1], false, wasLastFocusedTaskAnimated);
+                } else {
+                    setFocusedTask(visibleRange[0], false, wasLastFocusedTaskAnimated);
                 }
             }
 
@@ -473,118 +475,80 @@
         return mStackScroller;
     }
 
-    /** Focuses the task at the specified index in the stack */
-    void focusTask(int taskIndex, boolean scrollToNewPosition, final boolean animateFocusedState) {
-        // Return early if the task is already focused
-        if (taskIndex == mFocusedTaskIndex) return;
+    /**
+     * Sets the focused task to the provided (bounded taskIndex).
+     */
+    private void setFocusedTask(int taskIndex, boolean scrollToTask, final boolean animated) {
+        setFocusedTask(taskIndex, scrollToTask, animated, true);
+    }
 
-        if (0 <= taskIndex && taskIndex < mStack.getTaskCount()) {
-            mFocusedTaskIndex = taskIndex;
-            mPrevAccessibilityFocusedIndex = taskIndex;
+    /**
+     * Sets the focused task to the provided (bounded taskIndex).
+     */
+    private void setFocusedTask(int taskIndex, boolean scrollToTask, final boolean animated,
+                                final boolean requestViewFocus) {
+        // Find the next task to focus
+        int newFocusedTaskIndex = mStack.getTaskCount() > 0 ?
+                Math.max(0, Math.min(mStack.getTaskCount() - 1, taskIndex)) : -1;
+        final Task newFocusedTask = (newFocusedTaskIndex != -1) ?
+                mStack.getTasks().get(newFocusedTaskIndex) : null;
 
-            // Focus the view if possible, otherwise, focus the view after we scroll into position
-            final Task t = mStack.getTasks().get(mFocusedTaskIndex);
-            Runnable postScrollRunnable = new Runnable() {
+        // Reset the last focused task state if changed
+        if (mFocusedTaskIndex != -1) {
+            Task focusedTask = mStack.getTasks().get(mFocusedTaskIndex);
+            if (focusedTask != newFocusedTask) {
+                resetFocusedTask();
+            }
+        }
+
+        mFocusedTaskIndex = newFocusedTaskIndex;
+        if (mFocusedTaskIndex != -1) {
+            Runnable focusTaskRunnable = new Runnable() {
                 @Override
                 public void run() {
-                    TaskView tv = getChildViewForTask(t);
+                    TaskView tv = getChildViewForTask(newFocusedTask);
                     if (tv != null) {
-                        tv.setFocusedTask(animateFocusedState);
-                        tv.requestAccessibilityFocus();
+                        tv.setFocusedState(true, animated, requestViewFocus);
                     }
                 }
             };
 
-            // Scroll the view into position (just center it in the curve)
-            if (scrollToNewPosition) {
-                float newScroll = mLayoutAlgorithm.getStackScrollForTask(t) - 0.5f;
+            if (scrollToTask) {
+                // TODO: Center the newly focused task view
+                float newScroll = mLayoutAlgorithm.getStackScrollForTask(newFocusedTask) - 0.5f;
                 newScroll = mStackScroller.getBoundedStackScroll(newScroll);
-                mStackScroller.animateScroll(mStackScroller.getStackScroll(), newScroll, postScrollRunnable);
+                mStackScroller.animateScroll(mStackScroller.getStackScroll(), newScroll,
+                        focusTaskRunnable);
             } else {
-                if (postScrollRunnable != null) {
-                    postScrollRunnable.run();
-                }
+                focusTaskRunnable.run();
             }
-
         }
     }
 
     /**
-     * Ensures that there is a task focused, if nothing is focused, then we will use the task
-     * at the center of the visible stack.
+     * Sets the focused task relative to the currently focused task.
+     *
+     * @param animated determines whether to actually draw the highlight along with the change in
+     *                            focus.
      */
-    public boolean ensureFocusedTask(boolean findClosestToCenter) {
-        if (mFocusedTaskIndex < 0) {
-            List<TaskView> taskViews = getTaskViews();
-            int taskViewCount = taskViews.size();
-            if (findClosestToCenter) {
-                // If there is no task focused, then find the task that is closes to the center
-                // of the screen and use that as the currently focused task
-                int x = mLayoutAlgorithm.mStackRect.centerX();
-                int y = mLayoutAlgorithm.mStackRect.centerY();
-                for (int i = taskViewCount - 1; i >= 0; i--) {
-                    TaskView tv = taskViews.get(i);
-                    tv.getHitRect(mTmpRect);
-                    if (mTmpRect.contains(x, y)) {
-                        mFocusedTaskIndex = mStack.indexOfTask(tv.getTask());
-                        mPrevAccessibilityFocusedIndex = mFocusedTaskIndex;
-                        break;
-                    }
-                }
-            }
-            // If we can't find the center task, then use the front most index
-            if (mFocusedTaskIndex < 0 && taskViewCount > 0) {
-                TaskView tv = taskViews.get(taskViewCount - 1);
-                mFocusedTaskIndex = mStack.indexOfTask(tv.getTask());
-                mPrevAccessibilityFocusedIndex = mFocusedTaskIndex;
-            }
-        }
-        return mFocusedTaskIndex >= 0;
-    }
-
-    /**
-     * Focuses the next task in the stack.
-     * @param animateFocusedState determines whether to actually draw the highlight along with
-     *                            the change in focus, as well as whether to scroll to fit the
-     *                            task into view.
-     */
-    public void focusNextTask(boolean forward, boolean animateFocusedState) {
+    public void setRelativeFocusedTask(boolean forward, boolean animated) {
         // Find the next index to focus
-        int numTasks = mStack.getTaskCount();
-        if (numTasks == 0) return;
-
-        int direction = (forward ? -1 : 1);
-        int newIndex = mFocusedTaskIndex + direction;
-        if (newIndex >= 0 && newIndex <= (numTasks - 1)) {
-            newIndex = Math.max(0, Math.min(numTasks - 1, newIndex));
-            focusTask(newIndex, true, animateFocusedState);
-        }
+        int newIndex = mFocusedTaskIndex + (forward ? -1 : 1);
+        setFocusedTask(newIndex, true, animated);
     }
 
-    /** Dismisses the focused task. */
-    public void dismissFocusedTask() {
-        // Return early if the focused task index is invalid
-        if (mFocusedTaskIndex < 0 || mFocusedTaskIndex >= mStack.getTaskCount()) {
-            mFocusedTaskIndex = -1;
-            return;
-        }
-
-        Task t = mStack.getTasks().get(mFocusedTaskIndex);
-        TaskView tv = getChildViewForTask(t);
-        tv.dismissTask();
-    }
-
-    /** Resets the focused task. */
+    /**
+     * Resets the focused task.
+     */
     void resetFocusedTask() {
-        if ((0 <= mFocusedTaskIndex) && (mFocusedTaskIndex < mStack.getTaskCount())) {
+        if (mFocusedTaskIndex != -1) {
             Task t = mStack.getTasks().get(mFocusedTaskIndex);
             TaskView tv = getChildViewForTask(t);
             if (tv != null) {
-                tv.unsetFocusedTask();
+                tv.setFocusedState(false, false /* animated */, false /* requestViewFocus */);
             }
         }
         mFocusedTaskIndex = -1;
-        mPrevAccessibilityFocusedIndex = -1;
     }
 
     @Override
@@ -609,12 +573,12 @@
         super.onInitializeAccessibilityNodeInfo(info);
         List<TaskView> taskViews = getTaskViews();
         int taskViewCount = taskViews.size();
-        if (taskViewCount > 1 && mPrevAccessibilityFocusedIndex != -1) {
+        if (taskViewCount > 1 && mFocusedTaskIndex != -1) {
             info.setScrollable(true);
-            if (mPrevAccessibilityFocusedIndex > 0) {
+            if (mFocusedTaskIndex > 0) {
                 info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
             }
-            if (mPrevAccessibilityFocusedIndex < mStack.getTaskCount() - 1) {
+            if (mFocusedTaskIndex < mStack.getTaskCount() - 1) {
                 info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
             }
         }
@@ -630,22 +594,14 @@
         if (super.performAccessibilityAction(action, arguments)) {
             return true;
         }
-        if (ensureFocusedTask(false)) {
-            switch (action) {
-                case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
-                    if (mPrevAccessibilityFocusedIndex > 0) {
-                        focusNextTask(true, false);
-                        return true;
-                    }
-                }
-                break;
-                case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
-                    if (mPrevAccessibilityFocusedIndex < mStack.getTaskCount() - 1) {
-                        focusNextTask(false, false);
-                        return true;
-                    }
-                }
-                break;
+        switch (action) {
+            case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
+                setRelativeFocusedTask(true, false /* animated */);
+                return true;
+            }
+            case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
+                setRelativeFocusedTask(false, false /* animated */);
+                return true;
             }
         }
         return false;
@@ -678,7 +634,7 @@
 
     /** Computes the stack and task rects */
     public void computeRects(int windowWidth, int windowHeight, Rect taskStackBounds,
-            boolean launchedWithAltTab, boolean launchedFromHome) {
+                             boolean launchedWithAltTab, boolean launchedFromHome) {
         // Compute the rects in the stack algorithm
         mLayoutAlgorithm.computeRects(windowWidth, windowHeight, taskStackBounds);
 
@@ -741,12 +697,12 @@
                 mTmpRect.setEmpty();
             }
             tv.measure(
-                MeasureSpec.makeMeasureSpec(
-                        mLayoutAlgorithm.mTaskRect.width() + mTmpRect.left + mTmpRect.right,
-                        MeasureSpec.EXACTLY),
-                MeasureSpec.makeMeasureSpec(
-                        mLayoutAlgorithm.mTaskRect.height() + mTmpRect.top + mTmpRect.bottom,
-                        MeasureSpec.EXACTLY));
+                    MeasureSpec.makeMeasureSpec(
+                            mLayoutAlgorithm.mTaskRect.width() + mTmpRect.left + mTmpRect.right,
+                            MeasureSpec.EXACTLY),
+                    MeasureSpec.makeMeasureSpec(
+                            mLayoutAlgorithm.mTaskRect.height() + mTmpRect.top + mTmpRect.bottom,
+                            MeasureSpec.EXACTLY));
         }
 
         setMeasuredDimension(width, height);
@@ -815,17 +771,16 @@
             mStartEnterAnimationContext = null;
         }
 
-        // When Alt-Tabbing, focus the previous task (but leave the animation until we finish the
-        // enter animation).
-        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
-        if (launchState.launchedWithAltTab) {
-            if (launchState.launchedFromAppWithThumbnail) {
-                focusTask(Math.max(0, mStack.getTaskCount() - 2), false,
-                        launchState.launchedHasConfigurationChanged);
-            } else {
-                focusTask(Math.max(0, mStack.getTaskCount() - 1), false,
-                        launchState.launchedHasConfigurationChanged);
-            }
+        // Set the task focused state without requesting view focus, and leave the focus animations
+        // until after the enter-animation
+        if (!Constants.DebugFlags.App.EnableFastToggleRecents && launchTargetTask != null) {
+            setFocusedTask(mStack.indexOfTask(launchTargetTask), false /* scrollToTask */,
+                    false /* animated */, false /* requestViewFocus */);
+        } else {
+            RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+            int taskOffset = launchState.launchedFromHome ? -1 : -2;
+            setFocusedTask(mStack.getTaskCount() + taskOffset, false /* scrollToTask */,
+                    false /* animated */, false /* requestViewFocus */);
         }
 
         // Start dozing
@@ -874,32 +829,17 @@
             ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
                 @Override
                 public void run() {
-                    mStartEnterAnimationCompleted = true;
                     // Poke the dozer to restart the trigger after the animation completes
                     mUIDozeTrigger.poke();
 
-                    SystemServicesProxy ssp = Recents.getSystemServices();
-                    List<TaskView> taskViews = getTaskViews();
-                    int taskViewCount = taskViews.size();
-                    if (taskViewCount > 0) {
-                        // Focus the first view if accessibility is enabled
-                        if (ssp.isTouchExplorationEnabled()) {
-                            TaskView tv = taskViews.get(taskViewCount - 1);
-                            tv.requestAccessibilityFocus();
-                            mPrevAccessibilityFocusedIndex = mStack.indexOfTask(tv.getTask());
-                        }
-                    }
-
-                    // Start the focus animation when alt-tabbing
-                    ArrayList<Task> tasks = mStack.getTasks();
-                    RecentsActivityLaunchState launchState = mConfig.getLaunchState();
-                    if (launchState.launchedWithAltTab &&
-                            !launchState.launchedHasConfigurationChanged &&
-                            0 <= mFocusedTaskIndex && mFocusedTaskIndex < tasks.size()) {
-                        TaskView tv = getChildViewForTask(tasks.get(mFocusedTaskIndex));
-                        if (tv != null) {
-                            tv.setFocusedTask(true);
-                        }
+                    // Update the focused state here -- since we only set the focused task without
+                    // requesting view focus in onFirstLayout(), actually request view focus and
+                    // animate the focused state if we are alt-tabbing now, after the window enter
+                    // animation is completed
+                    if (mFocusedTaskIndex != -1) {
+                        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+                        setFocusedTask(mFocusedTaskIndex, false /* scrollToTask */,
+                                launchState.launchedWithAltTab);
                     }
                 }
             });
@@ -1132,11 +1072,6 @@
     public void prepareViewToEnterPool(TaskView tv) {
         Task task = tv.getTask();
 
-        // Clear the accessibility focus for that view
-        if (tv.isAccessibilityFocused()) {
-            tv.clearAccessibilityFocus();
-        }
-
         // Report that this tasks's data is no longer being used
         Recents.getTaskLoader().unloadTaskData(task);
 
@@ -1167,11 +1102,6 @@
         // If the doze trigger has already fired, then update the state for this task view
         tv.setNoUserInteractionState();
 
-        // If we've finished the start animation, then ensure we always enable the focus animations
-        if (mStartEnterAnimationCompleted) {
-            tv.enableFocusAnimations();
-        }
-
         // Find the index where this task should be placed in the stack
         int insertIndex = -1;
         int taskIndex = mStack.indexOfTask(task);
@@ -1231,13 +1161,6 @@
         }
     }
 
-    @Override
-    public void onTaskViewFocusChanged(TaskView tv, boolean focused) {
-        if (focused) {
-            mFocusedTaskIndex = mStack.indexOfTask(tv.getTask());
-        }
-    }
-
     /**** TaskStackViewScroller.TaskStackViewScrollerCallbacks ****/
 
     @Override
@@ -1259,13 +1182,13 @@
         for (int i = tasks.size() - 1; i >= 0; i--) {
             final Task t = tasks.get(i);
             if (removedComponents.contains(t.key.getComponent())) {
-                TaskView tv = getChildViewForTask(t);
+                final TaskView tv = getChildViewForTask(t);
                 if (tv != null) {
                     // For visible children, defer removing the task until after the animation
                     tv.startDeleteTaskAnimation(new Runnable() {
                         @Override
                         public void run() {
-                            mStack.removeTask(t);
+                            removeTaskViewFromStack(tv);
                         }
                     }, 0);
                 } else {
@@ -1276,33 +1199,23 @@
         }
     }
 
-    public final void onBusEvent(DismissTaskEvent event) {
-        TaskView tv = event.taskView;
-        Task task = tv.getTask();
-        int taskIndex = mStack.indexOfTask(task);
-        boolean taskWasFocused = tv.isFocusedTask();
+    public final void onBusEvent(DismissTaskViewEvent event) {
+        removeTaskViewFromStack(event.taskView);
+    }
 
-        // Announce for accessibility
-        tv.announceForAccessibility(getContext().getString(R.string.accessibility_recents_item_dismissed,
-                tv.getTask().activityLabel));
+    public final void onBusEvent(FocusNextTaskViewEvent event) {
+        setRelativeFocusedTask(true, true);
+    }
 
-        // Remove the task from the view
-        mStack.removeTask(task);
+    public final void onBusEvent(FocusPreviousTaskViewEvent event) {
+        setRelativeFocusedTask(false, true);
+    }
 
-        // If the dismissed task was focused, then we should focus the new task in the same index
-        if (taskWasFocused) {
-            ArrayList<Task> tasks = mStack.getTasks();
-            int nextTaskIndex = Math.min(tasks.size() - 1, taskIndex - 1);
-            if (nextTaskIndex >= 0) {
-                Task nextTask = tasks.get(nextTaskIndex);
-                TaskView nextTv = getChildViewForTask(nextTask);
-                if (nextTv != null) {
-                    // Focus the next task, and only animate the visible state if we are launched
-                    // from Alt-Tab
-                    RecentsActivityLaunchState launchState = mConfig.getLaunchState();
-                    nextTv.setFocusedTask(launchState.launchedWithAltTab);
-                }
-            }
+    public final void onBusEvent(DismissFocusedTaskViewEvent event) {
+        if (mFocusedTaskIndex != -1) {
+            Task t = mStack.getTasks().get(mFocusedTaskIndex);
+            TaskView tv = getChildViewForTask(t);
+            tv.dismissTask();
         }
     }
 
@@ -1316,4 +1229,32 @@
             reset();
         }
     }
+
+    /**
+     * Removes the task from the stack, and updates the focus to the next task in the stack if the
+     * removed TaskView was focused.
+     */
+    private void removeTaskViewFromStack(TaskView tv) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        Task task = tv.getTask();
+        int taskIndex = mStack.indexOfTask(task);
+        boolean taskWasFocused = tv.isFocusedTask();
+
+        // Reset the previously focused task before it is removed from the stack
+        resetFocusedTask();
+
+        // Announce for accessibility
+        tv.announceForAccessibility(getContext().getString(
+                R.string.accessibility_recents_item_dismissed, tv.getTask().activityLabel));
+
+        // Remove the task from the stack
+        mStack.removeTask(task);
+
+        if (taskWasFocused || ssp.isTouchExplorationEnabled()) {
+            // If the dismissed task was focused or if we are in touch exploration mode, then focus
+            // the next task
+            RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+            setFocusedTask(taskIndex - 1, true /* scrollToTask */, launchState.launchedWithAltTab);
+        }
+    }
 }
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 1274318..3a1a987 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -28,7 +28,7 @@
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
-import com.android.systemui.recents.events.ui.DismissTaskEvent;
+import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
 
 import java.util.List;
 
@@ -408,13 +408,9 @@
                     // Find the front most task and scroll the next task to the front
                     float vScroll = ev.getAxisValue(MotionEvent.AXIS_VSCROLL);
                     if (vScroll > 0) {
-                        if (mSv.ensureFocusedTask(true)) {
-                            mSv.focusNextTask(true, false);
-                        }
+                        mSv.setRelativeFocusedTask(true, false /* animated */);
                     } else {
-                        if (mSv.ensureFocusedTask(true)) {
-                            mSv.focusNextTask(false, false);
-                        }
+                        mSv.setRelativeFocusedTask(false, false /* animated */);
                     }
                     return true;
             }
@@ -461,7 +457,7 @@
         // Re-enable touch events from this task view
         tv.setTouchEnabled(true);
         // Remove the task view from the stack
-        EventBus.getDefault().send(new DismissTaskEvent(tv.getTask(), tv));
+        EventBus.getDefault().send(new DismissTaskViewEvent(tv.getTask(), tv));
         // Keep track of deletions by keyboard
         MetricsLogger.histogram(tv.getContext(), "overview_task_dismissed_source",
                 Constants.Metrics.DismissSourceSwipeGesture);
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 bab4da7..0a5ee79 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -29,8 +29,8 @@
 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;
 import android.view.View;
 import android.view.ViewOutlineProvider;
@@ -40,13 +40,15 @@
 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;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.ui.DismissTaskEvent;
+import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
@@ -55,11 +57,13 @@
 public class TaskView extends FrameLayout implements Task.TaskCallbacks,
         View.OnClickListener, View.OnLongClickListener {
 
+    private final static String TAG = "TaskView";
+    private final static boolean DEBUG = false;
+
     /** The TaskView callbacks */
     interface TaskViewCallbacks {
         public void onTaskViewClicked(TaskView tv, Task task, boolean lockToTask);
         public void onTaskViewClipStateChanged(TaskView tv);
-        public void onTaskViewFocusChanged(TaskView tv, boolean focused);
     }
 
     RecentsConfiguration mConfig;
@@ -76,6 +80,7 @@
     Task mTask;
     boolean mTaskDataLoaded;
     boolean mIsFocused;
+    boolean mIsFocusAnimated;
     boolean mFocusAnimationsEnabled;
     boolean mClipViewInStack;
     AnimateableViewBounds mViewBounds;
@@ -397,15 +402,6 @@
             ctx.postAnimationTrigger.increment();
             startDelay = delay;
         }
-
-        // Enable the focus animations from this point onwards so that they aren't affected by the
-        // window transitions
-        postDelayed(new Runnable() {
-            @Override
-            public void run() {
-                enableFocusAnimations();
-            }
-        }, startDelay);
     }
 
     public void fadeInActionButton(int delay, int duration) {
@@ -547,7 +543,7 @@
         startDeleteTaskAnimation(new Runnable() {
             @Override
             public void run() {
-                EventBus.getDefault().send(new DismissTaskEvent(mTask, tv));
+                EventBus.getDefault().send(new DismissTaskViewEvent(mTask, tv));
             }
         }, 0);
     }
@@ -620,6 +616,8 @@
                 anim.addListener(postAnimRunnable);
             }
             anim.start();
+        } else {
+            postAnimRunnable.onAnimationEnd(null);
         }
     }
 
@@ -641,58 +639,32 @@
     /**** View focus state ****/
 
     /**
-     * Sets the focused task explicitly. We need a separate flag because requestFocus() won't happen
-     * if the view is not currently visible, or we are in touch state (where we still want to keep
-     * track of focus).
+     * Explicitly sets the focused state of this task.
      */
-    public void setFocusedTask(boolean animateFocusedState) {
-        mIsFocused = true;
-        if (mFocusAnimationsEnabled) {
-            // Focus the header bar
-            mHeaderView.onTaskViewFocusChanged(true, animateFocusedState);
-        }
-        // Update the thumbnail alpha with the focus
-        mThumbnailView.onFocusChanged(true);
-        // Call the callback
-        if (mCb != null) {
-            mCb.onTaskViewFocusChanged(this, true);
-        }
-        // Workaround, we don't always want it focusable in touch mode, but we want the first task
-        // to be focused after the enter-recents animation, which can be triggered from either touch
-        // or keyboard
-        setFocusableInTouchMode(true);
-        requestFocus();
-        setFocusableInTouchMode(false);
-        invalidate();
-    }
-
-    /**
-     * Unsets the focused task explicitly.
-     */
-    void unsetFocusedTask() {
-        mIsFocused = false;
-        if (mFocusAnimationsEnabled) {
-            // Un-focus the header bar
-            mHeaderView.onTaskViewFocusChanged(false, true);
+    public void setFocusedState(boolean isFocused, boolean animated, boolean requestViewFocus) {
+        if (DEBUG) {
+            Log.d(TAG, "setFocusedState: " + mTask.activityLabel + " focused: " + isFocused +
+                    " mIsFocused: " + mIsFocused + " animated: " + animated +
+                    " requestViewFocus: " + requestViewFocus + " isFocused(): " + isFocused() +
+                    " isAccessibilityFocused(): " + isAccessibilityFocused());
         }
 
-        // Update the thumbnail alpha with the focus
-        mThumbnailView.onFocusChanged(false);
-        // Call the callback
-        if (mCb != null) {
-            mCb.onTaskViewFocusChanged(this, false);
-        }
-        invalidate();
-    }
-
-    /**
-     * Updates the explicitly focused state when the view focus changes.
-     */
-    @Override
-    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
-        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
-        if (!gainFocus) {
-            unsetFocusedTask();
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        mIsFocused = isFocused;
+        mIsFocusAnimated = animated;
+        mHeaderView.onTaskViewFocusChanged(isFocused, animated);
+        mThumbnailView.onFocusChanged(isFocused);
+        if (isFocused) {
+            if (requestViewFocus && !isFocused()) {
+                requestFocus();
+            }
+            if (requestViewFocus && !isAccessibilityFocused() && ssp.isTouchExplorationEnabled()) {
+                requestAccessibilityFocus();
+            }
+        } else {
+            if (isAccessibilityFocused() && ssp.isTouchExplorationEnabled()) {
+                clearAccessibilityFocus();
+            }
         }
     }
 
@@ -700,17 +672,14 @@
      * Returns whether we have explicitly been focused.
      */
     public boolean isFocusedTask() {
-        return mIsFocused || isFocused();
+        return mIsFocused;
     }
 
-    /** Enables all focus animations. */
-    void enableFocusAnimations() {
-        boolean wasFocusAnimationsEnabled = mFocusAnimationsEnabled;
-        mFocusAnimationsEnabled = true;
-        if (mIsFocused && !wasFocusAnimationsEnabled) {
-            // Re-notify the header if we were focused and animations were not previously enabled
-            mHeaderView.onTaskViewFocusChanged(true, true);
-        }
+    /**
+     * Returns whether this focused task is animated.
+     */
+    public boolean isFocusAnimated() {
+        return mIsFocusAnimated;
     }
 
     public void disableLayersForOneFrame() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index e1e07ef..f6353f8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -39,7 +39,6 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewOutlineProvider;
-import android.view.accessibility.AccessibilityManager;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
@@ -244,9 +243,8 @@
         mMoveTaskButton.setOnClickListener(this);
 
         // In accessibility, a single click on the focused app info button will show it
-        AccessibilityManager am = (AccessibilityManager) getContext().
-                getSystemService(Context.ACCESSIBILITY_SERVICE);
-        if (am != null && am.isEnabled()) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (ssp.isTouchExplorationEnabled()) {
             mApplicationIcon.setOnClickListener(this);
         }
     }
@@ -369,9 +367,6 @@
 
     /** Notifies the associated TaskView has been focused. */
     void onTaskViewFocusChanged(boolean focused, boolean animateFocusedState) {
-        // If we are not animating the visible state, just return
-        if (!animateFocusedState) return;
-
         boolean isRunning = false;
         if (mFocusAnimator != null) {
             isRunning = mFocusAnimator.isRunning();
@@ -379,6 +374,9 @@
         }
 
         if (focused) {
+            // If we are not animating the visible state, just return
+            if (!animateFocusedState) return;
+
             int currentColor = mBackgroundColor;
             int secondaryColor = getSecondaryColor(mCurrentPrimaryColor, mCurrentPrimaryColorIsDark);
             int[][] states = new int[][] {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 10c37ce..2c16f81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -217,7 +217,7 @@
 
     private boolean mDeviceProvisioned = false;
 
-    private RecentsComponent mRecents;
+    protected RecentsComponent mRecents;
 
     protected int mZenMode;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index cfde791..cfdb01e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -88,7 +88,6 @@
 import android.view.ViewStub;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
-import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.Interpolator;
@@ -146,7 +145,6 @@
 import com.android.systemui.statusbar.policy.FullscreenUserSwitcher;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.HotspotControllerImpl;
-import com.android.systemui.statusbar.policy.KeyButtonView;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.policy.LocationControllerImpl;
@@ -1115,13 +1113,22 @@
         }
     };
 
-    private long mLastLockToAppLongPress;
-    private View.OnLongClickListener mLongPressBackRecentsListener =
-            new View.OnLongClickListener() {
+    private View.OnLongClickListener mLongPressBackListener = new View.OnLongClickListener() {
         @Override
         public boolean onLongClick(View v) {
-            handleLongPressBackRecents(v);
-            return true;
+            return handleLongPressBack();
+        }
+    };
+
+    private View.OnLongClickListener mRecentsLongClickListener = new View.OnLongClickListener() {
+
+        @Override
+        public boolean onLongClick(View v) {
+            if (mRecents != null) {
+                mRecents.dockTopTask();
+                return true;
+            }
+            return false;
         }
     };
 
@@ -1170,9 +1177,9 @@
         mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
         mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);
         mNavigationBarView.getRecentsButton().setLongClickable(true);
-        mNavigationBarView.getRecentsButton().setOnLongClickListener(mLongPressBackRecentsListener);
+        mNavigationBarView.getRecentsButton().setOnLongClickListener(mRecentsLongClickListener);
         mNavigationBarView.getBackButton().setLongClickable(true);
-        mNavigationBarView.getBackButton().setOnLongClickListener(mLongPressBackRecentsListener);
+        mNavigationBarView.getBackButton().setOnLongClickListener(mLongPressBackListener);
         mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener);
         mNavigationBarView.getHomeButton().setOnLongClickListener(mLongPressHomeListener);
         mAssistManager.onConfigurationChanged();
@@ -4048,7 +4055,7 @@
 
     private void vibrateForCameraGesture() {
         // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
-        mVibrator.vibrate(new long[] { 0, 750L }, -1 /* repeat */);
+        mVibrator.vibrate(new long[]{0, 750L}, -1 /* repeat */);
     }
 
     public void onScreenTurnedOn() {
@@ -4057,58 +4064,22 @@
     }
 
     /**
-     * This handles long-press of both back and recents.  They are
-     * handled together to capture them both being long-pressed
-     * at the same time to exit screen pinning (lock task).
-     *
-     * When accessibility mode is on, only a long-press from recents
-     * is required to exit.
-     *
-     * In all other circumstances we try to pass through long-press events
-     * for Back, so that apps can still use it.  Which can be from two things.
-     * 1) Not currently in screen pinning (lock task).
-     * 2) Back is long-pressed without recents.
+     * Handles long press for back button. This exits screen pinning.
      */
-    private void handleLongPressBackRecents(View v) {
+    private boolean handleLongPressBack() {
         try {
-            boolean sendBackLongPress = false;
             IActivityManager activityManager = ActivityManagerNative.getDefault();
-            boolean isAccessiblityEnabled = mAccessibilityManager.isEnabled();
-            if (activityManager.isInLockTaskMode() && !isAccessiblityEnabled) {
-                long time = System.currentTimeMillis();
-                // If we recently long-pressed the other button then they were
-                // long-pressed 'together'
-                if ((time - mLastLockToAppLongPress) < LOCK_TO_APP_GESTURE_TOLERENCE) {
-                    activityManager.stopLockTaskModeOnCurrent();
-                    // When exiting refresh disabled flags.
-                    mNavigationBarView.setDisabledFlags(mDisabled1, true);
-                } else if ((v.getId() == R.id.back)
-                        && !mNavigationBarView.getRecentsButton().isPressed()) {
-                    // If we aren't pressing recents right now then they presses
-                    // won't be together, so send the standard long-press action.
-                    sendBackLongPress = true;
-                }
-                mLastLockToAppLongPress = time;
-            } else {
-                // If this is back still need to handle sending the long-press event.
-                if (v.getId() == R.id.back) {
-                    sendBackLongPress = true;
-                } else if (isAccessiblityEnabled && activityManager.isInLockTaskMode()) {
-                    // When in accessibility mode a long press that is recents (not back)
-                    // should stop lock task.
-                    activityManager.stopLockTaskModeOnCurrent();
-                    // When exiting refresh disabled flags.
-                    mNavigationBarView.setDisabledFlags(mDisabled1, true);
-                }
-            }
-            if (sendBackLongPress) {
-                KeyButtonView keyButtonView = (KeyButtonView) v;
-                keyButtonView.sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
-                keyButtonView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
+            if (activityManager.isInLockTaskMode()) {
+                activityManager.stopLockTaskModeOnCurrent();
+
+                // When exiting refresh disabled flags.
+                mNavigationBarView.setDisabledFlags(mDisabled1, true);
+                return true;
             }
         } catch (RemoteException e) {
             Log.d(TAG, "Unable to reach activity manager", e);
         }
+        return false;
     }
 
     // Recents
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9834757..257f034 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -75,6 +75,7 @@
 import android.os.storage.IMountService;
 import android.os.storage.MountServiceInternal;
 import android.os.storage.StorageManager;
+import android.provider.Settings.Global;
 import android.service.voice.IVoiceInteractionSession;
 import android.service.voice.VoiceInteractionSession;
 import android.util.ArrayMap;
@@ -1189,6 +1190,7 @@
     String mOrigDebugApp = null;
     boolean mOrigWaitForDebugger = false;
     boolean mAlwaysFinishActivities = false;
+    boolean mForceResizableActivites;
     IActivityController mController = null;
     String mProfileApp = null;
     ProcessRecord mProfileProc = null;
@@ -11638,14 +11640,17 @@
 
     private void retrieveSettings() {
         final ContentResolver resolver = mContext.getContentResolver();
-        String debugApp = Settings.Global.getString(
-            resolver, Settings.Global.DEBUG_APP);
+        String debugApp = Settings.Global.getString(resolver, Settings.Global.DEBUG_APP);
         boolean waitForDebugger = Settings.Global.getInt(
             resolver, Settings.Global.WAIT_FOR_DEBUGGER, 0) != 0;
         boolean alwaysFinishActivities = Settings.Global.getInt(
             resolver, Settings.Global.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
         boolean forceRtl = Settings.Global.getInt(
                 resolver, Settings.Global.DEVELOPMENT_FORCE_RTL, 0) != 0;
+        int defaultForceResizable = Build.IS_DEBUGGABLE ? 1 : 0;
+        boolean forceResizable = Settings.Global.getInt(
+                resolver, Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES,
+                defaultForceResizable) != 0;
         // Transfer any global setting for forcing RTL layout, into a System Property
         SystemProperties.set(Settings.Global.DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0");
 
@@ -11660,6 +11665,7 @@
             mDebugApp = mOrigDebugApp = debugApp;
             mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
             mAlwaysFinishActivities = alwaysFinishActivities;
+            mForceResizableActivites = forceResizable;
             // This happens before any activities are started, so we can
             // change mConfiguration in-place.
             updateConfigurationLocked(configuration, null, true);
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 7e47006..cd2f124 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2749,8 +2749,7 @@
         boolean didSomething = false;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            final int numStacks = stacks.size();
-            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
                 if (stack.finishDisabledPackageActivitiesLocked(
                         packageName, filterByClasses, doit, evenPersistent, userId)) {
@@ -2992,84 +2991,87 @@
         }
 
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stackId);
+        mWindowManager.deferSurfaceLayout();
+        try {
+            ActivityRecord r = stack.topRunningActivityLocked();
 
-        ActivityRecord r = stack.topRunningActivityLocked();
-
-        mTmpBounds.clear();
-        mTmpConfigs.clear();
-        ArrayList<TaskRecord> tasks = stack.getAllTasks();
-        for (int i = tasks.size() - 1; i >= 0; i--) {
-            TaskRecord task = tasks.get(i);
-            if (task.mResizeable) {
-                if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
-                    // For freeform stack we don't adjust the size of the tasks to match that
-                    // of the stack, but we do try to make sure the tasks are still contained
-                    // with the bounds of the stack.
-                    tempRect2.set(task.mBounds);
-                    fitWithinBounds(tempRect2, bounds);
-                    task.updateOverrideConfiguration(tempRect2);
-                } else {
-                    task.updateOverrideConfiguration(bounds);
-                }
-            }
-
-            mTmpConfigs.put(task.taskId, task.mOverrideConfig);
-            mTmpBounds.put(task.taskId, task.mBounds);
-        }
-        stack.mFullscreen = mWindowManager.resizeStack(stackId, bounds, mTmpConfigs, mTmpBounds);
-        if (stack.mStackId == DOCKED_STACK_ID) {
-            // Dock stack funness...Yay!
-            if (stack.mFullscreen) {
-                // The dock stack went fullscreen which is kinda like dismissing it.
-                // In this case we make all other static stacks fullscreen and move all
-                // docked stack tasks to the fullscreen stack.
-                for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
-                    if (i != DOCKED_STACK_ID && getStack(i) != null) {
-                        resizeStackLocked(i, null, preserveWindows, true);
+            mTmpBounds.clear();
+            mTmpConfigs.clear();
+            ArrayList<TaskRecord> tasks = stack.getAllTasks();
+            for (int i = tasks.size() - 1; i >= 0; i--) {
+                TaskRecord task = tasks.get(i);
+                if (task.mResizeable) {
+                    if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
+                        // For freeform stack we don't adjust the size of the tasks to match that
+                        // of the stack, but we do try to make sure the tasks are still contained
+                        // with the bounds of the stack.
+                        tempRect2.set(task.mBounds);
+                        fitWithinBounds(tempRect2, bounds);
+                        task.updateOverrideConfiguration(tempRect2);
+                    } else {
+                        task.updateOverrideConfiguration(bounds);
                     }
                 }
 
-                final int count = tasks.size();
-                for (int i = 0; i < count; i++) {
-                    moveTaskToStackLocked(tasks.get(i).taskId,
-                            FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, FORCE_FOCUS);
-                }
+                mTmpConfigs.put(task.taskId, task.mOverrideConfig);
+                mTmpBounds.put(task.taskId, task.mBounds);
+            }
+            stack.mFullscreen = mWindowManager.resizeStack(stackId, bounds, mTmpConfigs, mTmpBounds);
+            if (stack.mStackId == DOCKED_STACK_ID) {
+                // Dock stack funness...Yay!
+                if (stack.mFullscreen) {
+                    // The dock stack went fullscreen which is kinda like dismissing it.
+                    // In this case we make all other static stacks fullscreen and move all
+                    // docked stack tasks to the fullscreen stack.
+                    for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
+                        if (i != DOCKED_STACK_ID && getStack(i) != null) {
+                            resizeStackLocked(i, null, preserveWindows, true);
+                        }
+                    }
 
-                // stack shouldn't contain anymore activities, so nothing to resume.
-                r = null;
-            } else {
-                // Docked stacks occupy a dedicated region on screen so the size of all other
-                // static stacks need to be adjusted so they don't overlap with the docked stack.
-                // We get the bounds to use from window manager which has been adjusted for any
-                // screen controls and is also the same for all stacks.
-                mWindowManager.getStackDockedModeBounds(HOME_STACK_ID, tempRect);
+                    final int count = tasks.size();
+                    for (int i = 0; i < count; i++) {
+                        moveTaskToStackLocked(tasks.get(i).taskId,
+                                FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, FORCE_FOCUS);
+                    }
 
-                for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
-                    if (i != DOCKED_STACK_ID) {
-                        ActivityStack otherStack = getStack(i);
-                        if (otherStack != null) {
-                            resizeStackLocked(i, tempRect, PRESERVE_WINDOWS, true);
+                    // stack shouldn't contain anymore activities, so nothing to resume.
+                    r = null;
+                } else {
+                    // Docked stacks occupy a dedicated region on screen so the size of all other
+                    // static stacks need to be adjusted so they don't overlap with the docked stack.
+                    // We get the bounds to use from window manager which has been adjusted for any
+                    // screen controls and is also the same for all stacks.
+                    mWindowManager.getStackDockedModeBounds(HOME_STACK_ID, tempRect);
+
+                    for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
+                        if (i != DOCKED_STACK_ID) {
+                            ActivityStack otherStack = getStack(i);
+                            if (otherStack != null) {
+                                resizeStackLocked(i, tempRect, PRESERVE_WINDOWS, true);
+                            }
                         }
                     }
                 }
+                // Since we are resizing the stack, all other operations should strive to preserve
+                // windows.
+                preserveWindows = true;
             }
-            // Since we are resizing the stack, all other operations should strive to preserve
-            // windows.
-            preserveWindows = true;
-        }
-        stack.setBounds(bounds);
+            stack.setBounds(bounds);
 
-        if (r != null) {
-            final boolean updated = stack.ensureActivityConfigurationLocked(r, 0, preserveWindows);
-            // And we need to make sure at this point that all other activities
-            // are made visible with the correct configuration.
-            ensureActivitiesVisibleLocked(r, 0, preserveWindows);
-            if (!updated) {
-                resumeTopActivitiesLocked(stack, null, null);
+            if (r != null) {
+                final boolean updated = stack.ensureActivityConfigurationLocked(r, 0, preserveWindows);
+                // And we need to make sure at this point that all other activities
+                // are made visible with the correct configuration.
+                ensureActivitiesVisibleLocked(r, 0, preserveWindows);
+                if (!updated) {
+                    resumeTopActivitiesLocked(stack, null, null);
+                }
             }
+        } finally {
+            mWindowManager.continueSurfaceLayout();
+            Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
         }
-
-        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
 
     void resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 090a342..120b40c 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -318,7 +318,7 @@
         mNextAffiliateTaskId = nextTaskId;
         mCallingUid = callingUid;
         mCallingPackage = callingPackage;
-        mResizeable = resizeable;
+        mResizeable = resizeable || mService.mForceResizableActivites;
         mPrivileged = privileged;
         ActivityInfo info = mActivities.get(0).info;
         mMinimalSize = info != null && info.layout != null ? info.layout.minimalSize : -1;
@@ -420,7 +420,7 @@
         } else {
             autoRemoveRecents = false;
         }
-        mResizeable = info.resizeable;
+        mResizeable = info.resizeable || mService.mForceResizableActivites;
         mLockTaskMode = info.lockTaskLaunchMode;
         mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0;
         setLockTaskAuth();
@@ -626,6 +626,9 @@
         // Only set this based on the first activity
         if (mActivities.isEmpty()) {
             taskType = r.mActivityType;
+            if (taskType == HOME_ACTIVITY_TYPE && mService.mForceResizableActivites) {
+                mResizeable = r.info.resizeable;
+            }
             isPersistable = r.isPersistable();
             mCallingUid = r.launchedFromUid;
             mCallingPackage = r.launchedFromPackage;
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index be86e2f..f4a4140 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -31,6 +31,7 @@
 
 import android.content.Context;
 import android.os.RemoteException;
+import android.os.Trace;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
@@ -731,8 +732,15 @@
             mWindowPlacerLocked.requestTraversal();
         }
 
+        if (mAnimating && !wasAnimating && Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
+            Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
+        }
+
         if (!mAnimating && wasAnimating) {
             mWindowPlacerLocked.requestTraversal();
+            if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
+                Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
+            }
         }
 
         mService.destroyPreservedSurfaceLocked();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8a2442a..62553cf 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4679,7 +4679,7 @@
                 throw new IllegalArgumentException("resizeStack: stackId " + stackId
                         + " not found.");
             }
-            if (stack.setBounds(bounds, configs, taskBounds)) {
+            if (stack.setBounds(bounds, configs, taskBounds) && stack.isVisibleLocked()) {
                 stack.resizeWindows();
                 stack.getDisplayContent().layoutNeeded = true;
                 mWindowPlacerLocked.performSurfacePlacement();
@@ -4732,6 +4732,26 @@
         }
     }
 
+    /**
+     * Starts deferring layout passes. Useful when doing multiple changes but to optimize
+     * performance, only one layout pass should be done. This can be called multiple times, and
+     * layouting will be resumed once the last caller has called {@link #continueSurfaceLayout}
+     */
+    public void deferSurfaceLayout() {
+        synchronized (mWindowMap) {
+            mWindowPlacerLocked.deferLayout();
+        }
+    }
+
+    /**
+     * Resumes layout passes after deferring them. See {@link #deferSurfaceLayout()}
+     */
+    public void continueSurfaceLayout() {
+        synchronized (mWindowMap) {
+            mWindowPlacerLocked.continueLayout();
+        }
+    }
+
     public void getTaskBounds(int taskId, Rect bounds) {
         synchronized (mWindowMap) {
             Task task = mTaskIdToTask.get(taskId);
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index e2f4dd9..b267860 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -112,13 +112,34 @@
     private int mPreferredModeId = 0;
 
     private boolean mTraversalScheduled;
+    private int mDeferDepth = 0;
 
     public WindowSurfacePlacer(WindowManagerService service) {
         mService = service;
         mWallpaperControllerLocked = mService.mWallpaperControllerLocked;
     }
 
+    /**
+     * See {@link WindowManagerService#deferSurfaceLayout()}
+     */
+    void deferLayout() {
+        mDeferDepth++;
+    }
+
+    /**
+     * See {@link WindowManagerService#continueSurfaceLayout()}
+     */
+    void continueLayout() {
+        mDeferDepth--;
+        if (mDeferDepth <= 0) {
+            performSurfacePlacement();
+        }
+    }
+
     final void performSurfacePlacement() {
+        if (mDeferDepth > 0) {
+            return;
+        }
         int loopCount = 6;
         do {
             mTraversalScheduled = false;