Merge "Enable split from workspace / all apps"
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 7f9f63e..6df6212 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -33,7 +33,6 @@
         android:id="@+id/all_apps_header"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_below="@id/search_container_all_apps"
         android:clipToPadding="false"
         android:paddingTop="@dimen/all_apps_header_top_padding"
         android:paddingBottom="@dimen/all_apps_header_bottom_padding"
diff --git a/res/layout/all_apps_content_layout.xml b/res/layout/all_apps_content_layout.xml
deleted file mode 100644
index 5698977..0000000
--- a/res/layout/all_apps_content_layout.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2020 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:id="@+id/apps_list_view_override"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_below="@id/search_container_all_apps"
-    android:clipToPadding="false"
-    android:descendantFocusability="afterDescendants"
-    android:focusable="true"
-    android:layout_marginTop="@dimen/all_apps_header_top_padding"
-    android:orientation="vertical">
-</LinearLayout>
diff --git a/res/layout/all_apps_fast_scroller.xml b/res/layout/all_apps_fast_scroller.xml
index 5537bc6..f6a6156 100644
--- a/res/layout/all_apps_fast_scroller.xml
+++ b/res/layout/all_apps_fast_scroller.xml
@@ -21,7 +21,7 @@
         android:id="@+id/fast_scroller_popup"
         style="@style/FastScrollerPopup"
         android:layout_alignParentEnd="true"
-        android:layout_below="@+id/search_container_all_apps"
+        android:layout_alignTop="@+id/all_apps_header"
         android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
 
     <com.android.launcher3.views.RecyclerViewFastScroller
@@ -30,7 +30,7 @@
         android:layout_height="wrap_content"
         android:layout_alignParentBottom="true"
         android:layout_alignParentEnd="true"
-        android:layout_below="@+id/search_container_all_apps"
+        android:layout_alignTop="@+id/all_apps_header"
         android:layout_marginEnd="@dimen/fastscroll_end_margin"
         launcher:canThumbDetach="true" />
 
diff --git a/res/layout/all_apps_rv_layout.xml b/res/layout/all_apps_rv_layout.xml
index c353b36..26d8ecc 100644
--- a/res/layout/all_apps_rv_layout.xml
+++ b/res/layout/all_apps_rv_layout.xml
@@ -19,7 +19,6 @@
     android:id="@+id/apps_list_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:layout_below="@id/search_container_all_apps"
     android:clipToPadding="false"
     android:descendantFocusability="afterDescendants"
     android:focusable="true" />
diff --git a/res/layout/all_apps_tabs.xml b/res/layout/all_apps_tabs.xml
index de4a69d..cf68f51 100644
--- a/res/layout/all_apps_tabs.xml
+++ b/res/layout/all_apps_tabs.xml
@@ -20,7 +20,6 @@
     android:id="@+id/all_apps_tabs_view_pager"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:layout_below="@id/search_container_all_apps"
     android:layout_gravity="center_horizontal|top"
     android:layout_marginTop="@dimen/all_apps_header_pill_height"
     android:clipChildren="true"
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 49981be..c456a4d 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -1151,6 +1151,7 @@
         writer.println(prefix + pxToDpStr("hotseatBarSidePaddingEndPx",
                 hotseatBarSidePaddingEndPx));
         writer.println(prefix + "\tnumShownHotseatIcons: " + numShownHotseatIcons);
+        writer.println(prefix + pxToDpStr("hotseatBorderSpace", hotseatBorderSpace));
         writer.println(prefix + "\tisQsbInline: " + isQsbInline);
         writer.println(prefix + pxToDpStr("qsbWidth", qsbWidth));
 
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 59c40cc..fb4a7fd 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -41,6 +41,7 @@
 import static com.android.launcher3.Utilities.postAsyncCallback;
 import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions;
 import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_LAUNCHER_LOAD;
+import static com.android.launcher3.logging.StatsLogManager.EventEnum;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_ENTRY;
@@ -141,6 +142,8 @@
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.keyboard.ViewGroupFocusHelper;
 import com.android.launcher3.logger.LauncherAtom;
+import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
+import com.android.launcher3.logger.LauncherAtom.WorkspaceContainer;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.logging.InstanceId;
 import com.android.launcher3.logging.InstanceIdSequence;
@@ -1103,14 +1106,23 @@
                 && mAllAppsSessionLogId == null) {
             // creates new instance ID since new all apps session is started.
             mAllAppsSessionLogId = new InstanceIdSequence().newInstanceId();
-            getStatsLogManager()
-                    .logger()
-                    .log(FeatureFlags.ENABLE_DEVICE_SEARCH.get()
-                            ? LAUNCHER_ALLAPPS_ENTRY_WITH_DEVICE_SEARCH
-                            : LAUNCHER_ALLAPPS_ENTRY);
+            getStatsLogManager().logger().withContainerInfo(
+                    ContainerInfo.newBuilder().setWorkspace(
+                            WorkspaceContainer.newBuilder().setPageIndex(
+                                    getWorkspace().getCurrentPage())).build())
+                    .log(getAllAppsEntryEvent());
         }
     }
 
+    /**
+     * Returns {@link EventEnum} that should be logged when Launcher enters into AllApps state.
+     */
+    protected EventEnum getAllAppsEntryEvent() {
+        return FeatureFlags.ENABLE_DEVICE_SEARCH.get()
+                ? LAUNCHER_ALLAPPS_ENTRY_WITH_DEVICE_SEARCH
+                : LAUNCHER_ALLAPPS_ENTRY;
+    }
+
     @Override
     public void onStateSetEnd(LauncherState state) {
         super.onStateSetEnd(state);
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 070b98e..fb87f88 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -21,6 +21,7 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
+import android.widget.RelativeLayout;
 
 import androidx.core.graphics.ColorUtils;
 import androidx.recyclerview.widget.RecyclerView;
@@ -177,6 +178,28 @@
     }
 
     @Override
+    protected View replaceRVContainer(boolean showTabs) {
+        View rvContainer = super.replaceRVContainer(showTabs);
+        if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
+            alignParentTop(rvContainer);
+            layoutAboveSearchContainer(rvContainer);
+        } else {
+            layoutBelowSearchContainer(rvContainer);
+        }
+        return rvContainer;
+    }
+
+    @Override
+    void setupHeader() {
+        super.setupHeader();
+        if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
+            alignParentTop(mHeader);
+        } else {
+            layoutBelowSearchContainer(mHeader);
+        }
+    }
+
+    @Override
     protected void updateHeaderScroll(int scrolledOffset) {
         super.updateHeaderScroll(scrolledOffset);
         if (mSearchUiManager.getEditText() == null) {
@@ -202,6 +225,36 @@
 
     @Override
     protected int getHeaderBottom() {
+        if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
+            return super.getHeaderBottom();
+        }
         return super.getHeaderBottom() + mSearchContainer.getBottom();
     }
+
+    private void layoutBelowSearchContainer(View v) {
+        if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) {
+            return;
+        }
+        RelativeLayout.LayoutParams layoutParams = (LayoutParams) v.getLayoutParams();
+        layoutParams.removeRule(RelativeLayout.ALIGN_PARENT_TOP);
+        layoutParams.removeRule(RelativeLayout.ABOVE);
+        layoutParams.addRule(RelativeLayout.BELOW, R.id.search_container_all_apps);
+    }
+
+    private void layoutAboveSearchContainer(View v) {
+        if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) {
+            return;
+        }
+        RelativeLayout.LayoutParams layoutParams = (LayoutParams) v.getLayoutParams();
+        layoutParams.addRule(RelativeLayout.ABOVE, R.id.search_container_all_apps);
+    }
+
+    private void alignParentTop(View v) {
+        if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) {
+            return;
+        }
+        RelativeLayout.LayoutParams layoutParams = (LayoutParams) v.getLayoutParams();
+        layoutParams.removeRule(RelativeLayout.BELOW);
+        layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+    }
 }
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
index b257407..e8dcdbd 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
@@ -368,8 +368,7 @@
     }
 
     @Override
-    public void onDropCompleted(View target, DragObject d, boolean success) {
-    }
+    public void onDropCompleted(View target, DragObject d, boolean success) {}
 
     @Override
     public void setInsets(Rect insets) {
@@ -478,7 +477,7 @@
         return mHasWorkApps;
     }
 
-    private void replaceRVContainer(boolean showTabs) {
+    protected View replaceRVContainer(boolean showTabs) {
         for (AdapterHolder adapterHolder : mAH) {
             if (adapterHolder.mRecyclerView != null) {
                 adapterHolder.mRecyclerView.setLayoutManager(null);
@@ -503,6 +502,7 @@
             mWorkManager.detachWorkModeSwitch();
             mViewPager = null;
         }
+        return newView;
     }
 
     public View getRecyclerViewContainer() {
@@ -634,7 +634,9 @@
 
     @Override
     public void drawOnScrim(Canvas canvas) {
-        if (!mHeader.isHeaderProtectionSupported()) return;
+        if (!mHeader.isHeaderProtectionSupported()) {
+            return;
+        }
         mHeaderPaint.setColor(mHeaderColor);
         mHeaderPaint.setAlpha((int) (getAlpha() * Color.alpha(mHeaderColor)));
         if (mHeaderPaint.getColor() != mScrimColor && mHeaderPaint.getColor() != 0) {
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
index 9d1b04e..bcb0d14 100644
--- a/src/com/android/launcher3/allapps/WorkProfileManager.java
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -26,12 +26,14 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Log;
+import android.view.ViewGroup;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 
 import com.android.launcher3.R;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip;
 
@@ -138,6 +140,15 @@
             mWorkModeSwitch = (WorkModeSwitch) mAllApps.getLayoutInflater().inflate(
                     R.layout.work_mode_fab, mAllApps, false);
         }
+        int workFabMarginBottom =
+                mWorkModeSwitch.getResources().getDimensionPixelSize(R.dimen.work_fab_margin);
+        if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
+            workFabMarginBottom <<= 1;  // Double margin to add space above search bar.
+            workFabMarginBottom +=
+                    mWorkModeSwitch.getResources().getDimensionPixelSize(R.dimen.qsb_widget_height);
+        }
+        ((ViewGroup.MarginLayoutParams) mWorkModeSwitch.getLayoutParams()).bottomMargin =
+                workFabMarginBottom;
         if (mWorkModeSwitch.getParent() != mAllApps) {
             mAllApps.addView(mWorkModeSwitch);
         }
@@ -158,7 +169,6 @@
         mWorkModeSwitch = null;
     }
 
-
     public WorkAdapterProvider getAdapterProvider() {
         return mAdapterProvider;
     }
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 6ea95f2..99c9bb9 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -92,6 +92,10 @@
     public static final BooleanFlag ENABLE_ONE_SEARCH = new DeviceFlag("ENABLE_ONE_SEARCH", false,
             "Use homescreen search box to complete allApps searches");
 
+    public static final BooleanFlag ENABLE_FLOATING_SEARCH_BAR =
+            getDebugFlag("ENABLE_FLOATING_SEARCH_BAR", false,
+                    "Keep All Apps search bar at the bottom (but above keyboard if open)");
+
     public static final BooleanFlag COLLECT_SEARCH_HISTORY = new DeviceFlag(
             "COLLECT_SEARCH_HISTORY", false, "Allow launcher to collect search history for log");
 
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index a7cfdde..0d2bc37 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -258,6 +258,9 @@
         @UiEvent(doc = "User swipes or fling in DOWN direction to close apps drawer.")
         LAUNCHER_ALLAPPS_CLOSE_DOWN(569),
 
+        @UiEvent(doc = "User tap outside apps drawer sheet to close apps drawer.")
+        LAUNCHER_ALLAPPS_CLOSE_TAP_OUTSIDE(941),
+
         @UiEvent(doc = "User swipes or fling in UP direction and hold from the bottom bazel area")
         LAUNCHER_OVERVIEW_GESTURE(570),
 
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index 93387ad..e8941e6 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -23,6 +23,7 @@
 
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_CLOSE_TAP_OUTSIDE;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WORKSPACE_LONGPRESS;
 
 import android.graphics.PointF;
@@ -40,6 +41,7 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.logger.LauncherAtom;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.TestProtocol;
 
@@ -155,6 +157,16 @@
                 && mLauncher.isInState(ALL_APPS)
                 && mLauncher.getDeviceProfile().isTablet) {
             mLauncher.getStateManager().goToState(NORMAL);
+            mLauncher.getStatsLogManager().logger()
+                    .withSrcState(ALL_APPS.statsLogOrdinal)
+                    .withDstState(NORMAL.statsLogOrdinal)
+                    .withContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
+                            .setWorkspace(
+                                    LauncherAtom.WorkspaceContainer.newBuilder()
+                                            .setPageIndex(
+                                                    mLauncher.getWorkspace().getCurrentPage()))
+                            .build())
+                    .log(LAUNCHER_ALLAPPS_CLOSE_TAP_OUTSIDE);
         }
 
         return result;
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index f0b4ba0..53c772f 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -16,12 +16,16 @@
 
 package com.android.launcher3.widget;
 
+import android.annotation.TargetApi;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.os.Build;
 import android.os.Handler;
 import android.os.SystemClock;
+import android.os.Trace;
+import android.util.Log;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.view.MotionEvent;
@@ -52,6 +56,8 @@
         implements TouchCompleteListener, View.OnLongClickListener,
         LocalColorExtractor.Listener {
 
+    private static final String TAG = "LauncherAppWidgetHostView";
+
     // Related to the auto-advancing of widgets
     private static final long ADVANCE_INTERVAL = 20000;
     private static final long ADVANCE_STAGGER = 250;
@@ -61,6 +67,8 @@
     // Maximum duration for which updates can be deferred.
     private static final long UPDATE_LOCK_TIMEOUT_MILLIS = 1000;
 
+    private static final String TRACE_METHOD_NAME = "appwidget load-widget ";
+
     private final Rect mTempRect = new Rect();
     private final CheckLongPressHelper mLongPressHelper;
     protected final Launcher mLauncher;
@@ -88,6 +96,8 @@
     /** The drag content height which is only set when the drag content scale is not 1f. */
     private int mDragContentHeight = 0;
 
+    private boolean mTrackingWidgetUpdate = false;
+
     public LauncherAppWidgetHostView(Context context) {
         super(context);
         mLauncher = Launcher.getLauncher(context);
@@ -121,7 +131,25 @@
     }
 
     @Override
+    @TargetApi(Build.VERSION_CODES.Q)
+    public void setAppWidget(int appWidgetId, AppWidgetProviderInfo info) {
+        super.setAppWidget(appWidgetId, info);
+        if (!mTrackingWidgetUpdate && Utilities.ATLEAST_Q) {
+            mTrackingWidgetUpdate = true;
+            Trace.beginAsyncSection(TRACE_METHOD_NAME + info.provider, appWidgetId);
+            Log.i(TAG, "App widget created with id: " + appWidgetId);
+        }
+    }
+
+    @Override
+    @TargetApi(Build.VERSION_CODES.Q)
     public void updateAppWidget(RemoteViews remoteViews) {
+        if (mTrackingWidgetUpdate && remoteViews != null && Utilities.ATLEAST_Q) {
+            Log.i(TAG, "App widget with id: " + getAppWidgetId() + " loaded");
+            Trace.endAsyncSection(
+                    TRACE_METHOD_NAME + getAppWidgetInfo().provider, getAppWidgetId());
+            mTrackingWidgetUpdate = false;
+        }
         if (isDeferringUpdates()) {
             mDeferredRemoteViews = remoteViews;
             return;