Add ability to gather metrics to BubbleManager.
[chromium-blink-merge.git] / chrome / browser / ui / exclusive_access / mouse_lock_controller.cc
blobf6adfac00fb2e7cbcf7041974ed2571c985034e8
1 // Copyright (c) 2015 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/exclusive_access/mouse_lock_controller.h"
7 #include "chrome/browser/chrome_notification_types.h"
8 #include "chrome/browser/profiles/profile.h"
9 #include "chrome/browser/ui/browser.h"
10 #include "chrome/browser/ui/exclusive_access/exclusive_access_context.h"
11 #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
12 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
13 #include "components/content_settings/core/browser/host_content_settings_map.h"
14 #include "content/public/browser/notification_service.h"
15 #include "content/public/browser/render_view_host.h"
16 #include "content/public/browser/render_widget_host_view.h"
17 #include "content/public/browser/web_contents.h"
19 using content::RenderViewHost;
20 using content::WebContents;
22 MouseLockController::MouseLockController(ExclusiveAccessManager* manager)
23 : ExclusiveAccessControllerBase(manager),
24 mouse_lock_state_(MOUSELOCK_NOT_REQUESTED) {
27 MouseLockController::~MouseLockController() {
30 bool MouseLockController::IsMouseLocked() const {
31 return mouse_lock_state_ == MOUSELOCK_ACCEPTED ||
32 mouse_lock_state_ == MOUSELOCK_ACCEPTED_SILENTLY;
35 bool MouseLockController::IsMouseLockSilentlyAccepted() const {
36 return mouse_lock_state_ == MOUSELOCK_ACCEPTED_SILENTLY;
39 void MouseLockController::RequestToLockMouse(WebContents* web_contents,
40 bool user_gesture,
41 bool last_unlocked_by_target) {
42 DCHECK(!IsMouseLocked());
43 NotifyMouseLockChange();
45 // Must have a user gesture to prevent misbehaving sites from constantly
46 // re-locking the mouse. Exceptions are when the page has unlocked
47 // (i.e. not the user), or if we're in tab fullscreen (user gesture required
48 // for that)
49 if (!last_unlocked_by_target && !user_gesture &&
50 !exclusive_access_manager()
51 ->fullscreen_controller()
52 ->IsFullscreenForTabOrPending(web_contents)) {
53 web_contents->GotResponseToLockMouseRequest(false);
54 return;
56 SetTabWithExclusiveAccess(web_contents);
57 ExclusiveAccessBubbleType bubble_type =
58 exclusive_access_manager()->GetExclusiveAccessExitBubbleType();
60 switch (GetMouseLockSetting(web_contents->GetURL())) {
61 case CONTENT_SETTING_ALLOW:
62 // If bubble already displaying buttons we must not lock the mouse yet,
63 // or it would prevent pressing those buttons. Instead, merge the request.
64 if (!exclusive_access_manager()
65 ->fullscreen_controller()
66 ->IsPrivilegedFullscreenForTab() &&
67 exclusive_access_bubble::ShowButtonsForType(bubble_type)) {
68 mouse_lock_state_ = MOUSELOCK_REQUESTED;
69 } else {
70 // Lock mouse.
71 if (web_contents->GotResponseToLockMouseRequest(true)) {
72 if (last_unlocked_by_target) {
73 mouse_lock_state_ = MOUSELOCK_ACCEPTED_SILENTLY;
74 } else {
75 mouse_lock_state_ = MOUSELOCK_ACCEPTED;
77 } else {
78 SetTabWithExclusiveAccess(nullptr);
79 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
82 break;
83 case CONTENT_SETTING_BLOCK:
84 web_contents->GotResponseToLockMouseRequest(false);
85 SetTabWithExclusiveAccess(nullptr);
86 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
87 break;
88 case CONTENT_SETTING_ASK:
89 mouse_lock_state_ = MOUSELOCK_REQUESTED;
90 break;
91 default:
92 NOTREACHED();
94 exclusive_access_manager()->UpdateExclusiveAccessExitBubbleContent();
97 void MouseLockController::ExitExclusiveAccessIfNecessary() {
98 NotifyTabExclusiveAccessLost();
101 void MouseLockController::NotifyTabExclusiveAccessLost() {
102 WebContents* tab = exclusive_access_tab();
103 if (tab) {
104 if (IsMouseLockRequested()) {
105 tab->GotResponseToLockMouseRequest(false);
106 NotifyMouseLockChange();
107 } else {
108 UnlockMouse();
110 SetTabWithExclusiveAccess(nullptr);
111 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
112 exclusive_access_manager()->UpdateExclusiveAccessExitBubbleContent();
116 bool MouseLockController::HandleUserPressedEscape() {
117 if (IsMouseLocked() || IsMouseLockRequested()) {
118 ExitExclusiveAccessIfNecessary();
119 return true;
122 return false;
125 void MouseLockController::ExitExclusiveAccessToPreviousState() {
126 // Nothing to do for mouse lock.
129 bool MouseLockController::OnAcceptExclusiveAccessPermission() {
130 ExclusiveAccessBubbleType bubble_type =
131 exclusive_access_manager()->GetExclusiveAccessExitBubbleType();
132 bool mouse_lock = false;
133 exclusive_access_bubble::PermissionRequestedByType(bubble_type, nullptr,
134 &mouse_lock);
135 DCHECK(!(mouse_lock && IsMouseLocked()));
137 if (mouse_lock && !IsMouseLocked()) {
138 DCHECK(IsMouseLockRequested());
140 HostContentSettingsMap* settings_map = exclusive_access_manager()
141 ->context()
142 ->GetProfile()
143 ->GetHostContentSettingsMap();
145 GURL url = GetExclusiveAccessBubbleURL();
146 ContentSettingsPattern pattern = ContentSettingsPattern::FromURL(url);
148 // TODO(markusheintz): We should allow patterns for all possible URLs here.
150 // Do not store preference on file:// URLs, they don't have a clean
151 // origin policy.
152 // TODO(estark): Revisit this when crbug.com/455882 is fixed.
153 if (!url.SchemeIsFile() && pattern.IsValid()) {
154 settings_map->SetContentSetting(pattern,
155 ContentSettingsPattern::Wildcard(),
156 CONTENT_SETTINGS_TYPE_MOUSELOCK,
157 std::string(), CONTENT_SETTING_ALLOW);
160 WebContents* tab = exclusive_access_tab();
161 if (tab && tab->GotResponseToLockMouseRequest(true)) {
162 mouse_lock_state_ = MOUSELOCK_ACCEPTED;
163 } else {
164 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
165 SetTabWithExclusiveAccess(nullptr);
167 NotifyMouseLockChange();
168 return true;
171 return false;
174 bool MouseLockController::OnDenyExclusiveAccessPermission() {
175 WebContents* tab = exclusive_access_tab();
177 if (tab && IsMouseLockRequested()) {
178 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
179 tab->GotResponseToLockMouseRequest(false);
180 SetTabWithExclusiveAccess(nullptr);
181 NotifyMouseLockChange();
182 return true;
185 return false;
188 void MouseLockController::LostMouseLock() {
189 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
190 SetTabWithExclusiveAccess(nullptr);
191 NotifyMouseLockChange();
192 exclusive_access_manager()->UpdateExclusiveAccessExitBubbleContent();
195 bool MouseLockController::IsMouseLockRequested() const {
196 return mouse_lock_state_ == MOUSELOCK_REQUESTED;
199 void MouseLockController::NotifyMouseLockChange() {
200 content::NotificationService::current()->Notify(
201 chrome::NOTIFICATION_MOUSE_LOCK_CHANGED,
202 content::Source<MouseLockController>(this),
203 content::NotificationService::NoDetails());
206 void MouseLockController::UnlockMouse() {
207 WebContents* tab = exclusive_access_tab();
209 if (!tab)
210 return;
212 content::RenderWidgetHostView* mouse_lock_view = nullptr;
213 FullscreenController* fullscreen_controller =
214 exclusive_access_manager()->fullscreen_controller();
215 if ((fullscreen_controller->exclusive_access_tab() == tab) &&
216 fullscreen_controller->IsPrivilegedFullscreenForTab()) {
217 mouse_lock_view =
218 exclusive_access_tab()->GetFullscreenRenderWidgetHostView();
221 if (!mouse_lock_view) {
222 RenderViewHost* const rvh = exclusive_access_tab()->GetRenderViewHost();
223 if (rvh)
224 mouse_lock_view = rvh->GetView();
227 if (mouse_lock_view)
228 mouse_lock_view->UnlockMouse();
231 ContentSetting MouseLockController::GetMouseLockSetting(const GURL& url) const {
232 // If simplified UI is enabled, never ask the user, just auto-allow. (Always
233 // return CONTENT_SETTING_ALLOW in favour of CONTENT_SETTING_ASK.)
234 bool simplified_ui =
235 ExclusiveAccessManager::IsSimplifiedFullscreenUIEnabled();
237 // Always ask on file:// URLs, since we can't meaningfully make the
238 // decision stick for a particular origin.
239 // TODO(estark): Revisit this when crbug.com/455882 is fixed.
240 if (url.SchemeIsFile() && !simplified_ui)
241 return CONTENT_SETTING_ASK;
243 if (exclusive_access_manager()
244 ->fullscreen_controller()
245 ->IsPrivilegedFullscreenForTab())
246 return CONTENT_SETTING_ALLOW;
248 HostContentSettingsMap* settings_map = exclusive_access_manager()
249 ->context()
250 ->GetProfile()
251 ->GetHostContentSettingsMap();
252 ContentSetting setting = settings_map->GetContentSetting(
253 url, url, CONTENT_SETTINGS_TYPE_MOUSELOCK, std::string());
255 if (simplified_ui && setting == CONTENT_SETTING_ASK)
256 return CONTENT_SETTING_ALLOW;
258 return setting;