blob: b11506667b4b06bdf6f77e8bf97a3051c6cf2d7a [file] [log] [blame]
// Copyright 2014 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 "components/proximity_auth/proximity_auth_system.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/proximity_auth/logging/logging.h"
#include "components/proximity_auth/proximity_auth_client.h"
#include "components/proximity_auth/remote_device_life_cycle_impl.h"
#include "components/proximity_auth/unlock_manager.h"
namespace proximity_auth {
namespace {
// The time to wait after the device wakes up before beginning to connect to the
// remote device.
const int kWakeUpTimeoutSeconds = 2;
} // namespace
ProximityAuthSystem::ProximityAuthSystem(
ScreenlockType screenlock_type,
ProximityAuthClient* proximity_auth_client)
: proximity_auth_client_(proximity_auth_client),
unlock_manager_(
new UnlockManager(screenlock_type, proximity_auth_client)),
suspended_(false),
started_(false),
weak_ptr_factory_(this) {}
ProximityAuthSystem::~ProximityAuthSystem() {
ScreenlockBridge::Get()->RemoveObserver(this);
unlock_manager_->SetRemoteDeviceLifeCycle(nullptr);
}
void ProximityAuthSystem::Start() {
if (started_)
return;
started_ = true;
ScreenlockBridge::Get()->AddObserver(this);
const AccountId& focused_account_id =
ScreenlockBridge::Get()->focused_account_id();
if (focused_account_id.is_valid())
OnFocusedUserChanged(focused_account_id);
}
void ProximityAuthSystem::Stop() {
if (!started_)
return;
started_ = false;
ScreenlockBridge::Get()->RemoveObserver(this);
OnFocusedUserChanged(EmptyAccountId());
}
void ProximityAuthSystem::SetRemoteDevicesForUser(
const AccountId& account_id,
const cryptauth::RemoteDeviceList& remote_devices) {
remote_devices_map_[account_id] = remote_devices;
if (started_) {
const AccountId& focused_account_id =
ScreenlockBridge::Get()->focused_account_id();
if (focused_account_id.is_valid())
OnFocusedUserChanged(focused_account_id);
}
}
cryptauth::RemoteDeviceList ProximityAuthSystem::GetRemoteDevicesForUser(
const AccountId& account_id) const {
if (remote_devices_map_.find(account_id) == remote_devices_map_.end())
return cryptauth::RemoteDeviceList();
return remote_devices_map_.at(account_id);
}
void ProximityAuthSystem::OnAuthAttempted(const AccountId& /* account_id */) {
// TODO(tengs): There is no reason to pass the |account_id| argument anymore.
unlock_manager_->OnAuthAttempted(ScreenlockBridge::LockHandler::USER_CLICK);
}
void ProximityAuthSystem::OnSuspend() {
PA_LOG(INFO) << "Preparing for device suspension.";
DCHECK(!suspended_);
suspended_ = true;
unlock_manager_->SetRemoteDeviceLifeCycle(nullptr);
remote_device_life_cycle_.reset();
}
void ProximityAuthSystem::OnSuspendDone() {
PA_LOG(INFO) << "Device resumed from suspension.";
DCHECK(suspended_);
// TODO(tengs): On ChromeOS, the system's Bluetooth adapter is invalidated
// when the system suspends. However, Chrome does not receive this
// notification until a second or so after the system wakes up. That means
// using the adapter during this time will be problematic, so we wait instead.
// See crbug.com/537057.
proximity_auth_client_->UpdateScreenlockState(
ScreenlockState::BLUETOOTH_CONNECTING);
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, base::Bind(&ProximityAuthSystem::ResumeAfterWakeUpTimeout,
weak_ptr_factory_.GetWeakPtr()),
base::TimeDelta::FromSeconds(kWakeUpTimeoutSeconds));
}
void ProximityAuthSystem::ResumeAfterWakeUpTimeout() {
PA_LOG(INFO) << "Resume after suspend";
suspended_ = false;
if (!ScreenlockBridge::Get()->IsLocked()) {
PA_LOG(INFO) << "Suspend done, but no lock screen.";
} else if (!started_) {
PA_LOG(INFO) << "Suspend done, but not system started.";
} else {
OnFocusedUserChanged(ScreenlockBridge::Get()->focused_account_id());
}
}
void ProximityAuthSystem::OnLifeCycleStateChanged(
RemoteDeviceLifeCycle::State old_state,
RemoteDeviceLifeCycle::State new_state) {
unlock_manager_->OnLifeCycleStateChanged();
}
void ProximityAuthSystem::OnScreenDidLock(
ScreenlockBridge::LockHandler::ScreenType screen_type) {
OnFocusedUserChanged(ScreenlockBridge::Get()->focused_account_id());
}
void ProximityAuthSystem::OnScreenDidUnlock(
ScreenlockBridge::LockHandler::ScreenType screen_type) {
unlock_manager_->SetRemoteDeviceLifeCycle(nullptr);
remote_device_life_cycle_.reset();
}
void ProximityAuthSystem::OnFocusedUserChanged(const AccountId& account_id) {
// Update the current RemoteDeviceLifeCycle to the focused user.
if (account_id.is_valid() && remote_device_life_cycle_ &&
remote_device_life_cycle_->GetRemoteDevice().user_id !=
account_id.GetUserEmail()) {
PA_LOG(INFO) << "Focused user changed, destroying life cycle for "
<< account_id.Serialize() << ".";
unlock_manager_->SetRemoteDeviceLifeCycle(nullptr);
remote_device_life_cycle_.reset();
}
if (remote_devices_map_.find(account_id) == remote_devices_map_.end() ||
remote_devices_map_[account_id].size() == 0) {
PA_LOG(INFO) << "User " << account_id.Serialize()
<< " does not have a RemoteDevice.";
return;
}
// TODO(tengs): We currently assume each user has only one RemoteDevice, so we
// can simply take the first item in the list.
cryptauth::RemoteDevice remote_device = remote_devices_map_[account_id][0];
if (!suspended_) {
PA_LOG(INFO) << "Creating RemoteDeviceLifeCycle for focused user: "
<< account_id.Serialize();
remote_device_life_cycle_.reset(
new RemoteDeviceLifeCycleImpl(remote_device, proximity_auth_client_));
unlock_manager_->SetRemoteDeviceLifeCycle(remote_device_life_cycle_.get());
remote_device_life_cycle_->AddObserver(this);
remote_device_life_cycle_->Start();
}
}
} // proximity_auth