Add a minor text member to ui::MenuModel.
[chromium-blink-merge.git] / chrome / browser / ui / active_tab_tracker.cc
blob5a519841b7cbb34c5a37ccd3571455e26bbfbe9e
1 // Copyright (c) 2013 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.
5 #include "chrome/browser/ui/active_tab_tracker.h"
7 #include "chrome/browser/history/history_service.h"
8 #include "chrome/browser/history/history_service_factory.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/browser/ui/browser.h"
11 #include "chrome/browser/ui/browser_list.h"
12 #include "chrome/browser/ui/tabs/tab_strip_model.h"
13 #include "content/public/browser/navigation_entry.h"
14 #include "content/public/browser/notification_source.h"
15 #include "content/public/browser/notification_types.h"
16 #include "content/public/browser/web_contents.h"
18 namespace {
20 // Amount of time a page has to be active before we commit it.
21 const int kTimeBeforeCommitMS = 1000;
23 // Number of seconds input should be received before considered idle.
24 const int kIdleTimeSeconds = 30;
26 } // namespace
28 #if !defined(OS_WIN) && !defined(USE_AURA)
29 // static
30 NativeFocusTracker* NativeFocusTracker::Create(NativeFocusTrackerHost* host) {
31 return NULL;
33 #endif
35 ActiveTabTracker::ActiveTabTracker()
36 : browser_(NULL),
37 web_contents_(NULL),
38 idle_state_(IDLE_STATE_UNKNOWN),
39 timer_(false, false),
40 weak_ptr_factory_(this) {
41 native_focus_tracker_.reset(NativeFocusTracker::Create(this));
42 Browser* browser =
43 BrowserList::GetInstance(chrome::GetActiveDesktop())->GetLastActive();
44 SetBrowser(browser);
45 BrowserList::AddObserver(this);
48 ActiveTabTracker::~ActiveTabTracker() {
49 native_focus_tracker_.reset();
50 SetBrowser(NULL);
51 BrowserList::RemoveObserver(this);
54 void ActiveTabTracker::ActiveTabChanged(content::WebContents* old_contents,
55 content::WebContents* new_contents,
56 int index,
57 int reason) {
58 SetWebContents(new_contents);
61 void ActiveTabTracker::TabReplacedAt(TabStripModel* tab_strip_model,
62 content::WebContents* old_contents,
63 content::WebContents* new_contents,
64 int index) {
65 if (index == tab_strip_model->selection_model().active())
66 SetWebContents(new_contents);
69 void ActiveTabTracker::TabStripEmpty() {
70 SetBrowser(NULL);
73 void ActiveTabTracker::OnBrowserRemoved(Browser* browser) {
74 if (browser == browser_)
75 SetBrowser(NULL);
78 void ActiveTabTracker::Observe(int type,
79 const content::NotificationSource& source,
80 const content::NotificationDetails& details) {
81 const GURL url = GetURLFromWebContents();
82 if (url == url_)
83 return;
85 CommitActiveTime();
86 url_ = url;
89 void ActiveTabTracker::SetBrowser(Browser* browser) {
90 if (browser_ == browser)
91 return;
93 CommitActiveTime();
94 if (browser_)
95 browser_->tab_strip_model()->RemoveObserver(this);
96 // Don't track anything for otr profiles.
97 if (browser && browser->profile()->IsOffTheRecord())
98 browser = NULL;
99 browser_ = browser;
100 content::WebContents* web_contents = NULL;
101 if (browser_) {
102 TabStripModel* tab_strip = browser_->tab_strip_model();
103 tab_strip->AddObserver(this);
104 web_contents = tab_strip->GetActiveWebContents();
105 } else {
106 idle_state_ = IDLE_STATE_UNKNOWN;
107 timer_.Stop();
108 weak_ptr_factory_.InvalidateWeakPtrs();
110 SetWebContents(web_contents);
113 void ActiveTabTracker::SetWebContents(content::WebContents* web_contents) {
114 if (web_contents_ == web_contents)
115 return;
117 CommitActiveTime();
119 active_time_ = base::TimeTicks::Now();
120 web_contents_ = web_contents;
121 url_ = GetURLFromWebContents();
122 registrar_.RemoveAll();
123 // TODO(sky): this isn't quite right. We should really not include transient
124 // entries here. For that we need to make Browser::NavigationStateChanged()
125 // call through to this class.
126 if (web_contents_) {
127 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
128 content::Source<content::NavigationController>(
129 &web_contents_->GetController()));
130 QueryIdleState();
134 void ActiveTabTracker::SetIdleState(IdleState idle_state) {
135 if (idle_state_ != idle_state) {
136 if (idle_state_ == IDLE_STATE_ACTIVE)
137 CommitActiveTime();
138 else if (idle_state == IDLE_STATE_ACTIVE)
139 active_time_ = base::TimeTicks::Now();
140 idle_state_ = idle_state;
142 if (browser_) {
143 timer_.Start(FROM_HERE,
144 base::TimeDelta::FromSeconds(kIdleTimeSeconds),
145 base::Bind(&ActiveTabTracker::QueryIdleState,
146 base::Unretained(this)));
150 void ActiveTabTracker::QueryIdleState() {
151 if (weak_ptr_factory_.HasWeakPtrs())
152 return;
154 CalculateIdleState(kIdleTimeSeconds,
155 base::Bind(&ActiveTabTracker::SetIdleState,
156 weak_ptr_factory_.GetWeakPtr()));
159 GURL ActiveTabTracker::GetURLFromWebContents() const {
160 if (!web_contents_)
161 return GURL();
163 // TODO: handle subframe transitions better. Maybe go back to first entry
164 // that isn't a main frame?
165 content::NavigationEntry* entry =
166 web_contents_->GetController().GetLastCommittedEntry();
167 if (!entry || !PageTransitionIsMainFrame(entry->GetTransitionType()))
168 return GURL();
169 return !entry->GetUserTypedURL().is_empty() ?
170 entry->GetUserTypedURL() : entry->GetURL();
173 void ActiveTabTracker::CommitActiveTime() {
174 const base::TimeDelta active_delta = base::TimeTicks::Now() - active_time_;
175 active_time_ = base::TimeTicks::Now();
177 if (!web_contents_ || url_.is_empty() || idle_state_ != IDLE_STATE_ACTIVE ||
178 active_delta.InMilliseconds() < kTimeBeforeCommitMS)
179 return;
181 Profile* profile = Profile::FromBrowserContext(
182 web_contents_->GetBrowserContext());
183 HistoryService* history = HistoryServiceFactory::GetForProfile(
184 profile, Profile::EXPLICIT_ACCESS);
185 if (history)
186 history->IncreaseSegmentDuration(url_, base::Time::Now(), active_delta);