blob: 69b37b29288f77aa7725f45b954f028e47466651 [file] [log] [blame]
// Copyright (c) 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
#include "base/command_line.h"
#include "build/build_config.h"
#include "chrome/browser/app_mode/app_mode_utils.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/exclusive_access/exclusive_access_context.h"
#include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
#include "chrome/browser/ui/exclusive_access/mouse_lock_controller.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/chrome_switches.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/common/content_features.h"
#include "ui/events/keycodes/keyboard_codes.h"
using content::WebContents;
namespace {
// Time in milliseconds to hold the Esc key in order to exit full screen.
// TODO(dominickn) refactor the way timings/input handling works so this
// constant doesn't have to be in this file.
const int kHoldEscapeTimeMs = 1500;
}
ExclusiveAccessManager::ExclusiveAccessManager(
ExclusiveAccessContext* exclusive_access_context)
: exclusive_access_context_(exclusive_access_context),
fullscreen_controller_(this),
mouse_lock_controller_(this) {
}
ExclusiveAccessManager::~ExclusiveAccessManager() {
}
ExclusiveAccessBubbleType
ExclusiveAccessManager::GetExclusiveAccessExitBubbleType() const {
// In kiosk and exclusive app mode we always want to be fullscreen and do not
// want to show exit instructions for browser mode fullscreen.
bool app_mode = false;
#if !defined(OS_MACOSX) // App mode (kiosk) is not available on Mac yet.
app_mode = chrome::IsRunningInAppMode();
#endif
if (fullscreen_controller_.IsWindowFullscreenForTabOrPending()) {
if (!fullscreen_controller_.IsTabFullscreen())
return EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_EXIT_INSTRUCTION;
if (mouse_lock_controller_.IsMouseLockedSilently() ||
fullscreen_controller_.IsPrivilegedFullscreenForTab()) {
return EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE;
}
if (IsExperimentalKeyboardLockUIEnabled())
return EXCLUSIVE_ACCESS_BUBBLE_TYPE_KEYBOARD_LOCK_EXIT_INSTRUCTION;
if (mouse_lock_controller_.IsMouseLocked())
return EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_MOUSELOCK_EXIT_INSTRUCTION;
return EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_EXIT_INSTRUCTION;
}
if (mouse_lock_controller_.IsMouseLockedSilently())
return EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE;
if (mouse_lock_controller_.IsMouseLocked())
return EXCLUSIVE_ACCESS_BUBBLE_TYPE_MOUSELOCK_EXIT_INSTRUCTION;
if (fullscreen_controller_.IsExtensionFullscreenOrPending())
return EXCLUSIVE_ACCESS_BUBBLE_TYPE_EXTENSION_FULLSCREEN_EXIT_INSTRUCTION;
if (fullscreen_controller_.IsControllerInitiatedFullscreen() && !app_mode)
return EXCLUSIVE_ACCESS_BUBBLE_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION;
return EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE;
}
void ExclusiveAccessManager::UpdateExclusiveAccessExitBubbleContent(
ExclusiveAccessBubbleHideCallback bubble_first_hide_callback) {
GURL url = GetExclusiveAccessBubbleURL();
ExclusiveAccessBubbleType bubble_type = GetExclusiveAccessExitBubbleType();
exclusive_access_context_->UpdateExclusiveAccessExitBubbleContent(
url, bubble_type, std::move(bubble_first_hide_callback));
}
GURL ExclusiveAccessManager::GetExclusiveAccessBubbleURL() const {
GURL result = fullscreen_controller_.GetURLForExclusiveAccessBubble();
if (!result.is_valid())
result = mouse_lock_controller_.GetURLForExclusiveAccessBubble();
return result;
}
// static
bool ExclusiveAccessManager::IsExperimentalKeyboardLockUIEnabled() {
return base::FeatureList::IsEnabled(features::kKeyboardLockAPI) ||
base::FeatureList::IsEnabled(features::kExperimentalKeyboardLockUI);
}
// static
bool ExclusiveAccessManager::IsSimplifiedFullscreenUIEnabled() {
#if defined(OS_MACOSX)
// Always enabled on Mac (the mouse cursor tracking required to implement the
// non-simplified version is not implemented).
return true;
#else
return base::FeatureList::IsEnabled(features::kSimplifiedFullscreenUI);
#endif
}
void ExclusiveAccessManager::OnTabDeactivated(WebContents* web_contents) {
fullscreen_controller_.OnTabDeactivated(web_contents);
mouse_lock_controller_.OnTabDeactivated(web_contents);
}
void ExclusiveAccessManager::OnTabDetachedFromView(WebContents* web_contents) {
fullscreen_controller_.OnTabDetachedFromView(web_contents);
mouse_lock_controller_.OnTabDetachedFromView(web_contents);
}
void ExclusiveAccessManager::OnTabClosing(WebContents* web_contents) {
fullscreen_controller_.OnTabClosing(web_contents);
mouse_lock_controller_.OnTabClosing(web_contents);
}
bool ExclusiveAccessManager::HandleUserKeyPress(
const content::NativeWebKeyboardEvent& event) {
if (event.windows_key_code != ui::VKEY_ESCAPE) {
OnUserInput();
return false;
}
if (IsExperimentalKeyboardLockUIEnabled()) {
if (event.GetType() == content::NativeWebKeyboardEvent::kKeyUp &&
hold_timer_.IsRunning()) {
// Seeing a key up event on Esc with the hold timer running cancels the
// timer and doesn't exit. This means the user pressed Esc, but not long
// enough to trigger an exit
hold_timer_.Stop();
} else if (event.GetType() ==
content::NativeWebKeyboardEvent::kRawKeyDown &&
!hold_timer_.IsRunning()) {
// Seeing a key down event on Esc when the hold timer is stopped starts
// the timer. When the timer reaches 0, the callback will trigger an exit
// from fullscreen/mouselock.
hold_timer_.Start(
FROM_HERE, base::TimeDelta::FromMilliseconds(kHoldEscapeTimeMs),
base::Bind(&ExclusiveAccessManager::HandleUserHeldEscape,
base::Unretained(this)));
}
// We never handle the keyboard event.
return false;
}
bool handled = false;
handled = fullscreen_controller_.HandleUserPressedEscape();
handled |= mouse_lock_controller_.HandleUserPressedEscape();
return handled;
}
void ExclusiveAccessManager::OnUserInput() {
exclusive_access_context_->OnExclusiveAccessUserInput();
}
void ExclusiveAccessManager::ExitExclusiveAccess() {
fullscreen_controller_.ExitExclusiveAccessToPreviousState();
mouse_lock_controller_.LostMouseLock();
}
void ExclusiveAccessManager::RecordBubbleReshownUMA(
ExclusiveAccessBubbleType type) {
// Figure out whether each of fullscreen, mouselock is in effect.
bool fullscreen = false;
bool mouselock = false;
switch (type) {
case EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE:
// None in effect.
break;
case EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_EXIT_INSTRUCTION:
case EXCLUSIVE_ACCESS_BUBBLE_TYPE_KEYBOARD_LOCK_EXIT_INSTRUCTION:
case EXCLUSIVE_ACCESS_BUBBLE_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION:
case EXCLUSIVE_ACCESS_BUBBLE_TYPE_EXTENSION_FULLSCREEN_EXIT_INSTRUCTION:
// Only fullscreen in effect.
fullscreen = true;
break;
case EXCLUSIVE_ACCESS_BUBBLE_TYPE_MOUSELOCK_EXIT_INSTRUCTION:
// Only mouselock in effect.
mouselock = true;
break;
case EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_MOUSELOCK_EXIT_INSTRUCTION:
// Both in effect.
fullscreen = true;
mouselock = true;
break;
}
if (fullscreen)
fullscreen_controller_.RecordBubbleReshownUMA();
if (mouselock)
mouse_lock_controller_.RecordBubbleReshownUMA();
}
void ExclusiveAccessManager::HandleUserHeldEscape() {
fullscreen_controller_.HandleUserPressedEscape();
mouse_lock_controller_.HandleUserPressedEscape();
}