Deal with the edge case of dragging from shelf while typing

The edge case of dragging the shelf while typing in the search
box is not taken into consideration. As result, when the
expected app list view state is FULLSCREEN_SEARCH, its actual
state is FULLSCREEN_ALL_APPS. This CL fixes the problem.

In addition, refactor the code: move the code block, which is for
calculating the app list view state after shelf drag, from
ShelfLayoutManager to AppListView.


Test: None
Bug: 919205
Change-Id: I39aa095bbd1a9417d07b50cc6caed1084fde5f4d
Reviewed-on: https://chromium-review.googlesource.com/c/1462419
Commit-Queue: Andrew Xu <andrewxu@chromium.org>
Reviewed-by: Xiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#631795}
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc
index fb4107b..e87884f 100644
--- a/ash/app_list/app_list_controller_impl.cc
+++ b/ash/app_list/app_list_controller_impl.cc
@@ -702,6 +702,15 @@
   presenter_.SetExpandArrowViewVisibility(should_show);
 }
 
+app_list::AppListViewState AppListControllerImpl::CalculateStateAfterShelfDrag(
+    const ui::GestureEvent& gesture_in_screen,
+    float launcher_above_shelf_bottom_amount) const {
+  if (presenter_.GetView())
+    return presenter_.GetView()->CalculateStateAfterShelfDrag(
+        gesture_in_screen, launcher_above_shelf_bottom_amount);
+  return app_list::AppListViewState::CLOSED;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Methods of |client_|:
 
diff --git a/ash/app_list/app_list_controller_impl.h b/ash/app_list/app_list_controller_impl.h
index ce85fc7..b6f251f 100644
--- a/ash/app_list/app_list_controller_impl.h
+++ b/ash/app_list/app_list_controller_impl.h
@@ -255,9 +255,14 @@
   // Returns current visibility of the Assistant page.
   bool IsShowingEmbeddedAssistantUI() const;
 
-  // Update the visibility of expand arrow view.
+  // Updates the visibility of expand arrow view.
   void UpdateExpandArrowVisibility();
 
+  // Get updated app list view state after dragging from shelf.
+  app_list::AppListViewState CalculateStateAfterShelfDrag(
+      const ui::GestureEvent& gesture_in_screen,
+      float launcher_above_shelf_bottom_amount) const;
+
  private:
   syncer::StringOrdinal GetOemFolderPos();
   std::unique_ptr<app_list::AppListItem> CreateAppListItem(
diff --git a/ash/app_list/presenter/app_list_presenter_impl.h b/ash/app_list/presenter/app_list_presenter_impl.h
index 7d1c13d..a33c2fb 100644
--- a/ash/app_list/presenter/app_list_presenter_impl.h
+++ b/ash/app_list/presenter/app_list_presenter_impl.h
@@ -57,6 +57,7 @@
 
   // Returns app list view if one exists, or NULL otherwise.
   AppListView* GetView() { return view_; }
+  const AppListView* GetView() const { return view_; }
 
   // Show the app list window on the display with the given id. If
   // |event_time_stamp| is not 0, it means |Show()| was triggered by one of the
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc
index 2558adb9..1c7b78b 100644
--- a/ash/app_list/views/app_list_view.cc
+++ b/ash/app_list/views/app_list_view.cc
@@ -69,10 +69,6 @@
 // order to transition to the next state.
 constexpr int kAppListThresholdDenominator = 3;
 
-// The velocity the app list must be dragged in order to transition to the next
-// state, measured in DIPs/event.
-constexpr int kAppListDragVelocityThreshold = 6;
-
 // The scroll offset in order to transition from PEEKING to FULLSCREEN
 constexpr int kAppListMinScrollToSwitchStates = 20;
 
@@ -736,7 +732,7 @@
   // Change the app list state based on where the drag ended. If fling velocity
   // was over the threshold, snap to the next state in the direction of the
   // fling.
-  if (std::abs(last_fling_velocity_) >= kAppListDragVelocityThreshold) {
+  if (std::abs(last_fling_velocity_) >= kDragVelocityThreshold) {
     // If the user releases drag with velocity over the threshold, snap to
     // the next state, ignoring the drag release position.
 
@@ -1514,6 +1510,49 @@
   return display_bounds.height() - display.work_area().y() + display_bounds.y();
 }
 
+AppListViewState AppListView::CalculateStateAfterShelfDrag(
+    const ui::GestureEvent& gesture_in_screen,
+    float launcher_above_shelf_bottom_amount) const {
+  AppListViewState app_list_state = AppListViewState::PEEKING;
+  if (gesture_in_screen.type() == ui::ET_SCROLL_FLING_START &&
+      fabs(gesture_in_screen.details().velocity_y()) > kDragVelocityThreshold) {
+    // If the scroll sequence terminates with a fling, show the fullscreen app
+    // list if the fling was fast enough and in the correct direction, otherwise
+    // close it.
+    app_list_state = gesture_in_screen.details().velocity_y() < 0
+                         ? AppListViewState::FULLSCREEN_ALL_APPS
+                         : AppListViewState::CLOSED;
+  } else {
+    // Snap the app list to corresponding state according to the snapping
+    // thresholds.
+    if (is_tablet_mode_) {
+      app_list_state =
+          launcher_above_shelf_bottom_amount > kDragSnapToFullscreenThreshold
+              ? AppListViewState::FULLSCREEN_ALL_APPS
+              : AppListViewState::CLOSED;
+    } else {
+      if (launcher_above_shelf_bottom_amount <= kDragSnapToClosedThreshold)
+        app_list_state = AppListViewState::CLOSED;
+      else if (launcher_above_shelf_bottom_amount <=
+               kDragSnapToPeekingThreshold)
+        app_list_state = AppListViewState::PEEKING;
+      else
+        app_list_state = AppListViewState::FULLSCREEN_ALL_APPS;
+    }
+  }
+
+  // Deal with the situation of dragging app list from shelf while typing in
+  // the search box.
+  if (app_list_state == AppListViewState::FULLSCREEN_ALL_APPS) {
+    ash::AppListState active_state =
+        app_list_main_view_->contents_view()->GetActiveState();
+    if (active_state == ash::AppListState::kStateSearchResults)
+      app_list_state = AppListViewState::FULLSCREEN_SEARCH;
+  }
+
+  return app_list_state;
+}
+
 void AppListView::UpdateChildViewsYPositionAndOpacity() {
   if (app_list_state_ == AppListViewState::CLOSED)
     return;
diff --git a/ash/app_list/views/app_list_view.h b/ash/app_list/views/app_list_view.h
index c865474..589343c 100644
--- a/ash/app_list/views/app_list_view.h
+++ b/ash/app_list/views/app_list_view.h
@@ -86,6 +86,19 @@
   // its state.
   static constexpr int kScrollIgnoreTimeMs = 500;
 
+  // The snapping threshold for dragging app list from shelf in tablet mode,
+  // measured in DIPs.
+  static constexpr int kDragSnapToFullscreenThreshold = 320;
+
+  // The snapping thresholds for dragging app list from shelf in laptop mode,
+  // measured in DIPs.
+  static constexpr int kDragSnapToClosedThreshold = 144;
+  static constexpr int kDragSnapToPeekingThreshold = 561;
+
+  // The velocity the app list must be dragged in order to transition to the
+  // next state, measured in DIPs/event.
+  static constexpr int kDragVelocityThreshold = 6;
+
   struct InitParams {
     gfx::NativeView parent = nullptr;
     int initial_apps_page = 0;
@@ -215,6 +228,12 @@
   // Returns the height of app list in fullscreen state.
   int GetFullscreenStateHeight() const;
 
+  // Calculates and returns the app list view state after dragging from shelf
+  // ends.
+  AppListViewState CalculateStateAfterShelfDrag(
+      const ui::GestureEvent& gesture_in_screen,
+      float launcher_above_shelf_bottom_amount) const;
+
   views::Widget* get_fullscreen_widget_for_test() const {
     return fullscreen_widget_;
   }
diff --git a/ash/shelf/app_list_button_unittest.cc b/ash/shelf/app_list_button_unittest.cc
index 0a846c7..fa0bbb0 100644
--- a/ash/shelf/app_list_button_unittest.cc
+++ b/ash/shelf/app_list_button_unittest.cc
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "ash/app_list/test/app_list_test_helper.h"
+#include "ash/app_list/views/app_list_view.h"
 #include "ash/assistant/assistant_controller.h"
 #include "ash/assistant/assistant_ui_controller.h"
 #include "ash/assistant/model/assistant_ui_model.h"
@@ -15,7 +16,6 @@
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
 #include "ash/shelf/shelf.h"
-#include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shelf/shelf_view.h"
 #include "ash/shelf/shelf_view_test_api.h"
 #include "ash/shell.h"
@@ -79,7 +79,7 @@
   // Swiping up less than the threshold should trigger a peeking app list.
   gfx::Point end = start;
   end.set_y(shelf->GetIdealBounds().bottom() -
-            ShelfLayoutManager::kAppListDragSnapToPeekingThreshold + 10);
+            app_list::AppListView::kDragSnapToPeekingThreshold + 10);
   GetEventGenerator()->GestureScrollSequence(
       start, end, base::TimeDelta::FromMilliseconds(100), 4 /* steps */);
   GetAppListTestHelper()->WaitUntilIdle();
@@ -93,7 +93,7 @@
 
   // Swiping above the threshold should trigger a fullscreen app list.
   end.set_y(shelf->GetIdealBounds().bottom() -
-            ShelfLayoutManager::kAppListDragSnapToPeekingThreshold - 10);
+            app_list::AppListView::kDragSnapToPeekingThreshold - 10);
   GetEventGenerator()->GestureScrollSequence(
       start, end, base::TimeDelta::FromMilliseconds(100), 4 /* steps */);
   base::RunLoop().RunUntilIdle();
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index efa1af1..410a5f4 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -1399,42 +1399,15 @@
   }
 
   using app_list::AppListViewState;
-  AppListViewState app_list_state = AppListViewState::PEEKING;
-  if (gesture_in_screen.type() == ui::ET_SCROLL_FLING_START &&
-      fabs(gesture_in_screen.details().velocity_y()) >
-          kAppListDragVelocityThreshold) {
-    // If the scroll sequence terminates with a fling, show the fullscreen app
-    // list if the fling was fast enough and in the correct direction, otherwise
-    // close it.
-    app_list_state = gesture_in_screen.details().velocity_y() < 0
-                         ? AppListViewState::FULLSCREEN_ALL_APPS
-                         : AppListViewState::CLOSED;
-  } else {
-    // Snap the app list to corresponding state according to the snapping
-    // thresholds.
-    if (IsTabletModeEnabled()) {
-      app_list_state = launcher_above_shelf_bottom_amount_ >
-                               kAppListDragSnapToFullscreenThreshold
-                           ? AppListViewState::FULLSCREEN_ALL_APPS
-                           : AppListViewState::CLOSED;
-    } else {
-      if (launcher_above_shelf_bottom_amount_ <=
-          kAppListDragSnapToClosedThreshold)
-        app_list_state = AppListViewState::CLOSED;
-      else if (launcher_above_shelf_bottom_amount_ <=
-               kAppListDragSnapToPeekingThreshold)
-        app_list_state = AppListViewState::PEEKING;
-      else
-        app_list_state = AppListViewState::FULLSCREEN_ALL_APPS;
-    }
-  }
+  AppListViewState app_list_state =
+      Shell::Get()->app_list_controller()->CalculateStateAfterShelfDrag(
+          gesture_in_screen, launcher_above_shelf_bottom_amount_);
 
   // Keep auto-hide shelf visible if failed to open the app list.
   base::Optional<Shelf::ScopedAutoHideLock> auto_hide_lock;
   if (app_list_state == AppListViewState::CLOSED)
     auto_hide_lock.emplace(shelf_);
   Shell::Get()->app_list_controller()->EndDragFromShelf(app_list_state);
-
   gesture_drag_status_ = GESTURE_DRAG_NONE;
 }
 
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index a62bc36..32bfaf4f 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -63,19 +63,6 @@
       public WallpaperControllerObserver,
       public LocaleChangeObserver {
  public:
-  // The snapping threshold for dragging app list from shelf in tablet mode,
-  // measured in DIPs.
-  static constexpr int kAppListDragSnapToFullscreenThreshold = 320;
-
-  // The snapping thresholds for dragging app list from shelf in laptop mode,
-  // measured in DIPs.
-  static constexpr int kAppListDragSnapToClosedThreshold = 144;
-  static constexpr int kAppListDragSnapToPeekingThreshold = 561;
-
-  // The velocity the app list must be dragged in order to change the state of
-  // the app list for fling event, measured in DIPs/event.
-  static constexpr int kAppListDragVelocityThreshold = 6;
-
   ShelfLayoutManager(ShelfWidget* shelf_widget, Shelf* shelf);
   ~ShelfLayoutManager() override;
 
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index 5b3b3fc..aeeb9e49 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -12,6 +12,7 @@
 #include "ash/app_list/app_list_controller_impl.h"
 #include "ash/app_list/home_launcher_gesture_handler.h"
 #include "ash/app_list/test/app_list_test_helper.h"
+#include "ash/app_list/views/app_list_view.h"
 #include "ash/focus_cycler.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h"
@@ -1758,9 +1759,9 @@
   // Fling up that exceeds the velocity threshold should show the fullscreen app
   // list.
   StartScroll(start);
-  UpdateScroll(-ShelfLayoutManager::kAppListDragSnapToPeekingThreshold);
+  UpdateScroll(-app_list::AppListView::kDragSnapToPeekingThreshold);
   EndScroll(true /* is_fling */,
-            -(ShelfLayoutManager::kAppListDragVelocityThreshold + 10));
+            -(app_list::AppListView::kDragVelocityThreshold + 10));
   GetAppListTestHelper()->WaitUntilIdle();
   GetAppListTestHelper()->CheckVisibility(true);
   GetAppListTestHelper()->CheckState(
@@ -1773,9 +1774,9 @@
 
   // Fling down that exceeds the velocity threshold should close the app list.
   StartScroll(start);
-  UpdateScroll(-ShelfLayoutManager::kAppListDragSnapToPeekingThreshold);
+  UpdateScroll(-app_list::AppListView::kDragSnapToPeekingThreshold);
   EndScroll(true /* is_fling */,
-            ShelfLayoutManager::kAppListDragVelocityThreshold + 10);
+            app_list::AppListView::kDragVelocityThreshold + 10);
   GetAppListTestHelper()->WaitUntilIdle();
   GetAppListTestHelper()->CheckVisibility(false);
   GetAppListTestHelper()->CheckState(app_list::AppListViewState::CLOSED);
@@ -1783,9 +1784,9 @@
   // Fling the app list not exceed the velocity threshold, the state depends on
   // the drag amount.
   StartScroll(start);
-  UpdateScroll(-(ShelfLayoutManager::kAppListDragSnapToPeekingThreshold - 10));
+  UpdateScroll(-(app_list::AppListView::kDragSnapToPeekingThreshold - 10));
   EndScroll(true /* is_fling */,
-            -(ShelfLayoutManager::kAppListDragVelocityThreshold - 10));
+            -(app_list::AppListView::kDragVelocityThreshold - 10));
   GetAppListTestHelper()->WaitUntilIdle();
   GetAppListTestHelper()->CheckVisibility(true);
   GetAppListTestHelper()->CheckState(app_list::AppListViewState::PEEKING);
@@ -1805,8 +1806,7 @@
                  shelf_widget_bounds.bottom() + 1);
   gfx::Point end = gfx::Point(
       start.x(), shelf_widget_bounds.bottom() -
-                     ShelfLayoutManager::kAppListDragSnapToPeekingThreshold -
-                     10);
+                     app_list::AppListView::kDragSnapToPeekingThreshold - 10);
   ui::test::EventGenerator* generator = GetEventGenerator();
   constexpr base::TimeDelta kTimeDelta = base::TimeDelta::FromMilliseconds(100);
   constexpr int kNumScrollSteps = 4;
@@ -1828,7 +1828,7 @@
   start.set_y(
       display::Screen::GetScreen()->GetPrimaryDisplay().work_area().y());
   end.set_y(shelf_widget_bounds.bottom() -
-            ShelfLayoutManager::kAppListDragSnapToClosedThreshold + 10);
+            app_list::AppListView::kDragSnapToClosedThreshold + 10);
   generator->GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
   GetAppListTestHelper()->WaitUntilIdle();
   GetAppListTestHelper()->CheckVisibility(false);
@@ -1843,7 +1843,7 @@
   EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
 
   StartScroll(GetShelfWidget()->GetWindowBoundsInScreen().CenterPoint());
-  UpdateScroll(-ShelfLayoutManager::kAppListDragSnapToPeekingThreshold);
+  UpdateScroll(-app_list::AppListView::kDragSnapToPeekingThreshold);
   GetAppListTestHelper()->WaitUntilIdle();
   shelf->SetAlignment(SHELF_ALIGNMENT_LEFT);
   // Note, value -10 here has no specific meaning, it only used to make the
@@ -1870,7 +1870,7 @@
   gfx::Vector2d delta;
 
   // Swiping up less than the close threshold should close the app list.
-  delta.set_y(ShelfLayoutManager::kAppListDragSnapToClosedThreshold - 10);
+  delta.set_y(app_list::AppListView::kDragSnapToClosedThreshold - 10);
   gfx::Point end = start - delta;
   generator->GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
   EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
@@ -1880,7 +1880,7 @@
 
   // Swiping up more than the close threshold but less than peeking threshold
   // should keep the app list at PEEKING state.
-  delta.set_y(ShelfLayoutManager::kAppListDragSnapToPeekingThreshold - 10);
+  delta.set_y(app_list::AppListView::kDragSnapToPeekingThreshold - 10);
   end = start - delta;
   generator->GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
   EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
@@ -1895,7 +1895,7 @@
 
   // Swiping up more than the peeking threshold should keep the app list at
   // FULLSCREEN_ALL_APPS state.
-  delta.set_y(ShelfLayoutManager::kAppListDragSnapToPeekingThreshold + 10);
+  delta.set_y(app_list::AppListView::kDragSnapToPeekingThreshold + 10);
   end = start - delta;
   generator->GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
   EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
@@ -1926,7 +1926,7 @@
   // Swiping up on the auto-hide shelf to drag up the app list. Close the app
   // list on drag ended since the short drag distance but keep the previous
   // shown auto-hide shelf still visible.
-  delta.set_y(ShelfLayoutManager::kAppListDragSnapToClosedThreshold - 10);
+  delta.set_y(app_list::AppListView::kDragSnapToClosedThreshold - 10);
   end = start - delta;
   generator->GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
   GetAppListTestHelper()->WaitUntilIdle();