diff --git a/ash/home_screen/swipe_home_to_overview_controller.cc b/ash/home_screen/swipe_home_to_overview_controller.cc
index d2d2e9657c59f..e72457a8ffa5e 100644
--- a/ash/home_screen/swipe_home_to_overview_controller.cc
+++ b/ash/home_screen/swipe_home_to_overview_controller.cc
@@ -4,8 +4,11 @@
 
 #include "ash/home_screen/swipe_home_to_overview_controller.h"
 
+#include "ash/app_list/app_list_controller_impl.h"
+#include "ash/home_screen/drag_window_from_shelf_controller.h"
 #include "ash/home_screen/home_screen_controller.h"
 #include "ash/home_screen/home_screen_delegate.h"
+#include "ash/public/cpp/app_list/app_list_config.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/shelf_config.h"
 #include "ash/session/session_controller_impl.h"
@@ -50,8 +53,11 @@ constexpr base::TimeDelta kGestureCancelationDuration =
     base::TimeDelta::FromMilliseconds(350);
 
 void UpdateHomeAnimationForGestureCancel(
+    bool going_back,
     ui::ScopedLayerAnimationSettings* settings) {
-  settings->SetTransitionDuration(kGestureCancelationDuration);
+  settings->SetTransitionDuration(
+      going_back ? AppListConfig::instance().page_transition_duration()
+                 : kGestureCancelationDuration);
   settings->SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN);
   settings->SetPreemptionStrategy(
       ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
@@ -139,9 +145,21 @@ void SwipeHomeToOverviewController::Drag(const gfx::PointF& location_in_screen,
 void SwipeHomeToOverviewController::EndDrag(
     const gfx::PointF& location_in_screen,
     base::Optional<float> velocity_y) {
+  if (state_ != State::kTrackingDrag) {
+    state_ = State::kFinished;
+    return;
+  }
+
+  // Upward swipe should return to the home screen's initial state.
+  const bool go_back =
+      velocity_y &&
+      *velocity_y <
+          -DragWindowFromShelfController::kVelocityToHomeScreenThreshold;
+
   // Overview is triggered by |overview_transition_timer_|. If EndDrag()
-  // is called before the timer fires, the gesture is canceled.
-  CancelDrag();
+  // is called before the timer fires, the result of the gesture should be
+  // staying on the home screen.
+  FinalizeDragAndStayOnHomeScreen(go_back);
 }
 
 void SwipeHomeToOverviewController::CancelDrag() {
@@ -150,22 +168,7 @@ void SwipeHomeToOverviewController::CancelDrag() {
     return;
   }
 
-  overview_transition_timer_.Stop();
-  overview_transition_threshold_y_ = 0;
-  state_ = State::kFinished;
-
-  UMA_HISTOGRAM_ENUMERATION(kEnterOverviewHistogramName,
-                            EnterOverviewFromHomeLauncher::kCanceled);
-  Shell::Get()
-      ->home_screen_controller()
-      ->delegate()
-      ->UpdateScaleAndOpacityForHomeLauncher(
-          1.0f /*scale*/, 1.0f /*opacity*/, base::nullopt /*animation_info*/,
-          base::BindRepeating(&UpdateHomeAnimationForGestureCancel));
-
-  // No need to keep blur disabled for the drag - note that blur might remain
-  // disabled at this point due to the started home screen scale animation.
-  home_screen_blur_disabler_.reset();
+  FinalizeDragAndStayOnHomeScreen(/*go_back=*/false);
 }
 
 void SwipeHomeToOverviewController::ScheduleFinalizeDragAndShowOverview() {
@@ -190,7 +193,11 @@ void SwipeHomeToOverviewController::FinalizeDragAndShowOverview() {
   }
 
   UMA_HISTOGRAM_ENUMERATION(kEnterOverviewHistogramName,
-                            EnterOverviewFromHomeLauncher::kSuccess);
+                            EnterOverviewFromHomeLauncher::kOverview);
+
+  // NOTE: No need to update the home launcher opacity and scale here - the
+  // HomeScreenController will update the home launcher state when it detects
+  // that the overview is starting.
   Shell::Get()->overview_controller()->StartOverview();
 
   // No need to keep blur disabled for the drag - note that blur might remain
@@ -199,4 +206,34 @@ void SwipeHomeToOverviewController::FinalizeDragAndShowOverview() {
   home_screen_blur_disabler_.reset();
 }
 
+void SwipeHomeToOverviewController::FinalizeDragAndStayOnHomeScreen(
+    bool go_back) {
+  overview_transition_timer_.Stop();
+  overview_transition_threshold_y_ = 0;
+  state_ = State::kFinished;
+
+  if (go_back) {
+    Shell::Get()->app_list_controller()->Back();
+    UMA_HISTOGRAM_ENUMERATION(kEnterOverviewHistogramName,
+                              EnterOverviewFromHomeLauncher::kBack);
+  } else {
+    UMA_HISTOGRAM_ENUMERATION(kEnterOverviewHistogramName,
+                              EnterOverviewFromHomeLauncher::kCanceled);
+  }
+
+  // Make sure the home launcher scale and opacity return to the initial state.
+  // Note that this is needed even if the gesture ended up in a fling, as early
+  // gesture handling might have updated the launcher scale.
+  Shell::Get()
+      ->home_screen_controller()
+      ->delegate()
+      ->UpdateScaleAndOpacityForHomeLauncher(
+          1.0f /*scale*/, 1.0f /*opacity*/, base::nullopt /*animation_info*/,
+          base::BindRepeating(&UpdateHomeAnimationForGestureCancel, go_back));
+
+  // No need to keep blur disabled for the drag - note that blur might remain
+  // disabled at this point due to the started home screen scale animation.
+  home_screen_blur_disabler_.reset();
+}
+
 }  // namespace ash
diff --git a/ash/home_screen/swipe_home_to_overview_controller.h b/ash/home_screen/swipe_home_to_overview_controller.h
index 0d264261f93f4..6c870d06a54b9 100644
--- a/ash/home_screen/swipe_home_to_overview_controller.h
+++ b/ash/home_screen/swipe_home_to_overview_controller.h
@@ -64,6 +64,10 @@ class ASH_EXPORT SwipeHomeToOverviewController {
   // moving the pointer - those events will be ignored.
   void FinalizeDragAndShowOverview();
 
+  // Finalizes the drag sequence by staying on the home screen.
+  // |go_back| - if the gesture should invoke home screen back action.
+  void FinalizeDragAndStayOnHomeScreen(bool go_back);
+
   const int64_t display_id_;
 
   State state_ = State::kInitial;
diff --git a/ash/home_screen/swipe_home_to_overview_controller_unittest.cc b/ash/home_screen/swipe_home_to_overview_controller_unittest.cc
index 31759c33b4eb3..a24f9a364df2f 100644
--- a/ash/home_screen/swipe_home_to_overview_controller_unittest.cc
+++ b/ash/home_screen/swipe_home_to_overview_controller_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "ash/app_list/test/app_list_test_helper.h"
 #include "ash/app_list/views/app_list_view.h"
+#include "ash/app_list/views/search_box_view.h"
 #include "ash/home_screen/home_screen_controller.h"
 #include "ash/home_screen/home_screen_delegate.h"
 #include "ash/public/cpp/ash_features.h"
@@ -112,6 +113,14 @@ class SwipeHomeToOverviewControllerTest : public AshTestBase {
     }
   }
 
+  void TapOnHomeLauncherSearchBox() {
+    GetEventGenerator()->GestureTapAt(GetAppListTestHelper()
+                                          ->GetAppListView()
+                                          ->search_box_view()
+                                          ->GetBoundsInScreen()
+                                          .CenterPoint());
+  }
+
   base::TimeTicks GetTimerDesiredRunTime() const {
     return home_to_overview_controller_->overview_transition_timer_for_testing()
         ->desired_run_time();
@@ -191,7 +200,7 @@ TEST_F(SwipeHomeToOverviewControllerTest, BasicFlow) {
 
   base::HistogramTester histogram_tester;
   histogram_tester.ExpectBucketCount(
-      kEnterOverviewHistogramName, EnterOverviewFromHomeLauncher::kSuccess, 0);
+      kEnterOverviewHistogramName, EnterOverviewFromHomeLauncher::kOverview, 0);
 
   StartDrag();
   // Drag to a point within shelf bounds - verify that app list has not been
@@ -207,7 +216,7 @@ TEST_F(SwipeHomeToOverviewControllerTest, BasicFlow) {
   EXPECT_FALSE(OverviewTransitionTimerRunning());
   EXPECT_FALSE(OverviewStarted());
   histogram_tester.ExpectBucketCount(
-      kEnterOverviewHistogramName, EnterOverviewFromHomeLauncher::kSuccess, 0);
+      kEnterOverviewHistogramName, EnterOverviewFromHomeLauncher::kOverview, 0);
 
   const int transition_threshold =
       SwipeHomeToOverviewController::kVerticalThresholdForOverviewTransition;
@@ -224,7 +233,7 @@ TEST_F(SwipeHomeToOverviewControllerTest, BasicFlow) {
   EXPECT_FALSE(home_screen_window->transform().IsIdentityOrTranslation());
   EXPECT_EQ(1.f, home_screen_window->layer()->opacity());
   histogram_tester.ExpectBucketCount(
-      kEnterOverviewHistogramName, EnterOverviewFromHomeLauncher::kSuccess, 0);
+      kEnterOverviewHistogramName, EnterOverviewFromHomeLauncher::kOverview, 0);
 
   // Move above the transition threshold - verify the overview transition timer
   // has started.
@@ -239,14 +248,14 @@ TEST_F(SwipeHomeToOverviewControllerTest, BasicFlow) {
   EXPECT_TRUE(OverviewTransitionTimerRunning());
   EXPECT_FALSE(OverviewStarted());
   histogram_tester.ExpectBucketCount(
-      kEnterOverviewHistogramName, EnterOverviewFromHomeLauncher::kSuccess, 0);
+      kEnterOverviewHistogramName, EnterOverviewFromHomeLauncher::kOverview, 0);
 
   // Fire overview transition timer, and verify the overview has started.
   FireOverviewTransitionTimer();
 
   EXPECT_TRUE(OverviewStarted());
   histogram_tester.ExpectBucketCount(
-      kEnterOverviewHistogramName, EnterOverviewFromHomeLauncher::kSuccess, 1);
+      kEnterOverviewHistogramName, EnterOverviewFromHomeLauncher::kOverview, 1);
 
   // Home screen is still scaled down, and not visible.
   EXPECT_EQ(home_screen_window->transform(),
@@ -262,7 +271,7 @@ TEST_F(SwipeHomeToOverviewControllerTest, BasicFlow) {
 
   EXPECT_TRUE(OverviewStarted());
   histogram_tester.ExpectBucketCount(
-      kEnterOverviewHistogramName, EnterOverviewFromHomeLauncher::kSuccess, 1);
+      kEnterOverviewHistogramName, EnterOverviewFromHomeLauncher::kOverview, 1);
 
   // Home screen is still scaled down, and not visible.
   EXPECT_EQ(home_screen_window->transform(),
@@ -313,7 +322,108 @@ TEST_F(SwipeHomeToOverviewControllerTest, EndDragBeforeTimeout) {
   EXPECT_FALSE(OverviewStarted());
 }
 
+TEST_F(SwipeHomeToOverviewControllerTest, GoBackOnHomeLauncher) {
+  // Show home screen search results page.
+  GetAppListTestHelper()->CheckVisibility(true);
+  TapOnHomeLauncherSearchBox();
+  GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenSearch);
+
+  const gfx::RectF shelf_bounds = GetShelfBoundsInFloat();
+
+  StartDrag();
+
+  aura::Window* home_screen_window =
+      home_screen_delegate()->GetHomeScreenWindow();
+  ASSERT_TRUE(home_screen_window);
+
+  const int transition_threshold =
+      SwipeHomeToOverviewController::kVerticalThresholdForOverviewTransition;
+
+  // Move above the transition threshold - verify the overview transition timer
+  // has started.
+  Drag(shelf_bounds.top_center() - gfx::Vector2d(0, transition_threshold / 2),
+       0.f, 1.f);
+  Drag(shelf_bounds.top_center() - gfx::Vector2d(0, transition_threshold + 10),
+       0.f, 1.f);
+
+  EXPECT_EQ(home_screen_window->transform(),
+            home_screen_window->layer()->GetTargetTransform());
+  EXPECT_TRUE(home_screen_window->transform().IsScaleOrTranslation());
+  EXPECT_FALSE(home_screen_window->transform().IsIdentityOrTranslation());
+
+  EXPECT_TRUE(OverviewTransitionTimerRunning());
+  EXPECT_FALSE(OverviewStarted());
+
+  // The user ending drag with a fling should move home to the initial state -
+  // fullscreen all apps.
+  EndDrag(
+      shelf_bounds.top_center() - gfx::Vector2d(0, transition_threshold + 10),
+      -1500.f);
+
+  EXPECT_EQ(home_screen_window->transform(),
+            home_screen_window->layer()->GetTargetTransform());
+  EXPECT_EQ(gfx::Transform(), home_screen_window->transform());
+  EXPECT_EQ(1.f, home_screen_window->layer()->opacity());
+
+  EXPECT_FALSE(OverviewTransitionTimerRunning());
+  EXPECT_FALSE(OverviewStarted());
+  GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenAllApps);
+}
+
+TEST_F(SwipeHomeToOverviewControllerTest, FlingOnAppsPage) {
+  // Show home screen search results page.
+  GetAppListTestHelper()->CheckVisibility(true);
+  GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenAllApps);
+
+  const gfx::RectF shelf_bounds = GetShelfBoundsInFloat();
+
+  StartDrag();
+
+  aura::Window* home_screen_window =
+      home_screen_delegate()->GetHomeScreenWindow();
+  ASSERT_TRUE(home_screen_window);
+
+  const int transition_threshold =
+      SwipeHomeToOverviewController::kVerticalThresholdForOverviewTransition;
+
+  // Move above the transition threshold - verify the overview transition timer
+  // has started.
+  Drag(shelf_bounds.top_center() - gfx::Vector2d(0, transition_threshold / 2),
+       0.f, 1.f);
+  Drag(shelf_bounds.top_center() - gfx::Vector2d(0, transition_threshold + 10),
+       0.f, 1.f);
+
+  EXPECT_EQ(home_screen_window->transform(),
+            home_screen_window->layer()->GetTargetTransform());
+  EXPECT_TRUE(home_screen_window->transform().IsScaleOrTranslation());
+  EXPECT_FALSE(home_screen_window->transform().IsIdentityOrTranslation());
+
+  EXPECT_TRUE(OverviewTransitionTimerRunning());
+  EXPECT_FALSE(OverviewStarted());
+
+  // The user ending drag with a fling should move home to the initial state -
+  // fullscreen all apps.
+  EndDrag(
+      shelf_bounds.top_center() - gfx::Vector2d(0, transition_threshold + 10),
+      -1500.f);
+
+  EXPECT_EQ(home_screen_window->transform(),
+            home_screen_window->layer()->GetTargetTransform());
+  EXPECT_EQ(gfx::Transform(), home_screen_window->transform());
+  EXPECT_EQ(1.f, home_screen_window->layer()->opacity());
+
+  EXPECT_FALSE(OverviewTransitionTimerRunning());
+  EXPECT_FALSE(OverviewStarted());
+
+  GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenAllApps);
+}
+
 TEST_F(SwipeHomeToOverviewControllerTest, CancelDragBeforeTimeout) {
+  // Show home screen search results page.
+  GetAppListTestHelper()->CheckVisibility(true);
+  TapOnHomeLauncherSearchBox();
+  GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenSearch);
+
   const gfx::RectF shelf_bounds = GetShelfBoundsInFloat();
 
   StartDrag();
@@ -350,6 +460,10 @@ TEST_F(SwipeHomeToOverviewControllerTest, CancelDragBeforeTimeout) {
 
   EXPECT_FALSE(OverviewTransitionTimerRunning());
   EXPECT_FALSE(OverviewStarted());
+
+  // The gesture was not a fling - the home screen should have stayed in the
+  // fullscreen search state.
+  GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenSearch);
 }
 
 TEST_F(SwipeHomeToOverviewControllerTest, DragMovementRestartsTimeout) {
diff --git a/ash/shelf/shelf_metrics.h b/ash/shelf/shelf_metrics.h
index b253abc1a9428..e5de1be90be9a 100644
--- a/ash/shelf/shelf_metrics.h
+++ b/ash/shelf/shelf_metrics.h
@@ -50,10 +50,13 @@ enum class EnterOverviewFromHomeLauncher {
   kCanceled = 0,
 
   // Succeed to enter overview mode from home launcher.
-  kSuccess = 1,
+  kOverview = 1,
+
+  // The gesture was detected as a swipe to the home screen initial state.
+  kBack = 2,
 
   // New items should be added before to keep this one always the last.
-  kMaxState = 2,
+  kMaxState = 3,
 
   kMaxValue = kMaxState
 };
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 88cbc23081b2f..a5c76a18171e9 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -65128,6 +65128,7 @@ would be helpful to identify which type is being sent.
 <enum name="SwipeHomeToOverviewResult">
   <int value="0" label="Remained on the home screen"/>
   <int value="1" label="Transitioned to overview"/>
+  <int value="2" label="Went back on the home screen"/>
 </enum>
 
 <enum name="SwReporterRunningTimeRegistryError">