123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- // Copyright 2018 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 "ash/detachable_base/detachable_base_handler.h"
- #include "ash/constants/ash_pref_names.h"
- #include "ash/detachable_base/detachable_base_observer.h"
- #include "ash/public/cpp/session/user_info.h"
- #include "ash/shell.h"
- #include "base/bind.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/values.h"
- #include "components/account_id/account_id.h"
- #include "components/prefs/pref_registry_simple.h"
- #include "components/prefs/pref_service.h"
- #include "components/prefs/scoped_user_pref_update.h"
- namespace ash {
- namespace {
- // Keys in local state used to persist detachable base pairing state.
- // Example detachable base pref value:
- // {
- // ash.detachable_base.devices: {
- // user_key_1: {
- // last_used: hex encoded base device ID
- // },
- // user_key_2: {
- // // no detachable_base device info, e.g. the user has not ever used it
- // }
- // }
- // }
- constexpr char kLastUsedByUserPrefKey[] = "last_used";
- std::string GetKeyForPrefs(const AccountId& account_id) {
- if (account_id.HasAccountIdKey())
- return account_id.GetAccountIdKey();
- return account_id.GetUserEmail();
- }
- } // namespace
- // static
- void DetachableBaseHandler::RegisterPrefs(PrefRegistrySimple* registry) {
- registry->RegisterDictionaryPref(prefs::kDetachableBaseDevices);
- }
- DetachableBaseHandler::DetachableBaseHandler(PrefService* local_state)
- : local_state_(local_state),
- hammerd_observation_(this),
- power_manager_observation_(this) {
- if (HammerdClient::Get()) // May be null in tests
- hammerd_observation_.Observe(HammerdClient::Get());
- chromeos::PowerManagerClient* power_manager_client =
- chromeos::PowerManagerClient::Get();
- power_manager_observation_.Observe(power_manager_client);
- power_manager_client->GetSwitchStates(
- base::BindOnce(&DetachableBaseHandler::OnGotPowerManagerSwitchStates,
- weak_ptr_factory_.GetWeakPtr()));
- if (GetPairingStatus() != DetachableBasePairingStatus::kNone)
- NotifyPairingStatusChanged();
- }
- DetachableBaseHandler::~DetachableBaseHandler() = default;
- void DetachableBaseHandler::AddObserver(DetachableBaseObserver* observer) {
- observers_.AddObserver(observer);
- }
- void DetachableBaseHandler::RemoveObserver(DetachableBaseObserver* observer) {
- observers_.RemoveObserver(observer);
- }
- void DetachableBaseHandler::RemoveUserData(const UserInfo& user) {
- last_used_devices_.erase(user.account_id);
- if (local_state_) {
- DictionaryPrefUpdate update(local_state_, prefs::kDetachableBaseDevices);
- update->RemoveKey(GetKeyForPrefs(user.account_id));
- }
- }
- DetachableBasePairingStatus DetachableBaseHandler::GetPairingStatus() const {
- if (!tablet_mode_.has_value() ||
- *tablet_mode_ == chromeos::PowerManagerClient::TabletMode::ON) {
- return DetachableBasePairingStatus::kNone;
- }
- return pairing_status_;
- }
- bool DetachableBaseHandler::PairedBaseMatchesLastUsedByUser(
- const UserInfo& user) const {
- if (GetPairingStatus() != DetachableBasePairingStatus::kAuthenticated)
- return false;
- DCHECK(!authenticated_base_id_.empty());
- // If local state is not set for non-ephemeral users, the last used detachable
- // base cannot be determined at this point.
- // Assume no device has previously been used - the state will be evaluated
- // again when the local state prefs get initialzized.
- if (!local_state_ && !user.is_ephemeral)
- return true;
- DetachableBaseId last_used_base = GetLastUsedDeviceForUser(user);
- return last_used_base.empty() || authenticated_base_id_ == last_used_base;
- }
- bool DetachableBaseHandler::SetPairedBaseAsLastUsedByUser(
- const UserInfo& user) {
- if (GetPairingStatus() != DetachableBasePairingStatus::kAuthenticated)
- return false;
- // Do not update the last paired device for non-ephemeral users if local state
- // is not set, as the value would not be correctly preserved. Note that the
- // observers will be notified about the pairing status change when the local
- // state gets initialized - they should attempt to set this value at that
- // point.
- if (!local_state_ && !user.is_ephemeral)
- return false;
- last_used_devices_[user.account_id] = authenticated_base_id_;
- if (!user.is_ephemeral) {
- DictionaryPrefUpdate update(local_state_, prefs::kDetachableBaseDevices);
- update->SetPath({GetKeyForPrefs(user.account_id), kLastUsedByUserPrefKey},
- base::Value(authenticated_base_id_));
- }
- return true;
- }
- void DetachableBaseHandler::BaseFirmwareUpdateNeeded() {
- NotifyBaseRequiresFirmwareUpdate(true /*requires_update*/);
- }
- void DetachableBaseHandler::BaseFirmwareUpdateStarted() {}
- void DetachableBaseHandler::BaseFirmwareUpdateSucceeded() {
- NotifyBaseRequiresFirmwareUpdate(false /*requires_update*/);
- }
- void DetachableBaseHandler::BaseFirmwareUpdateFailed() {}
- void DetachableBaseHandler::PairChallengeSucceeded(
- const std::vector<uint8_t>& base_id) {
- authenticated_base_id_ = base::HexEncode(base_id.data(), base_id.size());
- pairing_status_ = DetachableBasePairingStatus::kAuthenticated;
- if (GetPairingStatus() != DetachableBasePairingStatus::kNone)
- NotifyPairingStatusChanged();
- }
- void DetachableBaseHandler::PairChallengeFailed() {
- authenticated_base_id_.clear();
- pairing_status_ = DetachableBasePairingStatus::kNotAuthenticated;
- if (GetPairingStatus() != DetachableBasePairingStatus::kNone)
- NotifyPairingStatusChanged();
- }
- void DetachableBaseHandler::InvalidBaseConnected() {
- authenticated_base_id_.clear();
- pairing_status_ = DetachableBasePairingStatus::kInvalidDevice;
- if (GetPairingStatus() != DetachableBasePairingStatus::kNone)
- NotifyPairingStatusChanged();
- }
- void DetachableBaseHandler::TabletModeEventReceived(
- chromeos::PowerManagerClient::TabletMode mode,
- base::TimeTicks timestamp) {
- UpdateTabletMode(mode);
- }
- void DetachableBaseHandler::OnGotPowerManagerSwitchStates(
- absl::optional<chromeos::PowerManagerClient::SwitchStates> switch_states) {
- if (!switch_states.has_value() || tablet_mode_.has_value())
- return;
- UpdateTabletMode(switch_states->tablet_mode);
- }
- void DetachableBaseHandler::UpdateTabletMode(
- chromeos::PowerManagerClient::TabletMode mode) {
- DetachableBasePairingStatus old_pairing_status = GetPairingStatus();
- tablet_mode_ = mode;
- if (*tablet_mode_ == chromeos::PowerManagerClient::TabletMode::ON) {
- authenticated_base_id_.clear();
- pairing_status_ = DetachableBasePairingStatus::kNone;
- NotifyBaseRequiresFirmwareUpdate(false /*requires_update*/);
- }
- if (GetPairingStatus() != old_pairing_status)
- NotifyPairingStatusChanged();
- }
- DetachableBaseHandler::DetachableBaseId
- DetachableBaseHandler::GetLastUsedDeviceForUser(const UserInfo& user) const {
- const auto it = last_used_devices_.find(user.account_id);
- // If the last used device was set within this session, bypass local state.
- if (it != last_used_devices_.end())
- return it->second;
- // For ephemeral lookup do not attempt getting the value from local state;
- // return empty string instead.
- if (user.is_ephemeral)
- return "";
- const base::Value::Dict& detachable_base_info =
- local_state_->GetValueDict(prefs::kDetachableBaseDevices);
- const base::Value::Dict* account_info =
- detachable_base_info.FindDictByDottedPath(
- GetKeyForPrefs(user.account_id));
- if (!account_info)
- return "";
- const std::string* last_used =
- account_info->FindString(kLastUsedByUserPrefKey);
- return last_used ? *last_used : "";
- }
- void DetachableBaseHandler::NotifyPairingStatusChanged() {
- for (auto& observer : observers_)
- observer.OnDetachableBasePairingStatusChanged(GetPairingStatus());
- }
- void DetachableBaseHandler::NotifyBaseRequiresFirmwareUpdate(
- bool requires_update) {
- for (auto& observer : observers_)
- observer.OnDetachableBaseRequiresUpdateChanged(requires_update);
- }
- } // namespace ash
|