// 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/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 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); } } RemoteDeviceList ProximityAuthSystem::GetRemoteDevicesForUser( const AccountId& account_id) const { if (remote_devices_map_.find(account_id) == remote_devices_map_.end()) return 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. 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