Merge "Subtracting the touchSlop when dragging the window, to prevent initial jump" into ub-launcher3-master
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index 20abdc7..a48a65c 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -45,7 +45,9 @@
     }
 
     public static void onWorkspaceLongPress(Launcher launcher) {
-        PopupMenu menu = new PopupMenu(launcher, launcher.getWorkspace().getPageIndicator());
+        PopupMenu menu = new PopupMenu(launcher.getApplicationContext(),
+                launcher.getWorkspace().getPageIndicator());
+
         menu.getMenu().add(R.string.wallpaper_button_text).setOnMenuItemClickListener((i) -> {
             launcher.onClickWallpaperPicker(null);
             return true;
diff --git a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
index 102f859..4c3a9ad 100644
--- a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
+++ b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
@@ -42,6 +42,7 @@
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.states.InternalStateHandler;
+import com.android.launcher3.util.TraceHelper;
 import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.Task.TaskKey;
@@ -154,11 +155,13 @@
 
     @Override
     public void onLauncherResume() {
+        TraceHelper.partitionSection("TouchInt", "Launcher On resume");
         mDragView.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {
             @Override
             public boolean onPreDraw() {
                 mDragView.getViewTreeObserver().removeOnPreDrawListener(this);
                 mStateCallback.setState(STATE_LAUNCHER_READY);
+                TraceHelper.partitionSection("TouchInt", "Launcher drawn");
                 return true;
             }
         });
@@ -180,6 +183,7 @@
         // Optimization
         mLauncher.getAppsView().setVisibility(View.GONE);
         mRecentsView.setVisibility(View.GONE);
+        TraceHelper.partitionSection("TouchInt", "Launcher on new intent");
     }
 
     @UiThread
diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java
index 675f456..ba88f99 100644
--- a/quickstep/src/com/android/quickstep/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/RecentsView.java
@@ -16,10 +16,12 @@
 
 package com.android.quickstep;
 
+import android.animation.TimeInterpolator;
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
+import android.view.View;
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
@@ -41,6 +43,12 @@
  */
 public class RecentsView extends PagedView {
 
+    /** Designates how "curvy" the carousel is from 0 to 1, where 0 is a straight line. */
+    private static final float CURVE_FACTOR = 0.25f;
+    /** A circular curve of x from 0 to 1, where 0 is the center of the screen and 1 is the edge. */
+    private static final TimeInterpolator CURVE_INTERPOLATOR
+        = x -> (float) (1 - Math.sqrt(1 - Math.pow(x, 2)));
+
     private boolean mOverviewStateEnabled;
     private boolean mTaskStackListenerRegistered;
 
@@ -69,6 +77,7 @@
         super(context, attrs, defStyleAttr);
         setWillNotDraw(false);
         setPageSpacing((int) getResources().getDimension(R.dimen.recents_page_spacing));
+        enableFreeScroll(true);
     }
 
     @Override
@@ -170,4 +179,39 @@
         padding.left = padding.right = (int) ((profile.availableWidthPx - overviewWidth) / 2);
         return padding;
     }
+
+    @Override
+    public void scrollTo(int x, int y) {
+        super.scrollTo(x, y);
+        updateCurveProperties();
+    }
+
+    /**
+     * Scales and adjusts translation of adjacent pages as if on a curved carousel.
+     */
+    private void updateCurveProperties() {
+        if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) {
+            return;
+        }
+        final int halfScreenWidth = getMeasuredWidth() / 2;
+        final int screenCenter = halfScreenWidth + getScrollX();
+        final int pageSpacing = getResources().getDimensionPixelSize(R.dimen.recents_page_spacing);
+        final int pageCount = getPageCount();
+        for (int i = 0; i < pageCount; i++) {
+            View page = getPageAt(i);
+            int pageWidth = page.getMeasuredWidth();
+            int halfPageWidth = pageWidth / 2;
+            int pageCenter = page.getLeft() + halfPageWidth;
+            float distanceFromScreenCenter = Math.abs(pageCenter - screenCenter);
+            float distanceToReachEdge = halfScreenWidth + halfPageWidth + pageSpacing;
+            float linearInterpolation = Math.min(1, distanceFromScreenCenter / distanceToReachEdge);
+            float curveInterpolation = CURVE_INTERPOLATOR.getInterpolation(linearInterpolation);
+            float scale = 1 - curveInterpolation * CURVE_FACTOR;
+            page.setScaleX(scale);
+            page.setScaleY(scale);
+            // Make sure the biggest card (i.e. the one in front) shows on top of the adjacent ones.
+            page.setTranslationZ(scale);
+            page.setTranslationX((screenCenter - pageCenter) * curveInterpolation * CURVE_FACTOR);
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index b34601d..eacc393 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -133,6 +133,7 @@
         }
         switch (ev.getActionMasked()) {
             case MotionEvent.ACTION_DOWN: {
+                TraceHelper.beginSection("TouchInt");
                 mActivePointerId = ev.getPointerId(0);
                 mDownPos.set(ev.getX(), ev.getY());
                 mLastPos.set(mDownPos);
@@ -196,6 +197,7 @@
             case MotionEvent.ACTION_CANCEL:
                 // TODO: Should be different than ACTION_UP
             case MotionEvent.ACTION_UP: {
+                TraceHelper.endSection("TouchInt");
 
                 endInteraction();
                 break;
@@ -212,6 +214,7 @@
         final Context context = this;
         final RecentsTaskLoadPlan loadPlan = new RecentsTaskLoadPlan(context);
         final int taskId = mRunningTask.id;
+        TraceHelper.partitionSection("TouchInt", "Thershold crossed ");
 
         BackgroundExecutor.get().submit(() -> {
             // Get the snap shot before
@@ -220,6 +223,7 @@
             // Start the launcher activity with our custom handler
             Intent homeIntent = handler.addToIntent(new Intent(mHomeIntent));
             startActivity(homeIntent, ActivityOptions.makeCustomAnimation(this, 0, 0).toBundle());
+            TraceHelper.partitionSection("TouchInt", "Home started");
 
             /*
             ActivityManagerWrapper.getInstance().startRecentsActivity(null, options,
diff --git a/res/drawable/ic_corp.xml b/res/drawable/ic_corp.xml
new file mode 100644
index 0000000..48f5007
--- /dev/null
+++ b/res/drawable/ic_corp.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:pathData="M20,6h-4V4c0,-1.11 -0.89,-2 -2,-2h-4C8.89,2 8,2.89 8,4v2H4C2.89,6 2.01,6.89 2.01,8L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2V8C22,6.89 21.11,6 20,6zM12,15c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2s2,0.9 2,2S13.1,15 12,15zM14,6h-4V4h4V6z"
+        android:fillColor="?android:attr/textColorHint"/>
+</vector>
\ No newline at end of file
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 832aaef..c42c15c 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -35,21 +35,27 @@
         android:id="@+id/all_apps_header"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:clickable="true"
-        android:paddingTop="30dp"
+        android:paddingTop="@dimen/all_apps_header_top_padding"
+        android:clipToPadding="false"
         android:layout_below="@id/search_container_all_apps" >
 
         <com.android.launcher3.allapps.PredictionRowView
             android:id="@+id/header_content"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"/>
+            android:layout_height="wrap_content" />
+
+        <include layout="@layout/all_apps_divider"
+            android:id="@+id/divider"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignBottom="@+id/tabs" />
 
         <com.android.launcher3.views.SlidingTabStrip
             android:id="@+id/tabs"
             android:layout_width="match_parent"
             android:layout_height="@dimen/all_apps_header_tab_height"
             android:layout_below="@id/header_content"
-            android:orientation="horizontal">
+            android:orientation="horizontal" >
             <Button
                 android:id="@+id/tab_personal"
                 android:layout_width="0dp"
@@ -67,7 +73,6 @@
                 android:textColor="@color/all_apps_tab_text"
                 android:background="?android:attr/selectableItemBackground"/>
         </com.android.launcher3.views.SlidingTabStrip>
-
     </RelativeLayout>
 
     <!-- Note: we are reusing/repurposing a system attribute for search layout, because of a
diff --git a/res/layout/all_apps_tabs.xml b/res/layout/all_apps_tabs.xml
index fa1d591..54a9b88 100644
--- a/res/layout/all_apps_tabs.xml
+++ b/res/layout/all_apps_tabs.xml
@@ -25,7 +25,7 @@
     android:clipChildren="false"
     android:clipToPadding="false"
     android:descendantFocusability="afterDescendants"
-    android:paddingTop="30dp">
+    android:paddingTop="@dimen/all_apps_header_top_padding">
 
     <include layout="@layout/all_apps_rv_layout" />
 
diff --git a/res/layout/work_tab_footer.xml b/res/layout/work_tab_footer.xml
new file mode 100644
index 0000000..48578d7
--- /dev/null
+++ b/res/layout/work_tab_footer.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:orientation="vertical"
+      android:paddingBottom="@dimen/all_apps_work_profile_tab_footer_bottom_padding"
+      android:paddingLeft="@dimen/dynamic_grid_cell_padding_x"
+      android:paddingRight="@dimen/dynamic_grid_cell_padding_x"
+      android:paddingTop="@dimen/all_apps_work_profile_tab_footer_top_padding">
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+        <Switch
+            android:id="@+id/work_mode_toggle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentRight="true"
+            android:theme="@style/WorkModeSwitchTheme"/>
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignBaseline="@id/work_mode_toggle"
+            android:layout_alignParentLeft="true"
+            android:ellipsize="end"
+            android:fontFamily="roboto-regular"
+            android:lines="1"
+            android:text="@string/work_profile_toggle_label"
+            android:textColor="?android:attr/textColorTertiary"
+            android:textSize="16sp"/>
+
+    </RelativeLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:paddingTop="8dp">
+
+        <ImageView
+            android:layout_width="24dp"
+            android:layout_height="24dp"
+            android:src="@drawable/ic_corp"/>
+
+        <TextView
+            android:id="@+id/managed_by_label"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:ellipsize="end"
+            android:lines="1"
+            android:paddingLeft="12dp"
+            android:textColor="?android:attr/textColorHint"
+            android:textSize="13sp"/>
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 9734781..40a566e 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -129,4 +129,6 @@
     <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> માટે <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> શૉર્ટકટ અને <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> સૂચનાઓ"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"છોડી દો"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"સૂચના છોડી દીધી"</string>
+    <string name="all_apps_personal_tab" msgid="4190252696685155002">"મનગમતી ઍપ"</string>
+    <string name="all_apps_work_tab" msgid="4884822796154055118">"કાર્યાલયની ઍપ"</string>
 </resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 2387404..cfd1904 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -129,4 +129,6 @@
     <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> के लिए <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> शॉर्टकट और <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> सूचनाएं हैं"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"खारिज करें"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"सूचना को खारिज किया गया"</string>
+    <string name="all_apps_personal_tab" msgid="4190252696685155002">"निजी ऐप"</string>
+    <string name="all_apps_work_tab" msgid="4884822796154055118">"काम से जुड़े ऐप"</string>
 </resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index d7905b4..5ed22f8 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -129,4 +129,6 @@
     <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> קיצורי דרך ו-<xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> הודעות של <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"סגור"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"ההודעה נסגרה"</string>
+    <string name="all_apps_personal_tab" msgid="4190252696685155002">"אישיות"</string>
+    <string name="all_apps_work_tab" msgid="4884822796154055118">"עבודה"</string>
 </resources>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 4156a21..e19b42e 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -129,4 +129,6 @@
     <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> ಗಾಗಿ <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು ಮತ್ತು <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> ಅಧಿಸೂಚನೆಗಳು"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"ವಜಾಗೊಳಿಸಿ"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"ಅಧಿಸೂಚನೆಯನ್ನು ವಜಾಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <string name="all_apps_personal_tab" msgid="4190252696685155002">"ವೈಯಕ್ತಿಕ"</string>
+    <string name="all_apps_work_tab" msgid="4884822796154055118">"ಕೆಲಸ"</string>
 </resources>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 299fc45..102176c 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -129,4 +129,6 @@
     <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> ആപ്പിനായുള്ള <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> കുറുക്കുവഴികളും <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> അറിയിപ്പുകളും"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"നിരസിക്കുക"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"അറിയിപ്പ് നിരസിച്ചു"</string>
+    <string name="all_apps_personal_tab" msgid="4190252696685155002">"വ്യക്തിപരം"</string>
+    <string name="all_apps_work_tab" msgid="4884822796154055118">"ജോലി"</string>
 </resources>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index ca9a402..7b98bce 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -98,7 +98,7 @@
     <string name="abandoned_promises_title" msgid="7096178467971716750">"हा अॅप इंस्टॉल केलेला नाही"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"या चिन्हासाठी अॅप इंस्टॉल केलेला नाही. आपण ते काढू शकता किंवा अॅपचा शोध घेऊ शकता आणि त्यास व्यक्तिचलितपणे इंस्टॉल करू शकता."</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> डाउनलोड होत आहे , <xliff:g id="PROGRESS">%2$s</xliff:g> पूर्ण झाले"</string>
-    <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> इंस्टॉल करण्याची प्रतिक्षा करीत आहे"</string>
+    <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> इंस्टॉल करण्याची प्रतिक्षा करत आहे"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> विजेट"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"होम स्क्रीनवर जोडा"</string>
     <string name="action_move_here" msgid="2170188780612570250">"आयटम येथे हलवा"</string>
@@ -129,4 +129,6 @@
     <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g>साठी <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> शॉर्टकट आणि <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> सूचना"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"डिसमिस करा"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"सूचना डिसमिस केली"</string>
+    <string name="all_apps_personal_tab" msgid="4190252696685155002">"वैयक्तिक"</string>
+    <string name="all_apps_work_tab" msgid="4884822796154055118">"कार्यालय"</string>
 </resources>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 41e43a7..930fb00 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -129,4 +129,6 @@
     <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> का <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> सर्टकट र <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> सूचनाहरू"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"खारेज गर्नुहोस्"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"सूचना खारेज गरियो"</string>
+    <string name="all_apps_personal_tab" msgid="4190252696685155002">"व्यक्तिगत"</string>
+    <string name="all_apps_work_tab" msgid="4884822796154055118">"कार्यसम्बन्धी"</string>
 </resources>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 525f2f6..4156009 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -129,4 +129,6 @@
     <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> ਲਈ <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ਸ਼ਾਰਟਕੱਟ ਅਤੇ <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> ਸੂਚਨਾਵਾਂ"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"ਖਾਰਜ ਕਰੋ"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"ਸੂਚਨਾ ਖਾਰਜ ਕੀਤੀ ਗਈ"</string>
+    <string name="all_apps_personal_tab" msgid="4190252696685155002">"ਨਿੱਜੀ"</string>
+    <string name="all_apps_work_tab" msgid="4884822796154055118">"ਕਾਰਜ-ਸਥਾਨ"</string>
 </resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 402f3a6..5209438 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -66,8 +66,8 @@
     <skip />
     <string name="workspace_new_page" msgid="257366611030256142">"Ukurasa mpya wa skrini ya kwanza"</string>
     <string name="folder_opened" msgid="94695026776264709">"Folda imefunguliwa, <xliff:g id="WIDTH">%1$d</xliff:g> kwa <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
-    <string name="folder_tap_to_close" msgid="4625795376335528256">"Gonga ili ufunge folda"</string>
-    <string name="folder_tap_to_rename" msgid="4017685068016979677">"Gonga ili ubadilishe jina"</string>
+    <string name="folder_tap_to_close" msgid="4625795376335528256">"Gusa ili ufunge folda"</string>
+    <string name="folder_tap_to_rename" msgid="4017685068016979677">"Gusa ili ubadilishe jina"</string>
     <string name="folder_closed" msgid="4100806530910930934">"Folda imefungwa"</string>
     <string name="folder_renamed" msgid="1794088362165669656">"Folda imebadilishwa jina kuwa <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_name_format" msgid="6629239338071103179">"Folda: <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -131,4 +131,6 @@
     <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"Njia <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> za mkato na arifa <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> za <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Ondoa"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Arifa imeondolewa"</string>
+    <string name="all_apps_personal_tab" msgid="4190252696685155002">"Binafsi"</string>
+    <string name="all_apps_work_tab" msgid="4884822796154055118">"Kazini"</string>
 </resources>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 5d72030..f8101bb 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -129,4 +129,6 @@
     <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> பயன்பாட்டிற்கான <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> குறுக்குவழிகளும் <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> அறிவிப்புகளும் உள்ளன"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"நிராகரி"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"அறிவிப்பு நிராகரிக்கப்பட்டது"</string>
+    <string name="all_apps_personal_tab" msgid="4190252696685155002">"தனிப்பட்டவை"</string>
+    <string name="all_apps_work_tab" msgid="4884822796154055118">"பணி"</string>
 </resources>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 99b8c80..860b132 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -129,4 +129,6 @@
     <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> کے <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> شارٹ کٹس اور <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> اطلاعات"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"برخاست کریں"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"اطلاع مسترد ہو گئی"</string>
+    <string name="all_apps_personal_tab" msgid="4190252696685155002">"ذاتی"</string>
+    <string name="all_apps_work_tab" msgid="4884822796154055118">"دفتری"</string>
 </resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index b44a31e..42fee80 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -40,4 +40,6 @@
 
     <color name="all_apps_bg_hand_fill">#E5E5E5</color>
     <color name="all_apps_bg_hand_fill_dark">#9AA0A6</color>
+
+    <color name="work_profile_color">#FF6D00</color>
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index efe5043..e7f45c2 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -92,6 +92,10 @@
     <dimen name="all_apps_caret_workspace_offset">18dp</dimen>
     <dimen name="all_apps_header_tab_height">50dp</dimen>
     <dimen name="all_apps_tabs_indicator_height">2dp</dimen>
+    <dimen name="all_apps_header_top_padding">36dp</dimen>
+    <dimen name="all_apps_prediction_row_divider_height">17dp</dimen>
+    <dimen name="all_apps_work_profile_tab_footer_top_padding">16dp</dimen>
+    <dimen name="all_apps_work_profile_tab_footer_bottom_padding">20dp</dimen>
 
 <!-- Search bar in All Apps -->
     <dimen name="all_apps_header_max_elevation">3dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index fdd4d8d..cbba9a2 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -324,4 +324,7 @@
     <!-- Label of tab to indicate work apps -->
     <string name="all_apps_work_tab">Work</string>
 
+    <!-- Label of the work mode toggle -->
+    <string name="work_profile_toggle_label">Work profile</string>
+
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 8cc4743..c714841 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -168,4 +168,8 @@
         <item name="android:colorControlHighlight">#DFE1E5</item>
         <item name="android:colorForeground">@color/all_apps_bg_hand_fill_dark</item>
     </style>
+
+    <style name="WorkModeSwitchTheme" parent="@style/LauncherTheme">
+        <item name="android:colorAccent">@color/work_profile_color</item>
+    </style>
 </resources>
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 6c22474..9f6efb3 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -30,7 +30,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.AttributeSet;
-import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.InputDevice;
 import android.view.KeyEvent;
@@ -87,6 +86,7 @@
     public static final int INVALID_RESTORE_PAGE = -1001;
 
     private boolean mFreeScroll = false;
+    private boolean mSettleOnPageInFreeScroll = false;
 
     protected int mFlingThresholdVelocity;
     protected int mMinFlingVelocity;
@@ -1170,7 +1170,12 @@
      * return true if freescroll has been enabled, false otherwise
      */
     protected void enableFreeScroll() {
+        enableFreeScroll(false);
+    }
+
+    protected void enableFreeScroll(boolean settleOnPageInFreeScroll) {
         setEnableFreeScroll(true);
+        mSettleOnPageInFreeScroll = settleOnPageInFreeScroll;
     }
 
     protected void disableFreeScroll() {
@@ -1414,7 +1419,22 @@
                     mScroller.setInterpolator(mDefaultInterpolator);
                     mScroller.fling(initialScrollX,
                             getScrollY(), vX, 0, Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0);
-                    mNextPage = getPageNearestToCenterOfScreen((int) (mScroller.getFinalX() / scaleX));
+                    int unscaledScrollX = (int) (mScroller.getFinalX() / scaleX);
+                    mNextPage = getPageNearestToCenterOfScreen(unscaledScrollX);
+                    int firstPageScroll = getScrollForPage(!mIsRtl ? 0 : getPageCount() - 1);
+                    int lastPageScroll = getScrollForPage(!mIsRtl ? getPageCount() - 1 : 0);
+                    if (mSettleOnPageInFreeScroll && unscaledScrollX > firstPageScroll
+                            && unscaledScrollX < lastPageScroll) {
+                        // Make sure we land directly on a page. If flinging past one of the ends,
+                        // don't change the velocity as it will get stopped at the end anyway.
+                        mScroller.setFinalX((int) (getScrollForPage(mNextPage) * getScaleX()));
+                        // Ensure the scroll/snap doesn't happen too fast;
+                        int extraScrollDuration = OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION
+                                - mScroller.getDuration();
+                        if (extraScrollDuration > 0) {
+                            mScroller.extendDuration(extraScrollDuration);
+                        }
+                    }
                     invalidate();
                 }
                 onScrollInteractionEnd();
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index efd7b97..72ad69b 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -120,8 +120,8 @@
         addView(mTouchFeedbackView, size, size);
 
         mAH = new AdapterHolder[2];
-        mAH[AdapterHolder.MAIN] = new AdapterHolder();
-        mAH[AdapterHolder.WORK] = new AdapterHolder();
+        mAH[AdapterHolder.MAIN] = new AdapterHolder(false /* isWork */);
+        mAH[AdapterHolder.WORK] = new AdapterHolder(true /* isWork */);
     }
 
     @Override
@@ -281,6 +281,9 @@
                 mAH[i].recyclerView.scrollToTop();
             }
         }
+        if (mFloatingHeaderHandler != null) {
+            mFloatingHeaderHandler.reset();
+        }
         // Reset the search bar and base recycler view after transitioning home
         mSearchUiManager.reset();
     }
@@ -301,6 +304,7 @@
         });
 
         mHeader = findViewById(R.id.all_apps_header);
+        mFloatingHeaderHandler = new FloatingHeaderHandler(mHeader);
         rebindAdapters(mUsingTabs);
 
         mSearchContainer = findViewById(R.id.search_container_all_apps);
@@ -431,10 +435,14 @@
             mAH[AdapterHolder.WORK].setup(mViewPager.getChildAt(1), mWorkMatcher);
             setupWorkProfileTabs();
             setupHeader();
-            mHeader.setVisibility(View.VISIBLE);
         } else {
-            mHeader.setVisibility(View.GONE);
             mAH[AdapterHolder.MAIN].setup(findViewById(R.id.apps_list_view), null);
+            if (FeatureFlags.ALL_APPS_PREDICTION_ROW_VIEW) {
+                setupHeader();
+            } else {
+                mFloatingHeaderHandler = null;
+                mHeader.setVisibility(View.GONE);
+            }
         }
 
         applyTouchDelegate();
@@ -512,7 +520,7 @@
     }
 
     public void setPredictedApps(List<ComponentKeyMapper<AppInfo>> apps) {
-        if (mUsingTabs) {
+        if (mFloatingHeaderHandler != null) {
             mFloatingHeaderHandler.getContentView().setPredictedApps(apps);
         }
         mAH[AdapterHolder.MAIN].appsList.setPredictedApps(apps);
@@ -535,15 +543,24 @@
     }
 
     private void setupHeader() {
+        mHeader.setVisibility(View.VISIBLE);
         int contentHeight = mLauncher.getDeviceProfile().allAppsCellHeightPx;
+        if (!mUsingTabs) {
+            contentHeight += getResources()
+                    .getDimensionPixelSize(R.dimen.all_apps_prediction_row_divider_height);
+        }
         RecyclerView mainRV = mAH[AdapterHolder.MAIN].recyclerView;
-        RecyclerView workRV = mAH[AdapterHolder.WORK] != null
-                ? mAH[AdapterHolder.WORK].recyclerView : null;
-        mFloatingHeaderHandler = new FloatingHeaderHandler(mHeader, mainRV, workRV, contentHeight);
-        mFloatingHeaderHandler.getContentView().setNumAppsPerRow(mNumPredictedAppsPerRow);
-        mFloatingHeaderHandler.getContentView().setComponentToAppMap(mComponentToAppMap);
+        RecyclerView workRV = mAH[AdapterHolder.WORK].recyclerView;
+        mFloatingHeaderHandler.setup(mainRV, workRV, contentHeight);
+        mFloatingHeaderHandler.getContentView().setup(mAH[AdapterHolder.MAIN].adapter,
+                mComponentToAppMap, mNumPredictedAppsPerRow);
+
+        int padding = contentHeight;
+        if (!mUsingTabs) {
+            padding += mHeader.getPaddingTop() + mHeader.getPaddingBottom();
+        }
         for (int i = 0; i < mAH.length; i++) {
-            mAH[i].paddingTopForTabs = contentHeight;
+            mAH[i].paddingTopForTabs = padding;
             mAH[i].applyPadding();
         }
     }
@@ -556,7 +573,9 @@
 
     public void onSearchResultsChanged() {
         for (int i = 0; i < mAH.length; i++) {
-            mAH[i].recyclerView.onSearchResultsChanged();
+            if (mAH[i].recyclerView != null) {
+                mAH[i].recyclerView.onSearchResultsChanged();
+            }
         }
     }
 
@@ -608,8 +627,8 @@
         AllAppsRecyclerView recyclerView;
         boolean verticalFadingEdge;
 
-        AdapterHolder() {
-            appsList = new AlphabeticalAppsList(mLauncher, mComponentToAppMap);
+        AdapterHolder(boolean isWork) {
+            appsList = new AlphabeticalAppsList(mLauncher, mComponentToAppMap, isWork);
             adapter = new AllAppsGridAdapter(mLauncher, appsList, mLauncher,
                     AllAppsContainerView.this, true);
             appsList.setAdapter(adapter);
@@ -640,9 +659,14 @@
 
         void applyPadding() {
             if (recyclerView != null) {
-                int paddingTop = mUsingTabs ? paddingTopForTabs : padding.top;
+                int paddingTop = mUsingTabs || FeatureFlags.ALL_APPS_PREDICTION_ROW_VIEW
+                        ? paddingTopForTabs : padding.top;
                 recyclerView.setPadding(padding.left, paddingTop, padding.right, padding.bottom);
             }
+            if (mFloatingHeaderHandler != null) {
+                mFloatingHeaderHandler.getContentView()
+                        .setPadding(padding.left, 0 , padding.right, 0);
+            }
         }
 
         void applyNumsPerRow() {
@@ -652,7 +676,7 @@
                 }
                 adapter.setNumAppsPerRow(mNumAppsPerRow);
                 appsList.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow);
-                if (mUsingTabs && mFloatingHeaderHandler != null) {
+                if (mFloatingHeaderHandler != null) {
                     mFloatingHeaderHandler.getContentView()
                             .setNumAppsPerRow(mNumPredictedAppsPerRow);
                 }
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index ac8d367..da4d9f0 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -18,6 +18,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
+import android.os.UserHandle;
 import android.support.animation.DynamicAnimation;
 import android.support.animation.SpringAnimation;
 import android.support.v4.view.accessibility.AccessibilityEventCompat;
@@ -32,6 +33,7 @@
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
+import android.widget.Switch;
 import android.widget.TextView;
 
 import com.android.launcher3.AppInfo;
@@ -41,6 +43,7 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.allapps.AlphabeticalAppsList.AdapterItem;
 import com.android.launcher3.anim.SpringAnimationHandler;
+import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.discovery.AppDiscoveryAppInfo;
 import com.android.launcher3.discovery.AppDiscoveryItemView;
@@ -68,14 +71,15 @@
     // but differ in enough attributes to require different view types
 
     // A divider that separates the apps list and the search market button
-    public static final int VIEW_TYPE_SEARCH_MARKET_DIVIDER = 1 << 5;
+    public static final int VIEW_TYPE_ALL_APPS_DIVIDER = 1 << 5;
     // The divider that separates prediction icons from the app list
     public static final int VIEW_TYPE_PREDICTION_DIVIDER = 1 << 6;
     public static final int VIEW_TYPE_APPS_LOADING_DIVIDER = 1 << 7;
     public static final int VIEW_TYPE_DISCOVERY_ITEM = 1 << 8;
+    public static final int VIEW_TYPE_WORK_TAB_FOOTER = 1 << 9;
 
     // Common view type masks
-    public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_SEARCH_MARKET_DIVIDER
+    public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER
             | VIEW_TYPE_PREDICTION_DIVIDER;
     public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON
             | VIEW_TYPE_PREDICTION_ICON;
@@ -182,8 +186,8 @@
             if (isIconViewType(mApps.getAdapterItems().get(position).viewType)) {
                 return 1;
             } else {
-                    // Section breaks span the full width
-                    return mAppsPerRow;
+                // Section breaks span the full width
+                return mAppsPerRow;
             }
         }
     }
@@ -323,9 +327,13 @@
                         R.layout.all_apps_discovery_loading_divider, parent, false);
                 return new ViewHolder(loadingDividerView);
             case VIEW_TYPE_PREDICTION_DIVIDER:
-            case VIEW_TYPE_SEARCH_MARKET_DIVIDER:
+            case VIEW_TYPE_ALL_APPS_DIVIDER:
                 return new ViewHolder(mLayoutInflater.inflate(
                         R.layout.all_apps_divider, parent, false));
+            case VIEW_TYPE_WORK_TAB_FOOTER:
+                View footer = mLayoutInflater.inflate(R.layout.work_tab_footer, parent, false);
+                // TODO: Implement the work mode toggle logic here.
+                return new ViewHolder(footer);
             default:
                 throw new RuntimeException("Unexpected view type");
         }
@@ -367,9 +375,17 @@
                 holder.itemView.findViewById(R.id.loadingProgressBar).setVisibility(visLoading);
                 holder.itemView.findViewById(R.id.loadedDivider).setVisibility(visLoaded);
                 break;
-            case VIEW_TYPE_SEARCH_MARKET_DIVIDER:
+            case VIEW_TYPE_ALL_APPS_DIVIDER:
                 // nothing to do
                 break;
+            case VIEW_TYPE_WORK_TAB_FOOTER:
+                Switch workModeToggle = holder.itemView.findViewById(R.id.work_mode_toggle);
+                workModeToggle.setChecked(!isAnyProfileQuietModeEnabled());
+
+                TextView textView = holder.itemView.findViewById(R.id.managed_by_label);
+                // TODO: Configure the textview properly.
+                textView.setText("Managed by your company");
+                break;
         }
         if (mBindViewCallback != null) {
             mBindViewCallback.onBindView(holder);
@@ -537,4 +553,15 @@
             return factor;
         }
     }
+
+    private boolean isAnyProfileQuietModeEnabled() {
+        UserManagerCompat userManager = UserManagerCompat.getInstance(mLauncher);
+        List<UserHandle> userProfiles = userManager.getUserProfiles();
+        for (UserHandle userProfile : userProfiles) {
+            if (userManager.isQuietModeEnabled(userProfile)) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 09357f7..5789b67 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -143,7 +143,7 @@
         RecyclerView.RecycledViewPool pool = getRecycledViewPool();
         int approxRows = (int) Math.ceil(grid.availableHeightPx / grid.allAppsIconSizePx);
         pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_EMPTY_SEARCH, 1);
-        pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET_DIVIDER, 1);
+        pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_ALL_APPS_DIVIDER, 1);
         pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET, 1);
         pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_ICON, approxRows * mNumAppsPerRow);
         pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_PREDICTION_ICON, mNumAppsPerRow);
@@ -167,7 +167,7 @@
 
         putSameHeightFor(adapter, widthMeasureSpec, heightMeasureSpec,
                 AllAppsGridAdapter.VIEW_TYPE_PREDICTION_DIVIDER,
-                AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET_DIVIDER);
+                AllAppsGridAdapter.VIEW_TYPE_ALL_APPS_DIVIDER);
         putSameHeightFor(adapter, widthMeasureSpec, heightMeasureSpec,
                 AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET);
         putSameHeightFor(adapter, widthMeasureSpec, heightMeasureSpec,
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index f9dde2f..12715cb 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -140,9 +140,9 @@
             return item;
         }
 
-        public static AdapterItem asMarketDivider(int pos) {
+        public static AdapterItem asAllAppsDivider(int pos) {
             AdapterItem item = new AdapterItem();
-            item.viewType = AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET_DIVIDER;
+            item.viewType = AllAppsGridAdapter.VIEW_TYPE_ALL_APPS_DIVIDER;
             item.position = pos;
             return item;
         }
@@ -160,6 +160,13 @@
             item.position = pos;
             return item;
         }
+
+        public static AdapterItem asWorkTabFooter(int pos) {
+            AdapterItem item = new AdapterItem();
+            item.viewType = AllAppsGridAdapter.VIEW_TYPE_WORK_TAB_FOOTER;
+            item.position = pos;
+            return item;
+        }
     }
 
     private final Launcher mLauncher;
@@ -179,6 +186,8 @@
     // The set of predicted apps resolved from the component names and the current set of apps
     private final List<AppInfo> mPredictedApps = new ArrayList<>();
     private final List<AppDiscoveryAppInfo> mDiscoveredApps = new ArrayList<>();
+    // Is it the work profile app list.
+    private final boolean mIsWork;
 
     // The of ordered component names as a result of a search query
     private ArrayList<ComponentKey> mSearchResults;
@@ -191,11 +200,16 @@
     private int mNumAppRowsInAdapter;
     private ItemInfoMatcher mItemFilter;
 
-    public AlphabeticalAppsList(Context context, HashMap<ComponentKey, AppInfo> componentToAppMap) {
+    public AlphabeticalAppsList(
+            Context context,
+            HashMap<ComponentKey,
+            AppInfo> componentToAppMap,
+            boolean isWork) {
         mComponentToAppMap = componentToAppMap;
         mLauncher = Launcher.getLauncher(context);
         mIndexer = new AlphabeticIndexCompat(context);
         mAppNameComparator = new AppInfoComparator(context);
+        mIsWork = isWork;
     }
 
     public void updateItemFilter(ItemInfoMatcher itemFilter) {
@@ -460,7 +474,7 @@
         mFastScrollerSections.clear();
         mAdapterItems.clear();
 
-        if (!FeatureFlags.ALL_APPS_TABS_ENABLED) {
+        if (!FeatureFlags.ALL_APPS_PREDICTION_ROW_VIEW) {
             if (DEBUG_PREDICTIONS) {
                 if (mPredictedAppComponents.isEmpty() && !mApps.isEmpty()) {
                     mPredictedAppComponents.add(new ComponentKeyMapper<AppInfo>(new ComponentKey(mApps.get(0).componentName,
@@ -545,7 +559,7 @@
                 if (hasNoFilteredResults()) {
                     mAdapterItems.add(AdapterItem.asEmptySearch(position++));
                 } else {
-                    mAdapterItems.add(AdapterItem.asMarketDivider(position++));
+                    mAdapterItems.add(AdapterItem.asAllAppsDivider(position++));
                 }
                 mAdapterItems.add(AdapterItem.asMarketSearch(position++));
             }
@@ -604,6 +618,12 @@
                     break;
             }
         }
+
+        // Add the work profile footer if required.
+        if (mIsWork) {
+            mAdapterItems.add(AdapterItem.asAllAppsDivider(position++));
+            mAdapterItems.add(AdapterItem.asWorkTabFooter(position++));
+        }
     }
 
     public boolean isAppDiscoveryRunning() {
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderHandler.java b/src/com/android/launcher3/allapps/FloatingHeaderHandler.java
index 984966b..0b39b7d 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderHandler.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderHandler.java
@@ -15,36 +15,52 @@
  */
 package com.android.launcher3.allapps;
 
+import android.animation.ValueAnimator;
+import android.content.res.Resources;
 import android.graphics.Rect;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v7.widget.RecyclerView;
 import android.view.View;
+import android.view.ViewGroup;
+import android.widget.RelativeLayout;
 
 import com.android.launcher3.R;
 
-public class FloatingHeaderHandler extends RecyclerView.OnScrollListener {
+public class FloatingHeaderHandler extends RecyclerView.OnScrollListener
+        implements ValueAnimator.AnimatorUpdateListener {
 
-    private final int mMaxTranslation;
     private final View mHeaderView;
-    private final PredictionRowView mContentView;
-    private final RecyclerView mMainRV;
-    private final RecyclerView mWorkRV;
+    private final PredictionRowView mPredictionRow;
+    private final ViewGroup mTabLayout;
+    private final View mDivider;
     private final Rect mClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
+    private final ValueAnimator mAnimator = ValueAnimator.ofInt(0, 0);
 
+    private RecyclerView mMainRV;
+    private RecyclerView mWorkRV;
+    private boolean mTopOnlyMode;
     private boolean mHeaderHidden;
+    private int mMaxTranslation;
     private int mSnappedScrolledY;
     private int mTranslationY;
     private int mMainScrolledY;
     private int mWorkScrolledY;
     private boolean mMainRVActive;
 
-    public FloatingHeaderHandler(@NonNull View header, @NonNull RecyclerView personalRV,
-            @Nullable RecyclerView workRV, int contentHeight) {
+    public FloatingHeaderHandler(@NonNull ViewGroup header) {
         mHeaderView = header;
-        mContentView = mHeaderView.findViewById(R.id.header_content);
-        mContentView.getLayoutParams().height = contentHeight;
-        mMaxTranslation = contentHeight;
+        mTabLayout = header.findViewById(R.id.tabs);
+        mDivider = header.findViewById(R.id.divider);
+        mPredictionRow = header.findViewById(R.id.header_content);
+    }
+
+    public void setup(@NonNull RecyclerView personalRV, @Nullable RecyclerView workRV,
+        int predictionRowHeight) {
+        mTopOnlyMode = workRV == null;
+        mTabLayout.setVisibility(mTopOnlyMode ? View.GONE : View.VISIBLE);
+        mPredictionRow.getLayoutParams().height = predictionRowHeight;
+        mMaxTranslation = predictionRowHeight;
         mMainRV = personalRV;
         mMainRV.addOnScrollListener(this);
         mWorkRV = workRV;
@@ -52,6 +68,18 @@
             workRV.addOnScrollListener(this);
         }
         setMainActive(true);
+        setupDivider();
+    }
+
+    private void setupDivider() {
+        Resources res = mHeaderView.getResources();
+        int verticalGap = res.getDimensionPixelSize(R.dimen.all_apps_divider_margin_vertical);
+        int sideGap = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
+        mDivider.setPadding(sideGap, verticalGap,sideGap, mTopOnlyMode ? verticalGap : 0);
+        RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) mDivider.getLayoutParams();
+        lp.removeRule(RelativeLayout.ALIGN_BOTTOM);
+        lp.addRule(RelativeLayout.ALIGN_BOTTOM, mTopOnlyMode ? R.id.header_content : R.id.tabs);
+        mDivider.setLayoutParams(lp);
     }
 
     public void setMainActive(boolean active) {
@@ -65,7 +93,15 @@
     }
 
     public PredictionRowView getContentView() {
-        return mContentView;
+        return mPredictionRow;
+    }
+
+    public ViewGroup getTabLayout() {
+        return mTabLayout;
+    }
+
+    public View getDivider() {
+        return mDivider;
     }
 
     @Override
@@ -75,27 +111,39 @@
             return;
         }
 
+        if (mAnimator.isStarted()) {
+            mAnimator.cancel();
+        }
+
         int current = isMainRV
                 ? (mMainScrolledY -= dy)
                 : (mWorkScrolledY -= dy);
 
-        if (dy == 0) {
-            setExpanded(true);
-        } else {
-            moved(current);
-            apply();
-        }
+        moved(current);
+        apply();
+    }
+
+    public void reset() {
+        mMainScrolledY = 0;
+        mWorkScrolledY = 0;
+        setExpanded(true);
+    }
+
+    private boolean canSnapAt(int currentScrollY) {
+        return !mTopOnlyMode || Math.abs(currentScrollY) <= mPredictionRow.getHeight();
     }
 
     private void moved(final int currentScrollY) {
         if (mHeaderHidden) {
             if (currentScrollY <= mSnappedScrolledY) {
-                mSnappedScrolledY = currentScrollY;
+                if (canSnapAt(currentScrollY)) {
+                    mSnappedScrolledY = currentScrollY;
+                }
             } else {
                 mHeaderHidden = false;
             }
             mTranslationY = currentScrollY;
-        } else {
+        } else if (!mHeaderHidden) {
             mTranslationY = currentScrollY - mSnappedScrolledY - mMaxTranslation;
 
             // update state vars
@@ -110,20 +158,36 @@
     }
 
     private void apply() {
+        int uncappedTranslationY = mTranslationY;
         mTranslationY = Math.max(mTranslationY, -mMaxTranslation);
-        mHeaderView.setTranslationY(mTranslationY);
+        mPredictionRow.setTranslationY(uncappedTranslationY);
+        mTabLayout.setTranslationY(mTranslationY);
+        mDivider.setTranslationY(mTopOnlyMode ? uncappedTranslationY : mTranslationY);
         mClip.top = mMaxTranslation + mTranslationY;
+        // clipping on a draw might cause additional redraw
         mMainRV.setClipBounds(mClip);
         if (mWorkRV != null) {
             mWorkRV.setClipBounds(mClip);
         }
     }
 
+    @Override
+    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+        if (!mTopOnlyMode && newState == RecyclerView.SCROLL_STATE_IDLE
+                && mTranslationY != -mMaxTranslation && mTranslationY != 0) {
+            float scroll = Math.abs(getCurrentScroll());
+            boolean expand =  scroll > mMaxTranslation
+                    ? Math.abs(mTranslationY) < mMaxTranslation / 2 : true;
+            setExpanded(expand);
+        }
+    }
+
     private void setExpanded(boolean expand) {
         int translateTo = expand ? 0 : -mMaxTranslation;
-        mTranslationY = translateTo;
-        apply();
-
+        mAnimator.setIntValues(mTranslationY, translateTo);
+        mAnimator.addUpdateListener(this);
+        mAnimator.setDuration(150);
+        mAnimator.start();
         mHeaderHidden = !expand;
         mSnappedScrolledY = expand ? getCurrentScroll() - mMaxTranslation : getCurrentScroll();
     }
@@ -136,4 +200,10 @@
         return mMainRVActive ? mMainScrolledY : mWorkScrolledY;
     }
 
+    @Override
+    public void onAnimationUpdate(ValueAnimator animation) {
+        mTranslationY = (Integer) animation.getAnimatedValue();
+        apply();
+    }
+
 }
diff --git a/src/com/android/launcher3/allapps/PredictionRowView.java b/src/com/android/launcher3/allapps/PredictionRowView.java
index 5551f07..45ef6c1 100644
--- a/src/com/android/launcher3/allapps/PredictionRowView.java
+++ b/src/com/android/launcher3/allapps/PredictionRowView.java
@@ -21,9 +21,11 @@
 import android.support.annotation.Nullable;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.View;
 import android.widget.LinearLayout;
 
 import com.android.launcher3.AppInfo;
+import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.ComponentKeyMapper;
@@ -43,6 +45,8 @@
     private final List<ComponentKeyMapper<AppInfo>> mPredictedAppComponents = new ArrayList<>();
     // The set of predicted apps resolved from the component names and the current set of apps
     private final List<AppInfo> mPredictedApps = new ArrayList<>();
+    // This adapter is only used to create an identical item w/ same behavior as in the all apps RV
+    private AllAppsGridAdapter mAdapter;
 
     public PredictionRowView(@NonNull Context context) {
         this(context, null);
@@ -53,8 +57,11 @@
         setOrientation(LinearLayout.HORIZONTAL);
     }
 
-    public void setComponentToAppMap(HashMap<ComponentKey, AppInfo> componentToAppMap) {
-        this.mComponentToAppMap = componentToAppMap;
+    public void setup(AllAppsGridAdapter adapter,
+            HashMap<ComponentKey, AppInfo> componentToAppMap, int numPredictedAppsPerRow) {
+        mAdapter = adapter;
+        mComponentToAppMap = componentToAppMap;
+        mNumPredictedAppsPerRow = numPredictedAppsPerRow;
     }
 
     /**
@@ -64,10 +71,6 @@
         mNumPredictedAppsPerRow = numPredictedAppsPerRow;
     }
 
-    public void onAppsUpdated() {
-        // TODO
-    }
-
     /**
      * Returns the predicted apps.
      */
@@ -87,15 +90,35 @@
     public void setPredictedApps(List<ComponentKeyMapper<AppInfo>> apps) {
         mPredictedAppComponents.clear();
         mPredictedAppComponents.addAll(apps);
+        mPredictedApps.addAll(processPredictedAppComponents(mPredictedAppComponents));
+        onAppsUpdated();
+    }
 
-        List<AppInfo> newPredictedApps = processPredictedAppComponents(apps);
-        // We only need to do work if any of the visible predicted apps have changed.
-        if (!newPredictedApps.equals(mPredictedApps)) {
-            if (newPredictedApps.size() == mPredictedApps.size()) {
-                swapInNewPredictedApps(newPredictedApps);
+    private void onAppsUpdated() {
+        if (getChildCount() != mNumPredictedAppsPerRow) {
+            while (getChildCount() > mNumPredictedAppsPerRow) {
+                removeViewAt(0);
+            }
+            while (getChildCount() < mNumPredictedAppsPerRow) {
+                AllAppsGridAdapter.ViewHolder holder = mAdapter
+                        .onCreateViewHolder(this, AllAppsGridAdapter.VIEW_TYPE_ICON);
+                BubbleTextView icon = (BubbleTextView) holder.itemView;
+                LinearLayout.LayoutParams params =
+                        new LayoutParams(0, icon.getLayoutParams().height);
+                params.weight = 1;
+                icon.setLayoutParams(params);
+                addView(icon);
+            }
+        }
+
+        for (int i = 0; i < getChildCount(); i++) {
+            BubbleTextView icon = (BubbleTextView) getChildAt(i);
+            icon.reset();
+            if (mPredictedApps.size() > i) {
+                icon.setVisibility(View.VISIBLE);
+                icon.applyFromApplicationInfo(mPredictedApps.get(i));
             } else {
-                // We need to update the appIndex of all the items.
-                onAppsUpdated();
+                icon.setVisibility(View.INVISIBLE);
             }
         }
     }
@@ -124,16 +147,4 @@
         }
         return predictedApps;
     }
-
-    /**
-     * Swaps out the old predicted apps with the new predicted apps, in place. This optimization
-     * allows us to skip an entire relayout that would otherwise be called by notifyDataSetChanged.
-     *
-     * Note: This should only be called if the # of predicted apps is the same.
-     *       This method assumes that predicted apps are the first items in the adapter.
-     */
-    private void swapInNewPredictedApps(List<AppInfo> apps) {
-        // TODO
-    }
-
 }
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index 1924710..7cf3da0 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -61,4 +61,6 @@
 
     // When enabled shows a work profile tab in all apps
     public static final boolean ALL_APPS_TABS_ENABLED = false;
+    // When enabled prediction row is rendered as it's own custom view
+    public static final boolean ALL_APPS_PREDICTION_ROW_VIEW = false;
 }
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index 816c1d4..8640401 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -118,9 +118,9 @@
         deepShortcutMap.clear();
     }
 
-     public synchronized void dump(String prefix, FileDescriptor fd, PrintWriter writer,
-             String[] args) {
-        if (args.length > 0 && TextUtils.equals(args[0], "--proto")) {
+    public synchronized void dump(String prefix, FileDescriptor fd, PrintWriter writer,
+            String[] args) {
+        if (Arrays.asList(args).contains("--proto")) {
             dumpProto(prefix, fd, writer, args);
             return;
         }
@@ -219,7 +219,7 @@
             targetList.addAll(workspaces.valueAt(i).getFlattenedList());
         }
 
-        if (args.length > 1 && TextUtils.equals(args[1], "--debug")) {
+        if (Arrays.asList(args).contains("--debug")) {
             for (int i = 0; i < targetList.size(); i++) {
                 writer.println(prefix + DumpTargetWrapper.getDumpTargetStr(targetList.get(i)));
             }
diff --git a/src/com/android/launcher3/util/TraceHelper.java b/src/com/android/launcher3/util/TraceHelper.java
index 5b66fcd..0f3ac57 100644
--- a/src/com/android/launcher3/util/TraceHelper.java
+++ b/src/com/android/launcher3/util/TraceHelper.java
@@ -33,9 +33,8 @@
 
     private static final boolean ENABLED = FeatureFlags.IS_DOGFOOD_BUILD;
 
-    private static final boolean SYSTEM_TRACE = true;
-    private static final ArrayMap<String, MutableLong> sUpTimes =
-            ENABLED ? new ArrayMap<String, MutableLong>() : null;
+    private static final boolean SYSTEM_TRACE = false;
+    private static final ArrayMap<String, MutableLong> sUpTimes = ENABLED ? new ArrayMap<>() : null;
 
     public static void beginSection(String sectionName) {
         if (ENABLED) {
diff --git a/src/com/android/launcher3/views/SlidingTabStrip.java b/src/com/android/launcher3/views/SlidingTabStrip.java
index 45c6261..c2ef41b 100644
--- a/src/com/android/launcher3/views/SlidingTabStrip.java
+++ b/src/com/android/launcher3/views/SlidingTabStrip.java
@@ -34,7 +34,7 @@
     private int mSelectedIndicatorHeight;
     private int mIndicatorLeft = -1;
     private int mIndicatorRight = -1;
-    private int mSelectedPosition = -1;
+    private int mSelectedPosition = 0;
     private float mSelectionOffset;
 
     public SlidingTabStrip(@NonNull Context context, @Nullable AttributeSet attrs) {
@@ -63,8 +63,8 @@
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
-        updateTabTextColor(0);
-        updateIndicatorPosition(0, 0);
+        updateTabTextColor(mSelectedPosition);
+        updateIndicatorPosition(mSelectedPosition, 0);
     }
 
     private void updateIndicatorPosition() {