blob: 4c43776a75fd9ed75ff066392f9bbb0d4c21a364 [file] [log] [blame]
// Copyright 2017 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/chromeos/login/lock/views_screen_locker.h"
#include <memory>
#include <string>
#include <utility>
#include "ash/public/cpp/ash_features.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/i18n/time_formatting.h"
#include "base/location.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/authpolicy/authpolicy_helper.h"
#include "chrome/browser/chromeos/lock_screen_apps/state_controller.h"
#include "chrome/browser/chromeos/login/lock_screen_utils.h"
#include "chrome/browser/chromeos/login/mojo_system_info_dispatcher.h"
#include "chrome/browser/chromeos/login/quick_unlock/pin_backend.h"
#include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_factory.h"
#include "chrome/browser/chromeos/login/screens/chrome_user_selection_screen.h"
#include "chrome/browser/chromeos/login/user_board_view_mojo.h"
#include "chrome/browser/chromeos/system/system_clock.h"
#include "chrome/browser/ui/ash/session_controller_client.h"
#include "chrome/browser/ui/ash/wallpaper_controller_client.h"
#include "chrome/common/pref_names.h"
#include "chromeos/components/proximity_auth/screenlock_bridge.h"
#include "chromeos/dbus/media_perception/media_perception.pb.h"
#include "components/user_manager/known_user.h"
#include "components/user_manager/user_manager.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "ui/base/ime/chromeos/ime_keyboard.h"
namespace chromeos {
namespace {
constexpr char kLockDisplay[] = "lock";
constexpr char kExternalBinaryAuth[] = "external_binary_auth";
constexpr char kExternalBinaryEnrollment[] = "external_binary_enrollment";
constexpr char kWebCameraDeviceContext[] = "WebCamera: WebCamera";
constexpr base::TimeDelta kExternalBinaryAuthTimeout =
base::TimeDelta::FromSeconds(2);
// Starts the graph specified by |configuration| if the current graph
// is SUSPENDED or if the current configuration is different.
void StartGraphIfNeeded(chromeos::MediaAnalyticsClient* client,
const std::string& configuration,
base::Optional<mri::State> maybe_state) {
if (!maybe_state)
return;
if (maybe_state->status() == mri::State::SUSPENDED) {
// Start the specified graph
mri::State new_state;
new_state.set_status(mri::State::RUNNING);
new_state.set_device_context(kWebCameraDeviceContext);
new_state.set_configuration(configuration);
client->SetState(new_state, base::DoNothing());
} else if (maybe_state->configuration() != configuration) {
// Suspend and restart with new graph
mri::State suspend_state;
suspend_state.set_status(mri::State::SUSPENDED);
suspend_state.set_configuration(configuration);
client->SetState(suspend_state, base::BindOnce(&StartGraphIfNeeded, client,
configuration));
}
}
} // namespace
ViewsScreenLocker::ViewsScreenLocker(ScreenLocker* screen_locker)
: screen_locker_(screen_locker),
system_info_updater_(std::make_unique<MojoSystemInfoDispatcher>()),
media_analytics_client_(chromeos::MediaAnalyticsClient::Get()) {
LoginScreenClient::Get()->SetDelegate(this);
user_board_view_mojo_ = std::make_unique<UserBoardViewMojo>();
user_selection_screen_ =
std::make_unique<ChromeUserSelectionScreen>(kLockDisplay);
user_selection_screen_->SetView(user_board_view_mojo_.get());
allowed_input_methods_subscription_ =
CrosSettings::Get()->AddSettingsObserver(
kDeviceLoginScreenInputMethods,
base::Bind(&ViewsScreenLocker::OnAllowedInputMethodsChanged,
base::Unretained(this)));
if (base::FeatureList::IsEnabled(ash::features::kUnlockWithExternalBinary))
scoped_observer_.Add(media_analytics_client_);
}
ViewsScreenLocker::~ViewsScreenLocker() {
lock_screen_apps::StateController::Get()->SetFocusCyclerDelegate(nullptr);
LoginScreenClient::Get()->SetDelegate(nullptr);
}
void ViewsScreenLocker::Init() {
lock_time_ = base::TimeTicks::Now();
user_selection_screen_->Init(screen_locker_->users());
LoginScreenClient::Get()->login_screen()->SetUserList(
user_selection_screen_->UpdateAndReturnUserListForMojo());
LoginScreenClient::Get()->login_screen()->SetAllowLoginAsGuest(
false /*show_guest*/);
if (!ime_state_.get())
ime_state_ = input_method::InputMethodManager::Get()->GetActiveIMEState();
// Reset Caps Lock state when lock screen is shown.
input_method::InputMethodManager::Get()->GetImeKeyboard()->SetCapsLockEnabled(
false);
// Enable pin for any users who can use it.
if (user_manager::UserManager::IsInitialized()) {
for (user_manager::User* user :
user_manager::UserManager::Get()->GetLoggedInUsers()) {
UpdatePinKeyboardState(user->GetAccountId());
}
}
system_info_updater_->StartRequest();
}
void ViewsScreenLocker::OnLockScreenReady() {
lock_screen_ready_ = true;
user_selection_screen_->InitEasyUnlock();
UMA_HISTOGRAM_TIMES("LockScreen.LockReady",
base::TimeTicks::Now() - lock_time_);
screen_locker_->ScreenLockReady();
lock_screen_apps::StateController::Get()->SetFocusCyclerDelegate(this);
OnAllowedInputMethodsChanged();
}
void ViewsScreenLocker::ShowErrorMessage(
int error_msg_id,
HelpAppLauncher::HelpTopic help_topic_id) {
// TODO(xiaoyinh): Complete the implementation here.
LoginScreenClient::Get()->login_screen()->ShowErrorMessage(
0 /* login_attempts */, std::string(), std::string(),
static_cast<int>(help_topic_id));
}
void ViewsScreenLocker::ClearErrors() {
LoginScreenClient::Get()->login_screen()->ClearErrors();
}
void ViewsScreenLocker::OnAshLockAnimationFinished() {
SessionControllerClient::Get()->NotifyChromeLockAnimationsComplete();
}
void ViewsScreenLocker::SetFingerprintState(
const AccountId& account_id,
ash::mojom::FingerprintState state) {
LoginScreenClient::Get()->login_screen()->SetFingerprintState(account_id,
state);
}
void ViewsScreenLocker::NotifyFingerprintAuthResult(const AccountId& account_id,
bool success) {
LoginScreenClient::Get()->login_screen()->NotifyFingerprintAuthResult(
account_id, success);
}
void ViewsScreenLocker::HandleAuthenticateUserWithPasswordOrPin(
const AccountId& account_id,
const std::string& password,
bool authenticated_by_pin,
AuthenticateUserWithPasswordOrPinCallback callback) {
DCHECK_EQ(account_id.GetUserEmail(),
gaia::SanitizeEmail(account_id.GetUserEmail()));
const user_manager::User* const user =
user_manager::UserManager::Get()->FindUser(account_id);
DCHECK(user);
UserContext user_context(*user);
user_context.SetKey(
Key(chromeos::Key::KEY_TYPE_PASSWORD_PLAIN, std::string(), password));
user_context.SetIsUsingPin(authenticated_by_pin);
user_context.SetSyncPasswordData(password_manager::PasswordHashData(
account_id.GetUserEmail(), base::UTF8ToUTF16(password),
false /*force_update*/));
if (account_id.GetAccountType() == AccountType::ACTIVE_DIRECTORY &&
(user_context.GetUserType() !=
user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY)) {
LOG(FATAL) << "Incorrect Active Directory user type "
<< user_context.GetUserType();
}
ScreenLocker::default_screen_locker()->Authenticate(user_context,
std::move(callback));
UpdatePinKeyboardState(account_id);
}
void ViewsScreenLocker::HandleAuthenticateUserWithExternalBinary(
const AccountId& account_id,
AuthenticateUserWithExternalBinaryCallback callback) {
authenticate_with_external_binary_callback_ = std::move(callback);
external_binary_timer_.Start(
FROM_HERE, kExternalBinaryAuthTimeout,
base::BindOnce(&ViewsScreenLocker::OnExternalBinaryAuthTimeout,
weak_factory_.GetWeakPtr()));
media_analytics_client_->GetState(base::BindOnce(
&StartGraphIfNeeded, media_analytics_client_, kExternalBinaryAuth));
}
void ViewsScreenLocker::HandleEnrollUserWithExternalBinary(
EnrollUserWithExternalBinaryCallback callback) {
enroll_user_with_external_binary_callback_ = std::move(callback);
external_binary_timer_.Start(
FROM_HERE, kExternalBinaryAuthTimeout,
base::BindOnce(&ViewsScreenLocker::OnExternalBinaryEnrollmentTimeout,
weak_factory_.GetWeakPtr()));
media_analytics_client_->GetState(base::BindOnce(
&StartGraphIfNeeded, media_analytics_client_, kExternalBinaryEnrollment));
}
void ViewsScreenLocker::HandleAuthenticateUserWithEasyUnlock(
const AccountId& account_id) {
user_selection_screen_->AttemptEasyUnlock(account_id);
}
void ViewsScreenLocker::HandleHardlockPod(const AccountId& account_id) {
user_selection_screen_->HardLockPod(account_id);
}
void ViewsScreenLocker::HandleOnFocusPod(const AccountId& account_id) {
proximity_auth::ScreenlockBridge::Get()->SetFocusedUser(account_id);
if (user_selection_screen_)
user_selection_screen_->CheckUserStatus(account_id);
focused_pod_account_id_ = base::Optional<AccountId>(account_id);
const user_manager::User* user =
user_manager::UserManager::Get()->FindUser(account_id);
// |user| may be null in kiosk mode or unit tests.
if (user && user->is_logged_in() && !user->is_active()) {
SessionControllerClient::DoSwitchActiveUser(account_id);
} else {
lock_screen_utils::SetUserInputMethod(account_id.GetUserEmail(),
ime_state_.get());
lock_screen_utils::SetKeyboardSettings(account_id);
WallpaperControllerClient::Get()->ShowUserWallpaper(account_id);
bool use_24hour_clock = false;
if (user_manager::known_user::GetBooleanPref(
account_id, prefs::kUse24HourClock, &use_24hour_clock)) {
g_browser_process->platform_part()
->GetSystemClock()
->SetLastFocusedPodHourClockType(
use_24hour_clock ? base::k24HourClock : base::k12HourClock);
}
}
}
void ViewsScreenLocker::HandleOnNoPodFocused() {
focused_pod_account_id_.reset();
lock_screen_utils::EnforcePolicyInputMethods(std::string());
}
bool ViewsScreenLocker::HandleFocusLockScreenApps(bool reverse) {
if (lock_screen_app_focus_handler_.is_null())
return false;
lock_screen_app_focus_handler_.Run(reverse);
return true;
}
void ViewsScreenLocker::HandleFocusOobeDialog() {
NOTREACHED();
}
void ViewsScreenLocker::HandleLaunchPublicSession(
const AccountId& account_id,
const std::string& locale,
const std::string& input_method) {
NOTREACHED();
}
void ViewsScreenLocker::SuspendDone(const base::TimeDelta& sleep_duration) {
for (user_manager::User* user :
user_manager::UserManager::Get()->GetUnlockUsers()) {
UpdatePinKeyboardState(user->GetAccountId());
}
}
void ViewsScreenLocker::RegisterLockScreenAppFocusHandler(
const LockScreenAppFocusCallback& focus_handler) {
lock_screen_app_focus_handler_ = focus_handler;
}
void ViewsScreenLocker::UnregisterLockScreenAppFocusHandler() {
lock_screen_app_focus_handler_.Reset();
}
void ViewsScreenLocker::HandleLockScreenAppFocusOut(bool reverse) {
LoginScreenClient::Get()->login_screen()->HandleFocusLeavingLockScreenApps(
reverse);
}
void ViewsScreenLocker::OnDetectionSignal(
const mri::MediaPerception& media_perception) {
if (authenticate_with_external_binary_callback_) {
const mri::FramePerception& frame = media_perception.frame_perception(0);
if (frame.frame_id() != 1)
return;
mri::State new_state;
new_state.set_status(mri::State::SUSPENDED);
media_analytics_client_->SetState(new_state, base::DoNothing());
external_binary_timer_.Stop();
std::move(authenticate_with_external_binary_callback_)
.Run(true /*auth_success*/);
ScreenLocker::Hide();
} else if (enroll_user_with_external_binary_callback_) {
const mri::FramePerception& frame = media_perception.frame_perception(0);
external_binary_timer_.Stop();
mri::State new_state;
new_state.set_status(mri::State::SUSPENDED);
media_analytics_client_->SetState(new_state, base::DoNothing());
std::move(enroll_user_with_external_binary_callback_)
.Run(frame.frame_id() == 1 /*enrollment_success*/);
}
}
void ViewsScreenLocker::UpdatePinKeyboardState(const AccountId& account_id) {
quick_unlock::PinBackend::GetInstance()->CanAuthenticate(
account_id, base::BindOnce(&ViewsScreenLocker::OnPinCanAuthenticate,
weak_factory_.GetWeakPtr(), account_id));
}
void ViewsScreenLocker::OnAllowedInputMethodsChanged() {
if (!lock_screen_ready_)
return;
if (focused_pod_account_id_) {
std::string user_input_method = lock_screen_utils::GetUserLastInputMethod(
focused_pod_account_id_->GetUserEmail());
lock_screen_utils::EnforcePolicyInputMethods(user_input_method);
} else {
lock_screen_utils::EnforcePolicyInputMethods(std::string());
}
}
void ViewsScreenLocker::OnPinCanAuthenticate(const AccountId& account_id,
bool can_authenticate) {
LoginScreenClient::Get()->login_screen()->SetPinEnabledForUser(
account_id, can_authenticate);
}
void ViewsScreenLocker::OnExternalBinaryAuthTimeout() {
std::move(authenticate_with_external_binary_callback_)
.Run(false /*auth_success*/);
mri::State new_state;
new_state.set_status(mri::State::SUSPENDED);
media_analytics_client_->SetState(new_state, base::DoNothing());
}
void ViewsScreenLocker::OnExternalBinaryEnrollmentTimeout() {
std::move(enroll_user_with_external_binary_callback_)
.Run(false /*auth_success*/);
mri::State new_state;
new_state.set_status(mri::State::SUSPENDED);
media_analytics_client_->SetState(new_state, base::DoNothing());
}
} // namespace chromeos