1 // Copyright 2018 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 "content/browser/idle/idle_manager_impl.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "content/public/browser/browser_context.h"
12 #include "content/public/browser/idle_manager.h"
13 #include "content/public/browser/permission_controller.h"
14 #include "content/public/browser/permission_type.h"
15 #include "ui/base/idle/idle.h"
16 #include "url/gurl.h"
17 #include "url/origin.h"
18
19 namespace content {
20
21 namespace {
22
23 using blink::mojom::IdleManagerError;
24 using blink::mojom::IdleState;
25 using blink::mojom::PermissionStatus;
26
27 constexpr base::TimeDelta kPollInterval = base::TimeDelta::FromSeconds(1);
28
29 constexpr base::TimeDelta kMinimumThreshold = base::TimeDelta::FromSeconds(60);
30
31 // Default provider implementation. Everything is delegated to
32 // ui::CalculateIdleTime and ui::CheckIdleStateIsLocked.
33 class DefaultIdleProvider : public IdleManager::IdleTimeProvider {
34 public:
35 DefaultIdleProvider() = default;
36 ~DefaultIdleProvider() override = default;
37
CalculateIdleTime()38 base::TimeDelta CalculateIdleTime() override {
39 return base::TimeDelta::FromSeconds(ui::CalculateIdleTime());
40 }
41
CheckIdleStateIsLocked()42 bool CheckIdleStateIsLocked() override {
43 return ui::CheckIdleStateIsLocked();
44 }
45 };
46
IdleTimeToIdleState(bool locked,base::TimeDelta idle_time,base::TimeDelta idle_threshold)47 blink::mojom::IdleStatePtr IdleTimeToIdleState(bool locked,
48 base::TimeDelta idle_time,
49 base::TimeDelta idle_threshold) {
50 blink::mojom::UserIdleState user;
51 if (idle_time >= idle_threshold)
52 user = blink::mojom::UserIdleState::kIdle;
53 else
54 user = blink::mojom::UserIdleState::kActive;
55
56 blink::mojom::ScreenIdleState screen;
57 if (locked)
58 screen = blink::mojom::ScreenIdleState::kLocked;
59 else
60 screen = blink::mojom::ScreenIdleState::kUnlocked;
61
62 return IdleState::New(user, screen);
63 }
64
65 } // namespace
66
IdleManagerImpl(BrowserContext * browser_context)67 IdleManagerImpl::IdleManagerImpl(BrowserContext* browser_context)
68 : idle_time_provider_(new DefaultIdleProvider()),
69 browser_context_(browser_context) {}
70
~IdleManagerImpl()71 IdleManagerImpl::~IdleManagerImpl() {
72 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
73
74 while (!monitors_.empty()) {
75 IdleMonitor* monitor = monitors_.head()->value();
76 monitor->RemoveFromList();
77 delete monitor;
78 }
79 }
80
CreateService(mojo::PendingReceiver<blink::mojom::IdleManager> receiver,const url::Origin & origin)81 void IdleManagerImpl::CreateService(
82 mojo::PendingReceiver<blink::mojom::IdleManager> receiver,
83 const url::Origin& origin) {
84 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
85
86 receivers_.Add(this, std::move(receiver), origin);
87 }
88
SetIdleOverride(blink::mojom::UserIdleState user_state,blink::mojom::ScreenIdleState screen_state)89 void IdleManagerImpl::SetIdleOverride(
90 blink::mojom::UserIdleState user_state,
91 blink::mojom::ScreenIdleState screen_state) {
92 state_override_ = IdleState::New(user_state, screen_state);
93 UpdateIdleState();
94 }
95
ClearIdleOverride()96 void IdleManagerImpl::ClearIdleOverride() {
97 state_override_ = nullptr;
98 UpdateIdleState();
99 }
100
AddMonitor(base::TimeDelta threshold,mojo::PendingRemote<blink::mojom::IdleMonitor> monitor_remote,AddMonitorCallback callback)101 void IdleManagerImpl::AddMonitor(
102 base::TimeDelta threshold,
103 mojo::PendingRemote<blink::mojom::IdleMonitor> monitor_remote,
104 AddMonitorCallback callback) {
105 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
106 if (threshold < kMinimumThreshold) {
107 receivers_.ReportBadMessage("Minimum threshold is 1 minute.");
108 return;
109 }
110
111 const url::Origin& origin = receivers_.current_context();
112 if (!HasPermission(origin)) {
113 std::move(callback).Run(IdleManagerError::kPermissionDisabled, nullptr);
114 return;
115 }
116
117 blink::mojom::IdleStatePtr current_state = CheckIdleState(threshold);
118 auto response_state = current_state->Clone();
119 auto monitor = std::make_unique<IdleMonitor>(
120 std::move(monitor_remote), std::move(current_state), threshold);
121
122 // This unretained reference is safe because IdleManagerImpl owns all
123 // IdleMonitor instances.
124 monitor->SetErrorHandler(
125 base::BindOnce(&IdleManagerImpl::RemoveMonitor, base::Unretained(this)));
126
127 monitors_.Append(monitor.release());
128
129 StartPolling();
130
131 std::move(callback).Run(IdleManagerError::kSuccess,
132 std::move(response_state));
133 }
134
HasPermission(const url::Origin & origin)135 bool IdleManagerImpl::HasPermission(const url::Origin& origin) {
136 PermissionController* permission_controller =
137 BrowserContext::GetPermissionController(browser_context_);
138 DCHECK(permission_controller);
139 PermissionStatus status = permission_controller->GetPermissionStatus(
140 PermissionType::IDLE_DETECTION, origin.GetURL(), origin.GetURL());
141 return status == PermissionStatus::GRANTED;
142 }
143
RemoveMonitor(IdleMonitor * monitor)144 void IdleManagerImpl::RemoveMonitor(IdleMonitor* monitor) {
145 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
146
147 monitor->RemoveFromList();
148 delete monitor;
149
150 if (monitors_.empty()) {
151 StopPolling();
152 }
153 }
154
SetIdleTimeProviderForTest(std::unique_ptr<IdleTimeProvider> idle_time_provider)155 void IdleManagerImpl::SetIdleTimeProviderForTest(
156 std::unique_ptr<IdleTimeProvider> idle_time_provider) {
157 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
158 idle_time_provider_ = std::move(idle_time_provider);
159 }
160
IsPollingForTest()161 bool IdleManagerImpl::IsPollingForTest() {
162 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
163 return poll_timer_.IsRunning();
164 }
165
StartPolling()166 void IdleManagerImpl::StartPolling() {
167 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
168 if (!poll_timer_.IsRunning()) {
169 poll_timer_.Start(FROM_HERE, kPollInterval,
170 base::BindRepeating(&IdleManagerImpl::UpdateIdleState,
171 base::Unretained(this)));
172 }
173 }
174
StopPolling()175 void IdleManagerImpl::StopPolling() {
176 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
177 poll_timer_.Stop();
178 }
179
CheckIdleState(base::TimeDelta threshold)180 blink::mojom::IdleStatePtr IdleManagerImpl::CheckIdleState(
181 base::TimeDelta threshold) {
182 if (state_override_) {
183 return state_override_->Clone();
184 }
185 base::TimeDelta idle_time = idle_time_provider_->CalculateIdleTime();
186 bool locked = idle_time_provider_->CheckIdleStateIsLocked();
187
188 return IdleTimeToIdleState(locked, idle_time, threshold);
189 }
190
UpdateIdleState()191 void IdleManagerImpl::UpdateIdleState() {
192 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
193
194 for (auto* node = monitors_.head(); node != monitors_.end();
195 node = node->next()) {
196 IdleMonitor* monitor = node->value();
197 monitor->SetLastState(CheckIdleState(monitor->threshold()));
198 }
199 }
200
201 } // namespace content
202