Merge changes Ie48f4b66,Ia48f4453 into ub-launcher3-master

* changes:
  Always update clip rect before applying surface params
  Clean up AppWindowAnimationHelper and TransformParams
diff --git a/go/src/com/android/launcher3/model/WidgetsModel.java b/go/src/com/android/launcher3/model/WidgetsModel.java
index 7690b9d..3b3dc01 100644
--- a/go/src/com/android/launcher3/model/WidgetsModel.java
+++ b/go/src/com/android/launcher3/model/WidgetsModel.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.model;
 
+import android.content.ComponentName;
 import android.content.Context;
 import android.os.UserHandle;
 
@@ -68,4 +69,9 @@
     public void onPackageIconsUpdated(Set<String> packageNames, UserHandle user,
             LauncherAppState app) {
     }
+
+    public WidgetItem getWidgetProviderInfoByProviderName(
+            ComponentName providerName) {
+        return null;
+    }
 }
\ No newline at end of file
diff --git a/protos/launcher_trace.proto b/protos/launcher_trace.proto
new file mode 100644
index 0000000..c6f3543
--- /dev/null
+++ b/protos/launcher_trace.proto
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+syntax = "proto2";
+
+package com.android.launcher3.tracing;
+
+option java_multiple_files = true;
+
+message LauncherTraceProto {
+
+    optional TouchInteractionServiceProto touch_interaction_service = 1;
+}
+
+message TouchInteractionServiceProto {
+
+    optional bool service_connected = 1;
+}
diff --git a/protos/launcher_trace_file.proto b/protos/launcher_trace_file.proto
new file mode 100644
index 0000000..6ce182a
--- /dev/null
+++ b/protos/launcher_trace_file.proto
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+syntax = "proto2";
+
+import "launcher_trace.proto";
+
+package com.android.launcher3.tracing;
+
+option java_multiple_files = true;
+
+/* represents a file full of launcher trace entries.
+   Encoded, it should start with 0x9 0x4C 0x4E 0x43 0x48 0x52 0x54 0x52 0x43 (.LNCHRTRC), such
+   that they can be easily identified. */
+message LauncherTraceFileProto {
+
+    /* constant; MAGIC_NUMBER = (long) MAGIC_NUMBER_H << 32 | MagicNumber.MAGIC_NUMBER_L
+       (this is needed because enums have to be 32 bits and there's no nice way to put 64bit
+        constants into .proto files. */
+    enum MagicNumber {
+        INVALID = 0;
+        MAGIC_NUMBER_L = 0x48434E4C;  /* LNCH (little-endian ASCII) */
+        MAGIC_NUMBER_H = 0x43525452;  /* RTRC (little-endian ASCII) */
+    }
+
+    optional fixed64 magic_number = 1;  /* Must be the first field, set to value in MagicNumber */
+    repeated LauncherTraceEntryProto entry = 2;
+}
+
+/* one launcher trace entry. */
+message LauncherTraceEntryProto {
+    /* required: elapsed realtime in nanos since boot of when this entry was logged */
+    optional fixed64 elapsed_realtime_nanos = 1;
+
+    optional LauncherTraceProto launcher = 3;
+}
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index d3cec28..a06a2dd 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -47,10 +47,7 @@
             </intent-filter>
         </service>
 
-        <!-- STOPSHIP: Change exported to false once all the integration is complete.
-        It is set to true so that the activity can be started from command line -->
         <activity android:name="com.android.quickstep.RecentsActivity"
-            android:exported="true"
             android:excludeFromRecents="true"
             android:launchMode="singleTask"
             android:clearTaskOnLaunch="true"
@@ -93,12 +90,12 @@
                   android:directBootAware="true" />
 
         <activity
-            android:name="com.android.quickstep.interaction.BackGestureTutorialActivity"
+            android:name="com.android.quickstep.interaction.GestureSandboxActivity"
             android:autoRemoveFromRecents="true"
             android:excludeFromRecents="true"
             android:screenOrientation="portrait">
             <intent-filter>
-                <action android:name="com.android.quickstep.action.BACK_GESTURE_TUTORIAL" />
+                <action android:name="com.android.quickstep.action.GESTURE_SANDBOX" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
diff --git a/quickstep/recents_ui_overrides/res/drawable/hotseat_edu_notification_icon.xml b/quickstep/recents_ui_overrides/res/drawable/hotseat_edu_notification_icon.xml
index fa3a0f8..4fda2a9 100644
--- a/quickstep/recents_ui_overrides/res/drawable/hotseat_edu_notification_icon.xml
+++ b/quickstep/recents_ui_overrides/res/drawable/hotseat_edu_notification_icon.xml
@@ -15,5 +15,5 @@
 -->
 <vector android:height="24dp" android:viewportHeight="24"
     android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
-    <path android:fillColor="@color/bottom_panel_background" android:pathData="M19 9l1.25-2.75L23 5l-2.75-1.25L19 1l-1.25 2.75L15 5l2.75 1.25L19 9zm-7.5.5L9 4 6.5 9.5 1 12l5.5 2.5L9 20l2.5-5.5L17 12l-5.5-2.5zM19 15l-1.25 2.75L15 19l2.75 1.25L19 23l1.25-2.75L23 19l-2.75-1.25L19 15z"/>
+    <path android:fillColor="?android:attr/colorAccent" android:pathData="M19 9l1.25-2.75L23 5l-2.75-1.25L19 1l-1.25 2.75L15 5l2.75 1.25L19 9zm-7.5.5L9 4 6.5 9.5 1 12l5.5 2.5L9 20l2.5-5.5L17 12l-5.5-2.5zM19 15l-1.25 2.75L15 19l2.75 1.25L19 23l1.25-2.75L23 19l-2.75-1.25L19 15z"/>
 </vector>
diff --git a/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml b/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml
index d94c665..fe99037 100644
--- a/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml
+++ b/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml
@@ -24,13 +24,13 @@
     <View
         android:layout_width="match_parent"
         android:layout_height="32dp"
-        android:backgroundTint="@color/bottom_panel_background"
+        android:backgroundTint="?android:attr/colorAccent"
         android:background="@drawable/bottom_sheet_top_border" />
 
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:background="@color/bottom_panel_background"
+        android:background="?android:attr/colorAccent"
         android:orientation="vertical">
 
         <TextView
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
index bfbd00e..e7290a4 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
@@ -34,6 +34,7 @@
 import com.android.launcher3.WorkspaceItemInfo;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.ActivityTracker;
+import com.android.launcher3.util.Themes;
 
 import java.util.List;
 
@@ -109,7 +110,7 @@
                 NOTIFICATION_CHANNEL_ID)
                 .setContentTitle(name)
                 .setOngoing(true)
-                .setColor(mLauncher.getColor(R.color.bottom_panel_background))
+                .setColor(Themes.getColorAccent(mLauncher))
                 .setContentIntent(PendingIntent.getActivity(mLauncher, 0, intent,
                         PendingIntent.FLAG_CANCEL_CURRENT))
                 .setSmallIcon(R.drawable.hotseat_edu_notification_icon)
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
index 00e72b1..8926246 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
@@ -191,7 +191,7 @@
                 || predictions.size() < mLauncher.getDeviceProfile().inv.numHotseatIcons) {
             return;
         }
-        mLauncher.getDragLayer().addView(this);
+        attachToContainer();
         logOnBoardingSeen();
         animateOpen();
         for (int i = 0; i < mLauncher.getDeviceProfile().inv.numHotseatIcons; i++) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
index a1c8378..7895bac 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -37,6 +37,7 @@
 
 import android.graphics.Rect;
 import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.Interpolator;
 
 import com.android.launcher3.AbstractFloatingView;
@@ -47,6 +48,7 @@
 import com.android.launcher3.Workspace;
 import com.android.launcher3.allapps.DiscoveryBounce;
 import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.quickstep.SysUINavigationMode;
@@ -143,6 +145,10 @@
     public void onStateTransitionEnd(Launcher launcher) {
         launcher.getRotationHelper().setCurrentStateRequest(REQUEST_ROTATE);
         DiscoveryBounce.showForOverviewIfNeeded(launcher);
+        RecentsView recentsView = launcher.getOverviewPanel();
+        AccessibilityManagerCompat.sendCustomAccessibilityEvent(
+                recentsView.getPageAt(recentsView.getCurrentPage()),
+                AccessibilityEvent.TYPE_VIEW_FOCUSED, null);
     }
 
     @Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
index b80830a..519939e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
@@ -172,7 +172,7 @@
         mMotionPauseDetector.setDisallowPause(!handlingOverviewAnim()
                 || upDisplacement < mMotionPauseMinDisplacement
                 || upDisplacement > mMotionPauseMaxDisplacement);
-        mMotionPauseDetector.addPosition(displacement, event.getEventTime());
+        mMotionPauseDetector.addPosition(event);
         return super.onDrag(displacement, event);
     }
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 8628db0..799f1ad 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -317,7 +317,7 @@
         // home screen elements will appear in the shelf on motion pause.
         mMotionPauseDetector.setDisallowPause(mIsHomeScreenVisible
                 || -displacement.y < mMotionPauseMinDisplacement);
-        mMotionPauseDetector.addPosition(displacement.y, ev.getEventTime());
+        mMotionPauseDetector.addPosition(ev);
 
         if (mIsHomeScreenVisible) {
             // Cancel the shelf anim so it doesn't clobber mNonOverviewAnim.
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index 3364b66..28e8fb6 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -28,6 +28,7 @@
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT;
 
 import android.annotation.TargetApi;
@@ -63,6 +64,8 @@
 import com.android.launcher3.provider.RestoreDbTask;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.TestProtocol;
+import com.android.launcher3.tracing.nano.LauncherTraceProto;
+import com.android.launcher3.tracing.nano.TouchInteractionServiceProto;
 import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
 import com.android.launcher3.util.TraceHelper;
 import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
@@ -76,6 +79,7 @@
 import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
 import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.util.AssistantUtilities;
+import com.android.quickstep.util.ProtoTracer;
 import com.android.systemui.plugins.OverscrollPlugin;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.shared.recents.IOverviewProxy;
@@ -85,6 +89,7 @@
 import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.shared.system.InputMonitorCompat;
 import com.android.systemui.shared.system.RecentsAnimationListener;
+import com.android.systemui.shared.tracing.ProtoTraceable;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -113,7 +118,8 @@
  * Service connected by system-UI for handling touch interaction.
  */
 @TargetApi(Build.VERSION_CODES.Q)
-public class TouchInteractionService extends Service implements PluginListener<OverscrollPlugin> {
+public class TouchInteractionService extends Service implements PluginListener<OverscrollPlugin>,
+        ProtoTraceable<LauncherTraceProto> {
 
     private static final String TAG = "TouchInteractionService";
 
@@ -275,6 +281,7 @@
         mDeviceState = new RecentsAnimationDeviceState(this);
         mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
         mDeviceState.runOnUserUnlocked(this::onUserUnlocked);
+        ProtoTracer.INSTANCE.get(this).add(this);
 
         sConnected = true;
     }
@@ -381,6 +388,13 @@
             SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(
                     mDeviceState.getSystemUiStateFlags());
             mOverviewComponentObserver.onSystemUiStateChanged();
+
+            // Update the tracing state
+            if ((mDeviceState.getSystemUiStateFlags() & SYSUI_STATE_TRACING_ENABLED) != 0) {
+                ProtoTracer.INSTANCE.get(TouchInteractionService.this).start();
+            } else {
+                ProtoTracer.INSTANCE.get(TouchInteractionService.this).stop();
+            }
         }
     }
 
@@ -403,6 +417,8 @@
         disposeEventHandlers();
         mDeviceState.destroy();
         SystemUiProxy.INSTANCE.get(this).setProxy(null);
+        ProtoTracer.INSTANCE.get(TouchInteractionService.this).stop();
+        ProtoTracer.INSTANCE.get(this).remove(this);
 
         sConnected = false;
         super.onDestroy();
@@ -723,6 +739,9 @@
             pw.println("  resumed=" + resumed);
             pw.println("  mConsumer=" + mConsumer.getName());
             ActiveGestureLog.INSTANCE.dump("", pw);
+            pw.println("ProtoTrace:");
+            pw.println("  file="
+                    + ProtoTracer.INSTANCE.get(TouchInteractionService.this).getTraceFile());
         }
     }
 
@@ -753,7 +772,7 @@
 
     protected boolean shouldNotifyBackGesture() {
         return mBackGestureNotificationCounter > 0 &&
-                mDeviceState.getGestureBlockedActivityPackage() != null;
+                !mDeviceState.getGestureBlockedActivityPackages().isEmpty();
     }
 
     @WorkerThread
@@ -762,8 +781,8 @@
             mBackGestureNotificationCounter--;
             Utilities.getDevicePrefs(this).edit()
                     .putInt(KEY_BACK_NOTIFICATION_COUNT, mBackGestureNotificationCounter).apply();
-            sendBroadcast(new Intent(NOTIFY_ACTION_BACK).setPackage(
-                    mDeviceState.getGestureBlockedActivityPackage()));
+            mDeviceState.getGestureBlockedActivityPackages().forEach(blockedPackage ->
+                    sendBroadcast(new Intent(NOTIFY_ACTION_BACK).setPackage(blockedPackage)));
         }
     }
 
@@ -781,4 +800,13 @@
     public void onPluginDisconnected(OverscrollPlugin overscrollPlugin) {
         mOverscrollPlugin = null;
     }
+
+    @Override
+    public void writeToProto(LauncherTraceProto proto) {
+        if (proto.touchInteractionService == null) {
+            proto.touchInteractionService = new TouchInteractionServiceProto();
+        }
+        proto.touchInteractionService.serviceConnected = true;
+        proto.touchInteractionService.serviceConnected = true;
+    }
 }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java
index d3765c5..5ad48eb 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java
@@ -31,8 +31,8 @@
 import com.android.launcher3.R;
 import com.android.quickstep.InputConsumer;
 import com.android.quickstep.RecentsAnimationDeviceState;
-import com.android.quickstep.util.MotionPauseDetector;
 import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.util.MotionPauseDetector;
 import com.android.systemui.shared.system.InputMonitorCompat;
 
 /**
@@ -117,9 +117,7 @@
                     if (pointerIndex == -1) {
                         break;
                     }
-
-                    mMotionPauseDetector.addPosition(ev.getY(pointerIndex) - mDownY,
-                            ev.getEventTime());
+                    mMotionPauseDetector.addPosition(ev, pointerIndex);
                 }
                 break;
             }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 3ee3c2d..8e7074d 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -59,6 +59,7 @@
 import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.util.CachedEventDispatcher;
 import com.android.quickstep.util.MotionPauseDetector;
+import com.android.quickstep.util.NavBarPosition;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.InputMonitorCompat;
 
@@ -77,6 +78,7 @@
     public static final float QUICKSTEP_TOUCH_SLOP_RATIO = 3;
 
     private final RecentsAnimationDeviceState mDeviceState;
+    private final NavBarPosition mNavBarPosition;
     private final TaskAnimationManager mTaskAnimationManager;
     private final GestureState mGestureState;
     private RecentsAnimationCallbacks mActiveCallbacks;
@@ -126,13 +128,16 @@
             Factory handlerFactory) {
         super(base);
         mDeviceState = deviceState;
+        mNavBarPosition = mDeviceState.getNavBarPosition();
         mTaskAnimationManager = taskAnimationManager;
         mGestureState = gestureState;
         mMainThreadHandler = new Handler(Looper.getMainLooper());
         mHandlerFactory = handlerFactory;
         mActivityInterface = mGestureState.getActivityInterface();
 
-        mMotionPauseDetector = new MotionPauseDetector(base);
+        mMotionPauseDetector = new MotionPauseDetector(base, false,
+                mNavBarPosition.isLeftEdge() || mNavBarPosition.isRightEdge()
+                        ? MotionEvent.AXIS_X : MotionEvent.AXIS_Y);
         mMotionPauseMinDisplacement = base.getResources().getDimension(
                 R.dimen.motion_pause_detector_min_displacement_from_app);
         mOnCompleteCallback = onCompleteCallback;
@@ -172,7 +177,7 @@
         if (mPassedWindowMoveSlop && mInteractionHandler != null
                 && !mRecentsViewDispatcher.hasConsumer()) {
             mRecentsViewDispatcher.setConsumer(mInteractionHandler.getRecentsViewDispatcher(
-                    mDeviceState.getNavBarPosition().getRotationMode()));
+                    mNavBarPosition.getRotationMode()));
         }
         int edgeFlags = ev.getEdgeFlags();
         ev.setEdgeFlags(edgeFlags | EDGE_NAV_BAR);
@@ -285,7 +290,7 @@
                     if (mDeviceState.isFullyGesturalNavMode()) {
                         mMotionPauseDetector.setDisallowPause(upDist < mMotionPauseMinDisplacement
                                 || isLikelyToStartNewTask);
-                        mMotionPauseDetector.addPosition(displacement, ev.getEventTime());
+                        mMotionPauseDetector.addPosition(ev);
                         mInteractionHandler.setIsLikelyToStartNewTask(isLikelyToStartNewTask);
                     }
                 }
@@ -354,9 +359,9 @@
                         ViewConfiguration.get(this).getScaledMaximumFlingVelocity());
                 float velocityX = mVelocityTracker.getXVelocity(mActivePointerId);
                 float velocityY = mVelocityTracker.getYVelocity(mActivePointerId);
-                float velocity = mDeviceState.getNavBarPosition().isRightEdge()
+                float velocity = mNavBarPosition.isRightEdge()
                         ? velocityX
-                        : mDeviceState.getNavBarPosition().isLeftEdge()
+                        : mNavBarPosition.isLeftEdge()
                                 ? -velocityX
                                 : velocityY;
 
@@ -410,9 +415,9 @@
     }
 
     private float getDisplacement(MotionEvent ev) {
-        if (mDeviceState.getNavBarPosition().isRightEdge()) {
+        if (mNavBarPosition.isRightEdge()) {
             return ev.getX() - mDownPos.x;
-        } else if (mDeviceState.getNavBarPosition().isLeftEdge()) {
+        } else if (mNavBarPosition.isLeftEdge()) {
             return mDownPos.x - ev.getX();
         } else {
             return ev.getY() - mDownPos.y;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java
index d5ed321..b9827ff 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java
@@ -23,8 +23,8 @@
 import com.android.launcher3.R;
 import com.android.quickstep.GestureState;
 import com.android.quickstep.InputConsumer;
-import com.android.quickstep.util.MotionPauseDetector;
 import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.util.MotionPauseDetector;
 
 /**
  * An input consumer that detects swipe up and hold to exit screen pinning mode.
@@ -72,7 +72,7 @@
             case MotionEvent.ACTION_MOVE:
                 float displacement = mTouchDownY - y;
                 mMotionPauseDetector.setDisallowPause(displacement < mMotionPauseMinDisplacement);
-                mMotionPauseDetector.addPosition(y, ev.getEventTime());
+                mMotionPauseDetector.addPosition(ev);
                 break;
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP:
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ProtoTracer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ProtoTracer.java
new file mode 100644
index 0000000..190763a
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ProtoTracer.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2019 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.quickstep.util;
+
+import static com.android.launcher3.tracing.nano.LauncherTraceFileProto.MagicNumber.MAGIC_NUMBER_H;
+import static com.android.launcher3.tracing.nano.LauncherTraceFileProto.MagicNumber.MAGIC_NUMBER_L;
+
+import android.content.Context;
+import android.os.SystemClock;
+
+import com.android.launcher3.tracing.nano.LauncherTraceProto;
+import com.android.launcher3.tracing.nano.LauncherTraceEntryProto;
+import com.android.launcher3.tracing.nano.LauncherTraceFileProto;
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.systemui.shared.tracing.FrameProtoTracer;
+import com.android.systemui.shared.tracing.FrameProtoTracer.ProtoTraceParams;
+import com.android.systemui.shared.tracing.ProtoTraceable;
+import com.google.protobuf.nano.MessageNano;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Queue;
+
+
+/**
+ * Controller for coordinating winscope proto tracing.
+ */
+public class ProtoTracer implements ProtoTraceParams<MessageNano,
+        LauncherTraceFileProto, LauncherTraceEntryProto, LauncherTraceProto> {
+
+    public static final MainThreadInitializedObject<ProtoTracer> INSTANCE =
+            new MainThreadInitializedObject<>(ProtoTracer::new);
+
+    private static final String TAG = "ProtoTracer";
+    private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
+
+    private final Context mContext;
+    private final FrameProtoTracer<MessageNano,
+            LauncherTraceFileProto, LauncherTraceEntryProto, LauncherTraceProto> mProtoTracer;
+
+    public ProtoTracer(Context context) {
+        mContext = context;
+        mProtoTracer = new FrameProtoTracer<>(this);
+    }
+
+    @Override
+    public File getTraceFile() {
+        return new File(mContext.getFilesDir(), "launcher_trace.pb");
+    }
+
+    @Override
+    public LauncherTraceFileProto getEncapsulatingTraceProto() {
+        return new LauncherTraceFileProto();
+    }
+
+    @Override
+    public LauncherTraceEntryProto updateBufferProto(LauncherTraceEntryProto reuseObj,
+            ArrayList<ProtoTraceable<LauncherTraceProto>> traceables) {
+        LauncherTraceEntryProto proto = reuseObj != null
+                ? reuseObj
+                : new LauncherTraceEntryProto();
+        proto.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos();
+        proto.launcher = proto.launcher != null ? proto.launcher : new LauncherTraceProto();
+        for (ProtoTraceable t : traceables) {
+            t.writeToProto(proto.launcher);
+        }
+        return proto;
+    }
+
+    @Override
+    public byte[] serializeEncapsulatingProto(LauncherTraceFileProto encapsulatingProto,
+            Queue<LauncherTraceEntryProto> buffer) {
+        encapsulatingProto.magicNumber = MAGIC_NUMBER_VALUE;
+        encapsulatingProto.entry = buffer.toArray(new LauncherTraceEntryProto[0]);
+        return MessageNano.toByteArray(encapsulatingProto);
+    }
+
+    @Override
+    public byte[] getProtoBytes(MessageNano proto) {
+        return MessageNano.toByteArray(proto);
+    }
+
+    @Override
+    public int getProtoSize(MessageNano proto) {
+        return proto.getCachedSize();
+    }
+
+    public void start() {
+        mProtoTracer.start();
+    }
+
+    public void stop() {
+        mProtoTracer.stop();
+    }
+
+    public void add(ProtoTraceable<LauncherTraceProto> traceable) {
+        mProtoTracer.add(traceable);
+    }
+
+    public void remove(ProtoTraceable<LauncherTraceProto> traceable) {
+        mProtoTracer.remove(traceable);
+    }
+
+    public void scheduleFrameUpdate() {
+        mProtoTracer.scheduleFrameUpdate();
+    }
+
+    public void update() {
+        mProtoTracer.update();
+    }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index ef1698e..fe78a84 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -92,6 +92,7 @@
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PropertyListBuilder;
 import com.android.launcher3.anim.SpringObjectAnimator;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.graphics.RotationMode;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -972,6 +973,10 @@
         TaskView runningTask = getRunningTaskView();
         if (runningTask != null) {
             runningTask.setStableAlpha(isHidden ? 0 : mContentAlpha);
+            if (!isHidden) {
+                AccessibilityManagerCompat.sendCustomAccessibilityEvent(runningTask,
+                        AccessibilityEvent.TYPE_VIEW_FOCUSED, null);
+            }
         }
     }
 
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index 327bb14..a688f9a 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -13,11 +13,13 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<resources>
-    <string name="task_overlay_factory_class" translatable="false"></string>
+<resources xmlns:tools="http://schemas.android.com/tools">
+    <string name="task_overlay_factory_class" translatable="false"/>
 
-    <!-- Activity which blocks home gesture -->
-    <string name="gesture_blocking_activity" translatable="false"></string>
+    <!-- Activities which block home gesture -->
+    <string-array name="gesture_blocking_activities" tools:ignore="InconsistentArrays">
+        <item>com.android.launcher3/com.android.quickstep.interaction.GestureSandboxActivity</item>
+    </string-array>
 
     <string name="stats_log_manager_class" translatable="false">com.android.quickstep.logging.StatsLogCompatManager</string>
 
@@ -32,5 +34,5 @@
     <integer name="assistant_gesture_min_time_threshold">200</integer>
     <integer name="assistant_gesture_corner_deg_threshold">20</integer>
 
-    <string name="wellbeing_provider_pkg" translatable="false"></string>
+    <string name="wellbeing_provider_pkg" translatable="false"/>
 </resources>
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index e88a8a4..b5e05ee 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -54,6 +54,12 @@
     }
 
     @Override
+    public void onStateDisabled(Launcher launcher) {
+        super.onStateDisabled(launcher);
+        AbstractFloatingView.closeAllOpenViews(launcher);
+    }
+
+    @Override
     public String getDescription(Launcher launcher) {
         AllAppsContainerView appsView = launcher.getAppsView();
         return appsView.getDescription();
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 4b33d21..abe1592 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -66,6 +66,8 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * Manages the state of the system during a swipe up gesture.
@@ -107,7 +109,7 @@
     private Region mExclusionRegion;
     private SystemGestureExclusionListenerCompat mExclusionListener;
 
-    private ComponentName mGestureBlockedActivity;
+    private final List<ComponentName> mGestureBlockedActivities;
 
     public RecentsAnimationDeviceState(Context context) {
         final ContentResolver resolver = context.getContentResolver();
@@ -142,9 +144,19 @@
         runOnDestroy(() -> mSysUiNavMode.removeModeChangeListener(this));
 
         // Add any blocked activities
-        String blockingActivity = context.getString(R.string.gesture_blocking_activity);
-        if (!TextUtils.isEmpty(blockingActivity)) {
-            mGestureBlockedActivity = ComponentName.unflattenFromString(blockingActivity);
+        String[] blockingActivities;
+        try {
+            blockingActivities =
+                    context.getResources().getStringArray(R.array.gesture_blocking_activities);
+        } catch (Resources.NotFoundException e) {
+            blockingActivities = new String[0];
+        }
+        mGestureBlockedActivities = new ArrayList<>(blockingActivities.length);
+        for (String blockingActivity : blockingActivities) {
+            if (!TextUtils.isEmpty(blockingActivity)) {
+                mGestureBlockedActivities.add(
+                        ComponentName.unflattenFromString(blockingActivity));
+            }
         }
     }
 
@@ -272,17 +284,16 @@
      * @return whether the given running task info matches the gesture-blocked activity.
      */
     public boolean isGestureBlockedActivity(ActivityManager.RunningTaskInfo runningTaskInfo) {
-        return runningTaskInfo != null && mGestureBlockedActivity != null
-                && mGestureBlockedActivity.equals(runningTaskInfo.topActivity);
+        return runningTaskInfo != null
+                && mGestureBlockedActivities.contains(runningTaskInfo.topActivity);
     }
 
     /**
-     * @return the package of the gesture-blocked activity or {@code null} if there is none.
+     * @return the packages of gesture-blocked activities.
      */
-    public String getGestureBlockedActivityPackage() {
-        return (mGestureBlockedActivity != null)
-                ? mGestureBlockedActivity.getPackageName()
-                : null;
+    public List<String> getGestureBlockedActivityPackages() {
+        return mGestureBlockedActivities.stream().map(ComponentName::getPackageName)
+                .collect(Collectors.toList());
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialActivity.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
similarity index 76%
rename from quickstep/src/com/android/quickstep/interaction/BackGestureTutorialActivity.java
rename to quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
index 295ab48..8081ad7 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
@@ -16,7 +16,10 @@
 package com.android.quickstep.interaction;
 
 import android.graphics.Color;
+import android.graphics.Rect;
 import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.view.Display;
 import android.view.View;
 import android.view.Window;
 
@@ -26,10 +29,11 @@
 import com.android.quickstep.interaction.BackGestureTutorialFragment.TutorialStep;
 import com.android.quickstep.interaction.BackGestureTutorialFragment.TutorialType;
 
+import java.util.List;
 import java.util.Optional;
 
-/** Shows the Back gesture interactive tutorial in full screen mode. */
-public class BackGestureTutorialActivity extends FragmentActivity {
+/** Shows the gesture interactive sandbox in full screen mode. */
+public class GestureSandboxActivity extends FragmentActivity {
 
     Optional<BackGestureTutorialFragment> mFragment = Optional.empty();
 
@@ -47,6 +51,12 @@
     }
 
     @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        disableSystemGestures();
+    }
+
+    @Override
     public void onWindowFocusChanged(boolean hasFocus) {
         super.onWindowFocusChanged(hasFocus);
         if (hasFocus) {
@@ -70,4 +80,14 @@
                         | View.SYSTEM_UI_FLAG_FULLSCREEN);
         getWindow().setNavigationBarColor(Color.TRANSPARENT);
     }
+
+    private void disableSystemGestures() {
+        Display display = getDisplay();
+        if (display != null) {
+            DisplayMetrics metrics = new DisplayMetrics();
+            display.getMetrics(metrics);
+            getWindow().setSystemGestureExclusionRects(
+                    List.of(new Rect(0, 0, metrics.widthPixels, metrics.heightPixels)));
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
index 801a560..d8b10b6 100644
--- a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
+++ b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
@@ -37,8 +37,7 @@
     private static final long FORCE_PAUSE_TIMEOUT = 300;
 
     /**
-     * After {@link #makePauseHarderToTrigger()}, must
-     * move slowly for this long to trigger a pause.
+     * After {@link #mMakePauseHarderToTrigger}, must move slowly for this long to trigger a pause.
      */
     private static final long HARDER_TRIGGER_TIMEOUT = 400;
 
@@ -49,13 +48,10 @@
     private final Alarm mForcePauseTimeout;
     private final boolean mMakePauseHarderToTrigger;
     private final Context mContext;
+    private final VelocityProvider mVelocityProvider;
 
-    private Long mPreviousTime = null;
-    private Float mPreviousPosition = null;
     private Float mPreviousVelocity = null;
 
-    private Float mFirstPosition = null;
-
     private OnMotionPauseListener mOnMotionPauseListener;
     private boolean mIsPaused;
     // Bias more for the first pause to make it feel extra responsive.
@@ -73,6 +69,13 @@
      * @param makePauseHarderToTrigger Used for gestures that require a more explicit pause.
      */
     public MotionPauseDetector(Context context, boolean makePauseHarderToTrigger) {
+        this(context, makePauseHarderToTrigger, MotionEvent.AXIS_Y);
+    }
+
+    /**
+     * @param makePauseHarderToTrigger Used for gestures that require a more explicit pause.
+     */
+    public MotionPauseDetector(Context context, boolean makePauseHarderToTrigger, int axis) {
         mContext = context;
         Resources res = context.getResources();
         mSpeedVerySlow = res.getDimension(R.dimen.motion_pause_detector_speed_very_slow);
@@ -82,6 +85,7 @@
         mForcePauseTimeout = new Alarm();
         mForcePauseTimeout.setOnAlarmListener(alarm -> updatePaused(true /* isPaused */));
         mMakePauseHarderToTrigger = makePauseHarderToTrigger;
+        mVelocityProvider = new LinearVelocityProvider(axis);
     }
 
     /**
@@ -101,28 +105,28 @@
 
     /**
      * Computes velocity and acceleration to determine whether the motion is paused.
-     * @param position The x or y component of the motion being tracked.
+     * @param ev The motion being tracked.
      *
      * TODO: Use historical positions as well, e.g. {@link MotionEvent#getHistoricalY(int, int)}.
      */
-    public void addPosition(float position, long time) {
-        if (mFirstPosition == null) {
-            mFirstPosition = position;
-        }
+    public void addPosition(MotionEvent ev) {
+        addPosition(ev, 0);
+    }
+
+    /**
+     * Computes velocity and acceleration to determine whether the motion is paused.
+     * @param ev The motion being tracked.
+     * @param pointerIndex Index for the pointer being tracked in the motion event
+     */
+    public void addPosition(MotionEvent ev, int pointerIndex) {
         mForcePauseTimeout.setAlarm(mMakePauseHarderToTrigger
                 ? HARDER_TRIGGER_TIMEOUT
                 : FORCE_PAUSE_TIMEOUT);
-        if (mPreviousTime != null && mPreviousPosition != null) {
-            long changeInTime = Math.max(1, time - mPreviousTime);
-            float changeInPosition = position - mPreviousPosition;
-            float velocity = changeInPosition / changeInTime;
-            if (mPreviousVelocity != null) {
-                checkMotionPaused(velocity, mPreviousVelocity, time);
-            }
-            mPreviousVelocity = velocity;
+        Float newVelocity = mVelocityProvider.addMotionEvent(ev, pointerIndex);
+        if (newVelocity != null && mPreviousVelocity != null) {
+            checkMotionPaused(newVelocity, mPreviousVelocity, ev.getEventTime());
         }
-        mPreviousTime = time;
-        mPreviousPosition = position;
+        mPreviousVelocity = newVelocity;
     }
 
     private void checkMotionPaused(float velocity, float prevVelocity, long time) {
@@ -178,10 +182,8 @@
     }
 
     public void clear() {
-        mPreviousTime = null;
-        mPreviousPosition = null;
+        mVelocityProvider.clear();
         mPreviousVelocity = null;
-        mFirstPosition = null;
         setOnMotionPauseListener(null);
         mIsPaused = mHasEverBeenPaused = false;
         mSlowStartTime = 0;
@@ -195,4 +197,55 @@
     public interface OnMotionPauseListener {
         void onMotionPauseChanged(boolean isPaused);
     }
+
+    /**
+     * Interface to abstract out velocity calculations
+     */
+    protected interface VelocityProvider {
+
+        /**
+         * Adds a new motion events, and returns the velocity at this point, or null if
+         * the velocity is not available
+         */
+        Float addMotionEvent(MotionEvent ev, int pointer);
+
+        /**
+         * Clears all stored motion event records
+         */
+        void clear();
+    }
+
+    private static class LinearVelocityProvider implements VelocityProvider {
+
+        private Long mPreviousTime = null;
+        private Float mPreviousPosition = null;
+
+        private final int mAxis;
+
+        LinearVelocityProvider(int axis) {
+            mAxis = axis;
+        }
+
+        @Override
+        public Float addMotionEvent(MotionEvent ev, int pointer) {
+            long time = ev.getEventTime();
+            float position = ev.getAxisValue(mAxis, pointer);
+            Float velocity = null;
+
+            if (mPreviousTime != null && mPreviousPosition != null) {
+                long changeInTime = Math.max(1, time - mPreviousTime);
+                float changeInPosition = position - mPreviousPosition;
+                velocity = changeInPosition / changeInTime;
+            }
+            mPreviousTime = time;
+            mPreviousPosition = position;
+            return velocity;
+        }
+
+        @Override
+        public void clear() {
+            mPreviousTime = null;
+            mPreviousPosition = null;
+        }
+    }
 }
diff --git a/res/layout/work_apps_paused.xml b/res/layout/work_apps_paused.xml
index 33502d0..1c18076 100644
--- a/res/layout/work_apps_paused.xml
+++ b/res/layout/work_apps_paused.xml
@@ -15,9 +15,9 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:background="?attr/allAppsScrimColor"
     android:padding="8dp"
     android:orientation="vertical"
-    android:background="?attr/allAppsScrimColor"
     android:gravity="center">
 
     <ImageView
@@ -38,7 +38,7 @@
         android:layout_marginBottom="8dp"
         android:text="@string/work_apps_paused_title"
         android:textAlignment="center"
-        android:textSize="24sp" />
+        android:textSize="20sp" />
 
     <TextView
         android:layout_width="wrap_content"
diff --git a/res/layout/work_profile_edu.xml b/res/layout/work_profile_edu.xml
index f7a529d..04094c4 100644
--- a/res/layout/work_profile_edu.xml
+++ b/res/layout/work_profile_edu.xml
@@ -21,22 +21,22 @@
 
     <View
         android:layout_width="match_parent"
-        android:backgroundTint="@color/bottom_panel_background"
         android:layout_height="32dp"
-        android:background="@drawable/bottom_sheet_top_border" />
+        android:background="@drawable/bottom_sheet_top_border"
+        android:backgroundTint="?android:attr/colorAccent" />
 
     <LinearLayout
         android:id="@+id/view_wrapper"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:background="@color/bottom_panel_background"
+        android:background="?android:attr/colorAccent"
         android:orientation="vertical"
         android:paddingLeft="@dimen/bottom_sheet_edu_padding"
         android:paddingRight="@dimen/bottom_sheet_edu_padding">
 
         <TextView
-            style="@style/TextHeadline"
             android:id="@+id/content_text"
+            style="@style/TextHeadline"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_marginTop="48dp"
@@ -57,5 +57,4 @@
             android:textAlignment="center"
             android:textColor="@android:color/white" />
     </LinearLayout>
-
 </com.android.launcher3.views.WorkEduView>
\ No newline at end of file
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 36f8468..194ef2c 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -45,5 +45,4 @@
     <color name="back_gesture_tutorial_primary_color">#1A73E8</color> <!-- Blue -->
 
 
-    <color name="bottom_panel_background">#f01A73E8</color>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index bde3c31..9d0fb56 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -142,7 +142,7 @@
     <string name="uninstall_system_app_text">This is a system app and can\'t be uninstalled.</string>
 
     <!-- Default folder title -->
-    <string name="folder_hint_text">Tap to edit</string>
+    <string name="folder_hint_text">Edit Name</string>
 
     <!-- Accessibility -->
     <!-- The format string for when an app is temporarily disabled. -->
@@ -330,7 +330,7 @@
     <!--- User onboarding title for personal apps -->
     <string name="work_profile_edu_personal_apps">Personal apps are private &amp; can\'t be seen by IT</string>
     <!--- User onboarding title for work profile apps -->
-    <string name="work_profile_edu_work_apps">Work apps are badged and monitored by IT</string>
+    <string name="work_profile_edu_work_apps">Work apps are badged &amp; visible to IT</string>
     <!-- Action label to proceed to the next work profile edu section-->
     <string name="work_profile_edu_next">Next</string>
     <!-- Action label to finish work profile edu-->
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 3a275ff..3fc8de2 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -482,7 +482,6 @@
     @Override
     public void onEnterAnimationComplete() {
         super.onEnterAnimationComplete();
-        mAllAppsController.highlightWorkTabIfNecessary();
         mRotationHelper.setCurrentTransitionRequest(REQUEST_NONE);
     }
 
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index ac0fef8..f618fe1 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -66,7 +66,6 @@
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Optional;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.Executor;
 import java.util.function.Supplier;
@@ -127,16 +126,6 @@
     }
 
     /**
-     * Returns AppInfo with corresponding package name.
-     * TODO: move to enqueueModelTask
-     */
-    public Optional<AppInfo> getAppInfoByPackageName(String pkg) {
-        return mBgAllAppsList.data.stream()
-                .filter(info -> info.componentName.getPackageName().equals(pkg))
-                .findAny();
-    }
-
-    /**
      * Adds the provided items to the workspace.
      */
     public void addAndBindAddedWorkspaceItems(List<Pair<ItemInfo, Object>> itemList) {
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 4c6e1f3..01893e9 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -374,6 +374,8 @@
     protected void onPageEndTransition() {
         mWasInOverscroll = false;
         AccessibilityManagerCompat.sendScrollFinishedEventToTest(getContext());
+        AccessibilityManagerCompat.sendCustomAccessibilityEvent(getPageAt(mCurrentPage),
+                AccessibilityEvent.TYPE_VIEW_FOCUSED, null);
     }
 
     protected int getUnboundedScrollX() {
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 4e5b031..fcccc59 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -103,6 +103,8 @@
 
     private final MultiValueAlpha mMultiValueAlpha;
 
+    Rect mInsets = new Rect();
+
     public AllAppsContainerView(Context context) {
         this(context, null);
     }
@@ -325,6 +327,7 @@
 
     @Override
     public void setInsets(Rect insets) {
+        mInsets.set(insets);
         DeviceProfile grid = mLauncher.getDeviceProfile();
         int leftRightPadding = grid.desiredWorkspaceLeftRightMarginPx
                 + grid.cellLayoutPaddingLeftRightPx;
@@ -416,6 +419,7 @@
                 new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                         ViewGroup.LayoutParams.WRAP_CONTENT));
         this.addView(mWorkFooterContainer);
+        mWorkFooterContainer.setInsets(mInsets);
         mWorkFooterContainer.post(() -> mAH[AdapterHolder.WORK].applyPadding());
     }
 
@@ -553,17 +557,6 @@
         return mHeader != null && mHeader.getVisibility() == View.VISIBLE;
     }
 
-    public void onScrollUpEnd() {
-        highlightWorkTabIfNecessary();
-    }
-
-    void highlightWorkTabIfNecessary() {
-        if (mUsingTabs) {
-            ((PersonalWorkSlidingTabStrip) findViewById(R.id.tabs))
-                    .highlightWorkTabIfNecessary();
-        }
-    }
-
     /**
      * Adds an update listener to {@param animator} that adds springs to the animation.
      */
@@ -648,9 +641,9 @@
                         R.layout.work_apps_paused, null);
                 recyclerView.post(() -> {
                     int width = recyclerView.getWidth();
-                    int height = recyclerView.getHeight();
-                    pausedOverlay.measure(makeMeasureSpec(width, EXACTLY),
-                            makeMeasureSpec(height, EXACTLY));
+                    int height = recyclerView.getHeight() -  mWorkFooterContainer.getHeight();
+                    pausedOverlay.measure(makeMeasureSpec(recyclerView.getWidth(), EXACTLY),
+                            makeMeasureSpec(recyclerView.getHeight(), EXACTLY));
                     pausedOverlay.layout(0, 0, width, height);
                     applyPadding();
                 });
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 93bdac9..6aa3efc 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -248,18 +248,6 @@
     private void onProgressAnimationEnd() {
         if (Float.compare(mProgress, 1f) == 0) {
             mAppsView.reset(false /* animate */);
-        } else if (isAllAppsExpanded()) {
-            mAppsView.onScrollUpEnd();
-        }
-    }
-
-    private boolean isAllAppsExpanded() {
-        return Float.compare(mProgress, 0f) == 0;
-    }
-
-    public void highlightWorkTabIfNecessary() {
-        if (isAllAppsExpanded()) {
-            mAppsView.highlightWorkTabIfNecessary();
         }
     }
 }
diff --git a/src/com/android/launcher3/allapps/DiscoveryBounce.java b/src/com/android/launcher3/allapps/DiscoveryBounce.java
index e8035eb..0f0fc3a 100644
--- a/src/com/android/launcher3/allapps/DiscoveryBounce.java
+++ b/src/com/android/launcher3/allapps/DiscoveryBounce.java
@@ -35,7 +35,6 @@
 import com.android.launcher3.LauncherStateManager.StateListener;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.pm.UserCache;
 
 /**
  * Abstract base class of floating view responsible for showing discovery bounce animation
@@ -144,8 +143,7 @@
 
     private static void showForHomeIfNeeded(Launcher launcher, boolean withDelay) {
         if (!launcher.isInState(NORMAL)
-                || (launcher.getSharedPrefs().getBoolean(HOME_BOUNCE_SEEN, false)
-                && !shouldShowForWorkProfile(launcher))
+                || launcher.getSharedPrefs().getBoolean(HOME_BOUNCE_SEEN, false)
                 || AbstractFloatingView.getTopOpenView(launcher) != null
                 || launcher.getSystemService(UserManager.class).isDemoUser()
                 || Utilities.IS_RUNNING_IN_TEST_HARNESS) {
@@ -170,8 +168,7 @@
                 || !launcher.hasBeenResumed()
                 || launcher.isForceInvisible()
                 || launcher.getDeviceProfile().isVerticalBarLayout()
-                || (launcher.getSharedPrefs().getBoolean(SHELF_BOUNCE_SEEN, false)
-                && !shouldShowForWorkProfile(launcher))
+                || launcher.getSharedPrefs().getBoolean(SHELF_BOUNCE_SEEN, false)
                 || launcher.getSystemService(UserManager.class).isDemoUser()
                 || Utilities.IS_RUNNING_IN_TEST_HARNESS) {
             return;
@@ -213,12 +210,6 @@
         }
     }
 
-    private static boolean shouldShowForWorkProfile(Launcher launcher) {
-        return !launcher.getSharedPrefs().getBoolean(
-                PersonalWorkSlidingTabStrip.KEY_SHOWED_PEEK_WORK_TAB, false)
-                && UserCache.INSTANCE.get(launcher).hasWorkProfile();
-    }
-
     private static void incrementShelfBounceCount(Launcher launcher) {
         SharedPreferences sharedPrefs = launcher.getSharedPrefs();
         int count = sharedPrefs.getInt(SHELF_BOUNCE_COUNT, 0);
diff --git a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
index 9d0ecd3..25db0e7 100644
--- a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
@@ -64,6 +64,14 @@
     }
 
     @Override
+    public void setupHeader() {
+        super.setupHeader();
+        if (mWorkTabListener != null && !mUsingTabs) {
+            mLauncher.getStateManager().removeStateListener(mWorkTabListener);
+        }
+    }
+
+    @Override
     public void onTabChanged(int pos) {
         super.onTabChanged(pos);
         if (mUsingTabs) {
diff --git a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
index 6204f31..0e39bbe 100644
--- a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
+++ b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
@@ -16,7 +16,6 @@
 package com.android.launcher3.allapps;
 
 import android.content.Context;
-import android.content.SharedPreferences;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.util.AttributeSet;
@@ -39,11 +38,8 @@
     private static final int POSITION_PERSONAL = 0;
     private static final int POSITION_WORK = 1;
 
-    public static final String KEY_SHOWED_PEEK_WORK_TAB = "showed_peek_work_tab";
-
     private final Paint mSelectedIndicatorPaint;
     private final Paint mDividerPaint;
-    private final SharedPreferences mSharedPreferences;
 
     private int mSelectedIndicatorHeight;
     private int mIndicatorLeft = -1;
@@ -72,7 +68,6 @@
         mDividerPaint.setStrokeWidth(
                 getResources().getDimensionPixelSize(R.dimen.all_apps_divider_height));
 
-        mSharedPreferences = Utilities.getPrefs(context);
         mIsRtl = Utilities.isRtl(getResources());
     }
 
@@ -128,25 +123,6 @@
             mIndicatorRight, getHeight(), mSelectedIndicatorPaint);
     }
 
-    public void highlightWorkTabIfNecessary() {
-        if (mSharedPreferences.getBoolean(KEY_SHOWED_PEEK_WORK_TAB, false)) {
-            return;
-        }
-        if (mLastActivePage != POSITION_PERSONAL) {
-            return;
-        }
-        highlightWorkTab();
-        mSharedPreferences.edit().putBoolean(KEY_SHOWED_PEEK_WORK_TAB, true).apply();
-    }
-
-    private void highlightWorkTab() {
-        View v = getChildAt(POSITION_WORK);
-        v.post(() -> {
-            v.setPressed(true);
-            v.setPressed(false);
-        });
-    }
-
     @Override
     public void setScroll(int currentScroll, int totalScroll) {
         float scrollOffset = ((float) currentScroll) / totalScroll;
diff --git a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
index 28579c1..db4bef0 100644
--- a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
+++ b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
@@ -18,11 +18,14 @@
 
 import android.content.Context;
 import android.os.Bundle;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 
+import androidx.annotation.Nullable;
+
 import com.android.launcher3.Utilities;
 import com.android.launcher3.testing.TestProtocol;
 
@@ -37,11 +40,13 @@
         return isAccessibilityEnabled(context);
     }
 
-    public static void sendCustomAccessibilityEvent(View target, int type, String text) {
+    public static void sendCustomAccessibilityEvent(View target, int type, @Nullable String text) {
         if (isObservedEventType(target.getContext(), type)) {
             AccessibilityEvent event = AccessibilityEvent.obtain(type);
             target.onInitializeAccessibilityEvent(event);
-            event.getText().add(text);
+            if (!TextUtils.isEmpty(text)) {
+                event.getText().add(text);
+            }
             getManager(target.getContext()).sendAccessibilityEvent(event);
         }
     }
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index 1b7b015..de7bc6d 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -160,8 +160,8 @@
 
         mOptions = options;
         if (mOptions.systemDndStartPoint != null) {
-            mMotionDownX = mOptions.systemDndStartPoint.x;
-            mMotionDownY = mOptions.systemDndStartPoint.y;
+            mLastTouch[0] = mMotionDownX = mOptions.systemDndStartPoint.x;
+            mLastTouch[1] = mMotionDownY = mOptions.systemDndStartPoint.y;
         }
 
         final int registrationX = mMotionDownX - dragLayerX;
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 1b45f10..c72509e 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -326,7 +326,7 @@
                             (FolderNameInfo[]) mInfo.suggestedFolderNames.getParcelableArrayExtra(
                                     FolderInfo.EXTRA_FOLDER_SUGGESTIONS);
                     if (nameInfos != null) {
-                        showLabelSuggestion(nameInfos);
+                        showLabelSuggestion(nameInfos, false);
                     }
                 }
             }
@@ -350,18 +350,11 @@
         mFolderIcon.onTitleChanged(newTitle);
         mLauncher.getModelWriter().updateItemInDatabase(mInfo);
 
-        if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
-            mFolderName.setText(mInfo.title);
-            // TODO: depending on whether the title was manually edited or automatically
-            // suggested, apply different hint.
-            mFolderName.setHint("");
+        if (TextUtils.isEmpty(mInfo.title)) {
+            mFolderName.setHint(R.string.folder_hint_text);
+            mFolderName.setText("");
         } else {
-            if (isEmpty(mInfo.title)) {
-                mFolderName.setHint(R.string.folder_hint_text);
-                mFolderName.setText("");
-            } else {
-                mFolderName.setHint(null);
-            }
+            mFolderName.setHint(null);
         }
 
         sendCustomAccessibilityEvent(
@@ -475,7 +468,7 @@
                     nameInfos);
             if (isEmpty(mFolderName.getText().toString())
                     && !mInfo.hasOption(FLAG_MANUAL_FOLDER_NAME)) {
-                showLabelSuggestion(nameInfos);
+                showLabelSuggestion(nameInfos, true);
             }
         }
     }
@@ -484,7 +477,7 @@
      * Show suggested folder title in FolderEditText if the first suggestion is non-empty, push
      * InputMethodManager suggestions.
      */
-    private void showLabelSuggestion(FolderNameInfo[] nameInfos) {
+    private void showLabelSuggestion(FolderNameInfo[] nameInfos, boolean animate) {
         if (nameInfos == null) {
             return;
         }
@@ -494,15 +487,16 @@
                 nameInfos[0].getLabel())
                 || nameInfos.length > 1 && nameInfos[1] != null && !isEmpty(
                 nameInfos[1].getLabel());
-        CharSequence firstLabel = nameInfos[0].getLabel();
 
         if (shouldOpen) {
+            CharSequence firstLabel = nameInfos[0] == null ? "" : nameInfos[0].getLabel();
             if (!isEmpty(firstLabel)) {
                 mFolderName.setHint("");
                 mFolderName.setText(firstLabel);
-                mInfo.title = firstLabel;
             }
-            animateOpen(mInfo.contents, 0, true);
+            if (animate) {
+                animateOpen(mInfo.contents, 0, true);
+            }
             mFolderName.showKeyboard();
             mFolderName.displayCompletions(
                     asList(nameInfos).subList(1, nameInfos.length).stream()
@@ -1658,6 +1652,7 @@
                         .getParcelableArrayExtra(FolderInfo.EXTRA_FOLDER_SUGGESTIONS))
                 .map(folderNameInfoArray ->
                         stream(folderNameInfoArray)
+                                .filter(Objects::nonNull)
                                 .map(FolderNameInfo::getLabel)
                                 .map(CharSequence::toString)
                                 .toArray(String[]::new));
diff --git a/src/com/android/launcher3/folder/FolderNameInfo.java b/src/com/android/launcher3/folder/FolderNameInfo.java
index eb9da90..ecbe46c 100644
--- a/src/com/android/launcher3/folder/FolderNameInfo.java
+++ b/src/com/android/launcher3/folder/FolderNameInfo.java
@@ -80,4 +80,10 @@
     public int describeContents() {
         return 0;
     }
+
+    @Override
+    @NonNull
+    public String toString() {
+        return mLabel.toString() + ":" + mScore;
+    }
 }
diff --git a/src/com/android/launcher3/folder/FolderNameProvider.java b/src/com/android/launcher3/folder/FolderNameProvider.java
index d5990fa..184dbb9 100644
--- a/src/com/android/launcher3/folder/FolderNameProvider.java
+++ b/src/com/android/launcher3/folder/FolderNameProvider.java
@@ -21,9 +21,14 @@
 import android.util.Log;
 
 import com.android.launcher3.AppInfo;
+import com.android.launcher3.FolderInfo;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.WorkspaceItemInfo;
+import com.android.launcher3.model.AllAppsList;
+import com.android.launcher3.model.BaseModelUpdateTask;
+import com.android.launcher3.model.BgDataModel;
+import com.android.launcher3.util.IntSparseArrayMap;
 import com.android.launcher3.util.ResourceBasedOverride;
 
 import java.util.ArrayList;
@@ -50,6 +55,8 @@
      * name edit box can also be used to provide suggestion.
      */
     public static final int SUGGEST_MAX = 4;
+    protected IntSparseArrayMap<FolderInfo> mFolderInfos;
+    protected List<AppInfo> mAppInfos;
 
     /**
      * Retrieve instance of this object that can be overridden in runtime based on the build
@@ -58,9 +65,30 @@
     public static FolderNameProvider newInstance(Context context) {
         FolderNameProvider fnp = Overrides.getObject(FolderNameProvider.class,
                 context.getApplicationContext(), R.string.folder_name_provider_class);
+        fnp.load(context);
+
         return fnp;
     }
 
+    public static FolderNameProvider newInstance(Context context, List<AppInfo> appInfos,
+            IntSparseArrayMap<FolderInfo> folderInfos) {
+        FolderNameProvider fnp = Overrides.getObject(FolderNameProvider.class,
+                context.getApplicationContext(), R.string.folder_name_provider_class);
+        fnp.load(appInfos, folderInfos);
+
+        return fnp;
+    }
+
+    private void load(Context context) {
+        LauncherAppState.getInstance(context).getModel().enqueueModelUpdateTask(
+                new FolderNameWorker());
+    }
+
+    private void load(List<AppInfo> appInfos, IntSparseArrayMap<FolderInfo> folderInfos) {
+        mAppInfos = appInfos;
+        mFolderInfos = folderInfos;
+    }
+
     /**
      * Generate and rank the suggested Folder names.
      */
@@ -92,9 +120,8 @@
                 .collect(Collectors.toList());
 
         if (distinctItemInfos.size() == 1) {
-            Optional<AppInfo> info = LauncherAppState.getInstance(context).getModel()
-                    .getAppInfoByPackageName(distinctItemInfos.get(0).getTargetComponent()
-                            .getPackageName());
+            Optional<AppInfo> info = getAppInfoByPackageName(
+                    distinctItemInfos.get(0).getTargetComponent().getPackageName());
             // Place it as first viable suggestion and shift everything else
             info.ifPresent(i -> setAsFirstSuggestion(nameInfos, i.title.toString()));
         }
@@ -103,6 +130,15 @@
         }
     }
 
+    private Optional<AppInfo> getAppInfoByPackageName(String packageName) {
+        if (mAppInfos == null || mAppInfos.isEmpty()) {
+            return Optional.empty();
+        }
+        return mAppInfos.stream()
+                .filter(info -> info.componentName.getPackageName().equals(packageName))
+                .findAny();
+    }
+
     private void setAsFirstSuggestion(FolderNameInfo[] nameInfos, CharSequence label) {
         if (nameInfos.length == 0 || contains(nameInfos, label)) {
             return;
@@ -143,4 +179,13 @@
         Map<Object, Boolean> map = new ConcurrentHashMap<>();
         return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
     }
+
+    private class FolderNameWorker extends BaseModelUpdateTask {
+        @Override
+        public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
+            mFolderInfos = dataModel.folders.clone();
+            mAppInfos = Arrays.asList(apps.copyData());
+        }
+    }
+
 }
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index def76e8..a429af2 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -25,6 +25,7 @@
 
 import android.annotation.TargetApi;
 import android.app.Fragment;
+import android.appwidget.AppWidgetHostView;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.TypedArray;
@@ -55,6 +56,7 @@
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherAppWidgetInfo;
 import com.android.launcher3.LauncherModel;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
@@ -72,6 +74,8 @@
 import com.android.launcher3.model.BgDataModel;
 import com.android.launcher3.model.BgDataModel.Callbacks;
 import com.android.launcher3.model.LoaderResults;
+import com.android.launcher3.model.WidgetItem;
+import com.android.launcher3.model.WidgetsModel;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.BaseDragLayer;
 
@@ -248,6 +252,16 @@
             addInScreenFromBind(folderIcon, info);
         }
 
+        private void inflateAndAddWidgets(LauncherAppWidgetInfo info, WidgetsModel widgetsModel) {
+            WidgetItem widgetItem = widgetsModel.getWidgetProviderInfoByProviderName(
+                    info.providerName);
+            AppWidgetHostView view = new AppWidgetHostView(mContext);
+            view.setAppWidget(-1, widgetItem.widgetInfo);
+            view.updateAppWidget(null);
+            view.setTag(info);
+            addInScreenFromBind(view, info);
+        }
+
         private void dispatchVisibilityAggregated(View view, boolean isVisible) {
             // Similar to View.dispatchVisibilityAggregated implementation.
             final boolean thisVisible = view.getVisibility() == VISIBLE;
@@ -272,9 +286,9 @@
                         mContext).getModel();
                 final WorkspaceItemsInfoFetcher fetcher = new WorkspaceItemsInfoFetcher();
                 launcherModel.enqueueModelUpdateTask(fetcher);
-                ArrayList<ItemInfo> workspaceItems;
+                WorkspaceResult workspaceResult;
                 try {
-                    workspaceItems = fetcher.mTask.get(5, TimeUnit.SECONDS);
+                    workspaceResult = fetcher.mTask.get(5, TimeUnit.SECONDS);
                 } catch (InterruptedException | ExecutionException | TimeoutException e) {
                     Log.d(TAG, "Error fetching workspace items info", e);
                     return;
@@ -284,9 +298,14 @@
                 // items
                 ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<>();
                 ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<>();
+                ArrayList<LauncherAppWidgetInfo> currentAppWidgets = new ArrayList<>();
+                ArrayList<LauncherAppWidgetInfo> otherAppWidgets = new ArrayList<>();
 
-                filterCurrentWorkspaceItems(0 /* currentScreenId */, workspaceItems,
-                        currentWorkspaceItems, otherWorkspaceItems);
+                filterCurrentWorkspaceItems(0 /* currentScreenId */,
+                        workspaceResult.mWorkspaceItems, currentWorkspaceItems,
+                        otherWorkspaceItems);
+                filterCurrentWorkspaceItems(0 /* currentScreenId */, workspaceResult.mAppWidgets,
+                        currentAppWidgets, otherAppWidgets);
                 sortWorkspaceItemsSpatially(mIdp, currentWorkspaceItems);
 
                 for (ItemInfo itemInfo : currentWorkspaceItems) {
@@ -303,6 +322,17 @@
                             break;
                     }
                 }
+                for (ItemInfo itemInfo : currentAppWidgets) {
+                    switch (itemInfo.itemType) {
+                        case Favorites.ITEM_TYPE_APPWIDGET:
+                        case Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
+                            inflateAndAddWidgets((LauncherAppWidgetInfo) itemInfo,
+                                    workspaceResult.mWidgetsModel);
+                            break;
+                        default:
+                            break;
+                    }
+                }
             } else {
                 // Add hotseat icons
                 for (int i = 0; i < mIdp.numHotseatIcons; i++) {
@@ -349,10 +379,10 @@
         }
     }
 
-    private static class WorkspaceItemsInfoFetcher implements Callable<ArrayList<ItemInfo>>,
+    private static class WorkspaceItemsInfoFetcher implements Callable<WorkspaceResult>,
             LauncherModel.ModelUpdateTask {
 
-        private final FutureTask<ArrayList<ItemInfo>> mTask = new FutureTask<>(this);
+        private final FutureTask<WorkspaceResult> mTask = new FutureTask<>(this);
 
         private LauncherAppState mApp;
         private LauncherModel mModel;
@@ -374,14 +404,16 @@
         }
 
         @Override
-        public ArrayList<ItemInfo> call() throws Exception {
+        public WorkspaceResult call() throws Exception {
             if (!mModel.isModelLoaded()) {
                 Log.d(TAG, "Workspace not loaded, loading now");
                 mModel.startLoaderForResults(
                         new LoaderResults(mApp, mBgDataModel, mAllAppsList, new Callbacks[0]));
-                return new ArrayList<>();
+                return null;
             }
-            return mBgDataModel.workspaceItems;
+
+            return new WorkspaceResult(mBgDataModel.workspaceItems, mBgDataModel.appWidgets,
+                    mBgDataModel.widgetsModel);
         }
     }
 
@@ -389,4 +421,17 @@
         view.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY));
         view.layout(0, 0, width, height);
     }
+
+    private static class WorkspaceResult {
+        private final ArrayList<ItemInfo> mWorkspaceItems;
+        private final ArrayList<LauncherAppWidgetInfo> mAppWidgets;
+        private final WidgetsModel mWidgetsModel;
+
+        private WorkspaceResult(ArrayList<ItemInfo> workspaceItems,
+                ArrayList<LauncherAppWidgetInfo> appWidgets, WidgetsModel widgetsModel) {
+            mWorkspaceItems = workspaceItems;
+            mAppWidgets = appWidgets;
+            mWidgetsModel = widgetsModel;
+        }
+    }
 }
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index af802ef..6223a23 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -901,7 +901,8 @@
     }
 
     private void loadFolderNames() {
-        FolderNameProvider provider = FolderNameProvider.newInstance(mApp.getContext());
+        FolderNameProvider provider = FolderNameProvider.newInstance(mApp.getContext(),
+                mBgAllAppsList.data, mBgDataModel.folders);
 
         synchronized (mBgDataModel) {
             for (int i = 0; i < mBgDataModel.folders.size(); i++) {
diff --git a/src/com/android/launcher3/model/PackageItemInfo.java b/src/com/android/launcher3/model/PackageItemInfo.java
index 3ef48cd..2fc064c 100644
--- a/src/com/android/launcher3/model/PackageItemInfo.java
+++ b/src/com/android/launcher3/model/PackageItemInfo.java
@@ -19,6 +19,8 @@
 import com.android.launcher3.ItemInfoWithIcon;
 import com.android.launcher3.LauncherSettings;
 
+import java.util.Objects;
+
 /**
  * Represents a {@link Package} in the widget tray section.
  */
@@ -48,4 +50,17 @@
     public PackageItemInfo clone() {
         return new PackageItemInfo(this);
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        PackageItemInfo that = (PackageItemInfo) o;
+        return Objects.equals(packageName, that.packageName);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(packageName);
+    }
 }
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index 9334c46..bdba39c 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.views;
 
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+
 import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
 
 import android.animation.Animator;
@@ -62,6 +64,7 @@
     protected final ObjectAnimator mOpenCloseAnimator;
 
     protected View mContent;
+    private final View mColorScrim;
     protected Interpolator mScrollInterpolator;
 
     // range [0, 1], 0=> completely open, 1=> completely closed
@@ -85,11 +88,30 @@
                 announceAccessibilityChanges();
             }
         });
+        int scrimColor = getScrimColor(mLauncher);
+        mColorScrim = scrimColor != -1 ? createColorScrim(mLauncher, scrimColor) : null;
+    }
+
+    protected void attachToContainer() {
+        if (mColorScrim != null) {
+            getPopupContainer().addView(mColorScrim);
+        }
+        getPopupContainer().addView(this);
+    }
+
+    /**
+     * Returns a scrim color for a sliding view. if returned value is -1, no scrim is added.
+     */
+    protected int getScrimColor(Context context) {
+        return -1;
     }
 
     protected void setTranslationShift(float translationShift) {
         mTranslationShift = translationShift;
         mContent.setTranslationY(mTranslationShift * mContent.getHeight());
+        if (mColorScrim != null) {
+            mColorScrim.setAlpha(1 - mTranslationShift);
+        }
     }
 
     @Override
@@ -127,7 +149,8 @@
     /* SingleAxisSwipeDetector.Listener */
 
     @Override
-    public void onDragStart(boolean start) { }
+    public void onDragStart(boolean start) {
+    }
 
     @Override
     public boolean onDrag(float displacement) {
@@ -185,9 +208,25 @@
     protected void onCloseComplete() {
         mIsOpen = false;
         getPopupContainer().removeView(this);
+        if (mColorScrim != null) {
+            getPopupContainer().removeView(mColorScrim);
+        }
     }
 
     protected BaseDragLayer getPopupContainer() {
         return mLauncher.getDragLayer();
     }
+
+
+    protected static View createColorScrim(Context context, int bgColor) {
+        View view = new View(context);
+        view.forceHasOverlappingRendering(false);
+        view.setBackgroundColor(bgColor);
+
+        BaseDragLayer.LayoutParams lp = new BaseDragLayer.LayoutParams(MATCH_PARENT, MATCH_PARENT);
+        lp.ignoreInsets = true;
+        view.setLayoutParams(lp);
+
+        return view;
+    }
 }
diff --git a/src/com/android/launcher3/views/WorkEduView.java b/src/com/android/launcher3/views/WorkEduView.java
index b6c81ae..81f8327 100644
--- a/src/com/android/launcher3/views/WorkEduView.java
+++ b/src/com/android/launcher3/views/WorkEduView.java
@@ -52,11 +52,15 @@
     private static final int WORK_EDU_PERSONAL_APPS = 1;
     private static final int WORK_EDU_WORK_APPS = 2;
 
+    protected static final int FINAL_SCRIM_BG_COLOR = 0x88000000;
+
+
     private Rect mInsets = new Rect();
     private View mViewWrapper;
     private Button mProceedButton;
     private TextView mContentText;
     private AllAppsPagedView mAllAppsPagedView;
+
     private int mNextWorkEduStep = WORK_EDU_PERSONAL_APPS;
 
 
@@ -141,10 +145,15 @@
     }
 
     private void show() {
-        mLauncher.getDragLayer().addView(this);
+        attachToContainer();
         animateOpen();
     }
 
+    @Override
+    protected int getScrimColor(Context context) {
+        return FINAL_SCRIM_BG_COLOR;
+    }
+
     private void goToFirstPage() {
         if (mAllAppsPagedView != null) {
             mAllAppsPagedView.snapToPageImmediately(AllAppsContainerView.AdapterHolder.MAIN);
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 6cae43d..df1a469 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -15,8 +15,6 @@
  */
 package com.android.launcher3.widget;
 
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-
 import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
 import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
 
@@ -42,7 +40,6 @@
 import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.AbstractSlideInView;
-import com.android.launcher3.views.BaseDragLayer;
 
 /**
  * Base class for various widgets popup
@@ -55,11 +52,14 @@
     /* Touch handling related member variables. */
     private Toast mWidgetInstructionToast;
 
-    protected final View mColorScrim;
-
     public BaseWidgetSheet(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        mColorScrim = createColorScrim(context);
+    }
+
+    protected int getScrimColor(Context context) {
+        WallpaperColorInfo colors = WallpaperColorInfo.INSTANCE.get(context);
+        int alpha = context.getResources().getInteger(R.integer.extracted_color_gradient_alpha);
+        return setColorAlphaBound(colors.getSecondaryColor(), alpha);
     }
 
     @Override
@@ -98,16 +98,6 @@
         return true;
     }
 
-    protected void attachToContainer() {
-        getPopupContainer().addView(mColorScrim);
-        getPopupContainer().addView(this);
-    }
-
-    protected void setTranslationShift(float translationShift) {
-        super.setTranslationShift(translationShift);
-        mColorScrim.setAlpha(1 - mTranslationShift);
-    }
-
     private boolean beginDraggingWidget(WidgetCell v) {
         // Get the widget preview as the drag representation
         WidgetImageView image = v.getWidgetView();
@@ -138,7 +128,6 @@
 
     protected void onCloseComplete() {
         super.onCloseComplete();
-        getPopupContainer().removeView(mColorScrim);
         clearNavBarColor();
     }
 
@@ -177,19 +166,4 @@
     protected SystemUiController getSystemUiController() {
         return mLauncher.getSystemUiController();
     }
-
-    private static View createColorScrim(Context context) {
-        View view = new View(context);
-        view.forceHasOverlappingRendering(false);
-
-        WallpaperColorInfo colors = WallpaperColorInfo.INSTANCE.get(context);
-        int alpha = context.getResources().getInteger(R.integer.extracted_color_gradient_alpha);
-        view.setBackgroundColor(setColorAlphaBound(colors.getSecondaryColor(), alpha));
-
-        BaseDragLayer.LayoutParams lp = new BaseDragLayer.LayoutParams(MATCH_PARENT, MATCH_PARENT);
-        lp.ignoreInsets = true;
-        view.setLayoutParams(lp);
-
-        return view;
-    }
 }
diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
index 282867a..ae32692 100644
--- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
+++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
@@ -6,6 +6,7 @@
 import static com.android.launcher3.pm.ShortcutConfigActivityInfo.queryList;
 
 import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Process;
@@ -243,4 +244,16 @@
             }
         }
     }
+
+    public WidgetItem getWidgetProviderInfoByProviderName(
+            ComponentName providerName) {
+        ArrayList<WidgetItem> widgetsList = mWidgetsList.get(
+                new PackageItemInfo(providerName.getPackageName()));
+        for (WidgetItem item : widgetsList) {
+            if (item.componentName.equals(providerName)) {
+                return item;
+            }
+        }
+        return null;
+    }
 }
\ No newline at end of file
diff --git a/tests/src/com/android/launcher3/ui/WorkTabTest.java b/tests/src/com/android/launcher3/ui/WorkTabTest.java
index 5aa0090..6fe6739 100644
--- a/tests/src/com/android/launcher3/ui/WorkTabTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkTabTest.java
@@ -73,11 +73,10 @@
         mDevice.pressHome();
         waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
         executeOnLauncher(launcher -> launcher.getStateManager().goToState(ALL_APPS));
-
         waitForLauncherCondition("Personal tab is missing",
-                launcher -> launcher.getAppsView().isPersonalTabVisible());
+                launcher -> launcher.getAppsView().isPersonalTabVisible(), 60000);
         waitForLauncherCondition("Work tab is missing",
-                launcher -> launcher.getAppsView().isWorkTabVisible());
+                launcher -> launcher.getAppsView().isWorkTabVisible(), 60000);
     }
 
     @Test
@@ -89,7 +88,7 @@
         executeOnLauncher(launcher -> launcher.getStateManager().goToState(ALL_APPS));
         waitForState("Launcher internal state didn't switch to All Apps", () -> ALL_APPS);
         getOnceNotNull("Apps view did not bind",
-                launcher -> launcher.getAppsView().getWorkFooterContainer());
+                launcher -> launcher.getAppsView().getWorkFooterContainer(), 60000);
 
         UserManager userManager = getFromLauncher(l -> l.getSystemService(UserManager.class));
         assertEquals(2, userManager.getUserProfiles().size());