1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/ui/ash/back_gesture_contextual_nudge_delegate.h"
6 
7 #include "ash/public/cpp/back_gesture_contextual_nudge_controller.h"
8 #include "chrome/browser/ui/browser.h"
9 #include "chrome/browser/ui/tabs/tab_strip_model.h"
10 #include "chrome/browser/ui/views/frame/browser_view.h"
11 #include "content/public/browser/navigation_details.h"
12 #include "content/public/browser/navigation_handle.h"
13 #include "ui/aura/window.h"
14 
BackGestureContextualNudgeDelegate(ash::BackGestureContextualNudgeController * controller)15 BackGestureContextualNudgeDelegate::BackGestureContextualNudgeDelegate(
16     ash::BackGestureContextualNudgeController* controller)
17     : controller_(controller) {}
18 
~BackGestureContextualNudgeDelegate()19 BackGestureContextualNudgeDelegate::~BackGestureContextualNudgeDelegate() {
20   StopTrackingNavigation();
21 }
22 
MaybeStartTrackingNavigation(aura::Window * window)23 void BackGestureContextualNudgeDelegate::MaybeStartTrackingNavigation(
24     aura::Window* window) {
25   if (window == window_)
26     return;
27 
28   // Stop tracking the previous window before tracking a new window.
29   StopTrackingNavigation();
30 
31   BrowserView* browser_view =
32       BrowserView::GetBrowserViewForNativeWindow(window);
33   if (!browser_view)
34     return;
35 
36   window_ = window;
37   window_->AddObserver(this);
38 
39   TabStripModel* tab_strip_model = browser_view->browser()->tab_strip_model();
40   tab_strip_model->AddObserver(this);
41 
42   content::WebContents* contents = tab_strip_model->GetActiveWebContents();
43   Observe(contents);
44 }
45 
DidFinishNavigation(content::NavigationHandle * navigation_handle)46 void BackGestureContextualNudgeDelegate::DidFinishNavigation(
47     content::NavigationHandle* navigation_handle) {
48   DCHECK(window_);
49   // Make sure for one valid navigation, we only fire one status change
50   // notification.
51   if (navigation_handle->HasCommitted() &&
52       (navigation_handle->IsInMainFrame() ||
53        navigation_handle->HasSubframeNavigationEntryCommitted()) &&
54       (navigation_handle->GetURL() != navigation_handle->GetPreviousURL())) {
55     controller_->NavigationEntryChanged(window_);
56   }
57 }
58 
OnTabStripModelChanged(TabStripModel * tab_strip_model,const TabStripModelChange & change,const TabStripSelectionChange & selection)59 void BackGestureContextualNudgeDelegate::OnTabStripModelChanged(
60     TabStripModel* tab_strip_model,
61     const TabStripModelChange& change,
62     const TabStripSelectionChange& selection) {
63   const bool active_tab_changed = selection.active_tab_changed();
64   if (active_tab_changed) {
65     DCHECK(window_);
66     controller_->NavigationEntryChanged(window_);
67     content::WebContents* contents = tab_strip_model->GetActiveWebContents();
68     Observe(contents);
69   }
70 }
71 
OnWindowDestroying(aura::Window * window)72 void BackGestureContextualNudgeDelegate::OnWindowDestroying(
73     aura::Window* window) {
74   DCHECK_EQ(window_, window);
75   StopTrackingNavigation();
76 }
77 
StopTrackingNavigation()78 void BackGestureContextualNudgeDelegate::StopTrackingNavigation() {
79   if (window_) {
80     BrowserView* browser_view =
81         BrowserView::GetBrowserViewForNativeWindow(window_);
82     DCHECK(browser_view);
83     browser_view->browser()->tab_strip_model()->RemoveObserver(this);
84 
85     window_->RemoveObserver(this);
86     window_ = nullptr;
87   }
88   Observe(nullptr);
89 }
90