// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/ash/services/multidevice_setup/feature_state_manager_impl.h"
#include <memory>
#include <optional>
#include <vector>
#include "ash/constants/ash_features.h"
#include "base/containers/contains.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "chromeos/ash/components/multidevice/remote_device_test_util.h"
#include "chromeos/ash/services/device_sync/public/cpp/fake_device_sync_client.h"
#include "chromeos/ash/services/multidevice_setup/fake_feature_state_manager.h"
#include "chromeos/ash/services/multidevice_setup/fake_global_state_feature_manager.h"
#include "chromeos/ash/services/multidevice_setup/fake_host_status_provider.h"
#include "chromeos/ash/services/multidevice_setup/public/cpp/fake_android_sms_pairing_state_tracker.h"
#include "chromeos/ash/services/multidevice_setup/public/cpp/prefs.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace ash {
namespace multidevice_setup {
namespace {
multidevice::RemoteDeviceRef CreateTestLocalDevice() {
multidevice::RemoteDeviceRef local_device =
multidevice::CreateRemoteDeviceRefForTest();
// Set all client features to not supported.
multidevice::RemoteDevice* raw_device =
multidevice::GetMutableRemoteDevice(local_device);
raw_device
->software_features[multidevice::SoftwareFeature::kBetterTogetherClient] =
multidevice::SoftwareFeatureState::kNotSupported;
raw_device
->software_features[multidevice::SoftwareFeature::kSmartLockClient] =
multidevice::SoftwareFeatureState::kNotSupported;
raw_device->software_features
[multidevice::SoftwareFeature::kInstantTetheringClient] =
multidevice::SoftwareFeatureState::kNotSupported;
raw_device->software_features[multidevice::SoftwareFeature::kPhoneHubClient] =
multidevice::SoftwareFeatureState::kNotSupported;
raw_device->software_features[multidevice::SoftwareFeature::kWifiSyncClient] =
multidevice::SoftwareFeatureState::kNotSupported;
return local_device;
}
multidevice::RemoteDeviceRef CreateTestHostDevice(
bool empty_mac_address = false) {
multidevice::RemoteDeviceRef host_device =
multidevice::CreateRemoteDeviceRefForTest();
// Set all host features to supported.
multidevice::RemoteDevice* raw_device =
multidevice::GetMutableRemoteDevice(host_device);
raw_device
->software_features[multidevice::SoftwareFeature::kBetterTogetherHost] =
multidevice::SoftwareFeatureState::kSupported;
raw_device->software_features[multidevice::SoftwareFeature::kSmartLockHost] =
multidevice::SoftwareFeatureState::kSupported;
raw_device
->software_features[multidevice::SoftwareFeature::kInstantTetheringHost] =
multidevice::SoftwareFeatureState::kSupported;
raw_device->software_features[multidevice::SoftwareFeature::kPhoneHubHost] =
multidevice::SoftwareFeatureState::kSupported;
raw_device->software_features[multidevice::SoftwareFeature::kWifiSyncHost] =
multidevice::SoftwareFeatureState::kSupported;
if (empty_mac_address) {
raw_device->bluetooth_public_address.clear();
}
return host_device;
}
} // namespace
class MultiDeviceSetupFeatureStateManagerImplTest : public testing::Test {
public:
MultiDeviceSetupFeatureStateManagerImplTest(
const MultiDeviceSetupFeatureStateManagerImplTest&) = delete;
MultiDeviceSetupFeatureStateManagerImplTest& operator=(
const MultiDeviceSetupFeatureStateManagerImplTest&) = delete;
protected:
MultiDeviceSetupFeatureStateManagerImplTest()
: test_local_device_(CreateTestLocalDevice()),
test_host_device_(CreateTestHostDevice()) {}
~MultiDeviceSetupFeatureStateManagerImplTest() override = default;
void SetupFeatureStateManager(bool is_secondary_user = false,
bool empty_mac_address = false) {
test_host_device_ = CreateTestHostDevice(empty_mac_address);
test_pref_service_ =
std::make_unique<sync_preferences::TestingPrefServiceSyncable>();
user_prefs::PrefRegistrySyncable* registry = test_pref_service_->registry();
RegisterFeaturePrefs(registry);
fake_host_status_provider_ = std::make_unique<FakeHostStatusProvider>();
fake_device_sync_client_ =
std::make_unique<device_sync::FakeDeviceSyncClient>();
fake_device_sync_client_->set_synced_devices(
multidevice::RemoteDeviceRefList{test_local_device_,
test_host_device_});
fake_device_sync_client_->set_local_device_metadata(test_local_device_);
fake_android_sms_pairing_state_tracker_ =
std::make_unique<FakeAndroidSmsPairingStateTracker>();
fake_android_sms_pairing_state_tracker_->SetPairingComplete(true);
fake_global_state_feature_managers_.emplace(
mojom::Feature::kWifiSync,
std::make_unique<FakeGlobalStateFeatureManager>());
manager_ = FeatureStateManagerImpl::Factory::Create(
test_pref_service_.get(), fake_host_status_provider_.get(),
fake_device_sync_client_.get(),
fake_android_sms_pairing_state_tracker_.get(),
{{mojom::Feature::kWifiSync,
fake_global_state_feature_managers_.at(mojom::Feature::kWifiSync)
.get()}},
is_secondary_user);
fake_observer_ = std::make_unique<FakeFeatureStateManagerObserver>();
manager_->AddObserver(fake_observer_.get());
}
void TryAllUnverifiedHostStatesAndVerifyFeatureState(mojom::Feature feature) {
bool previously_had_eligible_hosts =
fake_host_status_provider_->GetHostWithStatus().host_status() !=
mojom::HostStatus::kNoEligibleHosts;
size_t num_observer_events_before_call =
fake_observer_->feature_state_updates().size();
size_t expected_num_observer_events_after_call =
num_observer_events_before_call +
(previously_had_eligible_hosts ? 1u : 0u);
fake_host_status_provider_->SetHostWithStatus(
mojom::HostStatus::kNoEligibleHosts, std::nullopt /* host_device */);
if (previously_had_eligible_hosts) {
VerifyFeatureStateChange(
num_observer_events_before_call, feature,
mojom::FeatureState::kUnavailableNoVerifiedHost_NoEligibleHosts);
}
EXPECT_EQ(mojom::FeatureState::kUnavailableNoVerifiedHost_NoEligibleHosts,
manager_->GetFeatureStates()[feature]);
EXPECT_EQ(expected_num_observer_events_after_call,
fake_observer_->feature_state_updates().size());
fake_host_status_provider_->SetHostWithStatus(
mojom::HostStatus::kEligibleHostExistsButNoHostSet,
std::nullopt /* host_device */);
// Updating host status here updates feature state from
// kUnavailableNoVerifiedHost_NoEligibleHosts to
// kUnavailableNoVerifiedHost_HostExistsButNotSetAndVerified.
expected_num_observer_events_after_call += 1;
EXPECT_EQ(mojom::FeatureState::
kUnavailableNoVerifiedHost_HostExistsButNotSetAndVerified,
manager_->GetFeatureStates()[feature]);
EXPECT_EQ(expected_num_observer_events_after_call,
fake_observer_->feature_state_updates().size());
fake_host_status_provider_->SetHostWithStatus(
mojom::HostStatus::kHostSetLocallyButWaitingForBackendConfirmation,
test_host_device_);
EXPECT_EQ(mojom::FeatureState::
kUnavailableNoVerifiedHost_HostExistsButNotSetAndVerified,
manager_->GetFeatureStates()[feature]);
EXPECT_EQ(expected_num_observer_events_after_call,
fake_observer_->feature_state_updates().size());
fake_host_status_provider_->SetHostWithStatus(
mojom::HostStatus::kHostSetButNotYetVerified, test_host_device_);
EXPECT_EQ(mojom::FeatureState::
kUnavailableNoVerifiedHost_HostExistsButNotSetAndVerified,
manager_->GetFeatureStates()[feature]);
EXPECT_EQ(expected_num_observer_events_after_call,
fake_observer_->feature_state_updates().size());
}
void SetVerifiedHost() {
// Should not already be verified if we are setting it to be verified.
EXPECT_NE(mojom::HostStatus::kHostVerified,
fake_host_status_provider_->GetHostWithStatus().host_status());
size_t num_observer_events_before_call =
fake_observer_->feature_state_updates().size();
SetSoftwareFeatureState(false /* use_local_device */,
multidevice::SoftwareFeature::kBetterTogetherHost,
multidevice::SoftwareFeatureState::kEnabled);
fake_host_status_provider_->SetHostWithStatus(
mojom::HostStatus::kHostVerified, test_host_device_);
// Since the host is now verified, there should be a feature state update
// for all features.
EXPECT_EQ(num_observer_events_before_call + 1u,
fake_observer_->feature_state_updates().size());
}
void MakeBetterTogetherSuiteDisabledByUser(
const mojom::FeatureState& expected_state_upon_disabling =
mojom::FeatureState::kDisabledByUser) {
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kBetterTogetherClient,
multidevice::SoftwareFeatureState::kSupported);
test_pref_service_->SetBoolean(kBetterTogetherSuiteEnabledPrefName, false);
EXPECT_EQ(
expected_state_upon_disabling,
manager_->GetFeatureStates()[mojom::Feature::kBetterTogetherSuite]);
}
void VerifyFeatureState(mojom::FeatureState expected_feature_state,
mojom::Feature feature) {
EXPECT_TRUE(base::Contains(manager_->GetFeatureStates(), feature));
EXPECT_EQ(expected_feature_state, manager_->GetFeatureStates()[feature]);
}
void VerifyFeatureStateChange(size_t expected_index,
mojom::Feature expected_feature,
mojom::FeatureState expected_feature_state) {
const FeatureStateManager::FeatureStatesMap& map =
fake_observer_->feature_state_updates()[expected_index];
const auto it = map.find(expected_feature);
EXPECT_NE(map.end(), it);
EXPECT_EQ(expected_feature_state, it->second);
}
void SetSoftwareFeatureState(
bool use_local_device,
multidevice::SoftwareFeature software_feature,
multidevice::SoftwareFeatureState software_feature_state) {
multidevice::RemoteDeviceRef& device =
use_local_device ? test_local_device_ : test_host_device_;
multidevice::GetMutableRemoteDevice(device)
->software_features[software_feature] = software_feature_state;
fake_device_sync_client_->NotifyNewDevicesSynced();
}
void SetAndroidSmsPairingState(bool is_paired) {
fake_android_sms_pairing_state_tracker_->SetPairingComplete(is_paired);
}
sync_preferences::TestingPrefServiceSyncable* test_pref_service() {
return test_pref_service_.get();
}
FeatureStateManager* manager() { return manager_.get(); }
base::flat_map<mojom::Feature,
std::unique_ptr<FakeGlobalStateFeatureManager>>&
global_state_feature_managers() {
return fake_global_state_feature_managers_;
}
private:
base::test::TaskEnvironment task_environment_;
multidevice::RemoteDeviceRef test_local_device_;
multidevice::RemoteDeviceRef test_host_device_;
std::unique_ptr<sync_preferences::TestingPrefServiceSyncable>
test_pref_service_;
std::unique_ptr<FakeHostStatusProvider> fake_host_status_provider_;
std::unique_ptr<device_sync::FakeDeviceSyncClient> fake_device_sync_client_;
std::unique_ptr<FakeAndroidSmsPairingStateTracker>
fake_android_sms_pairing_state_tracker_;
base::flat_map<mojom::Feature, std::unique_ptr<FakeGlobalStateFeatureManager>>
fake_global_state_feature_managers_;
std::unique_ptr<FakeFeatureStateManagerObserver> fake_observer_;
std::unique_ptr<FeatureStateManager> manager_;
};
TEST_F(MultiDeviceSetupFeatureStateManagerImplTest,
DisableAllowCrossDeviceFeatureSuiteFlag) {
// Disable the "AllowCrossDeviceFeatureSuite" flag, which should force all
// Cross Device features to be unsupported.
base::test::ScopedFeatureList feature_list;
feature_list.InitAndDisableFeature(
ash::features::kAllowCrossDeviceFeatureSuite);
// Enable all features
SetupFeatureStateManager();
SetVerifiedHost();
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kBetterTogetherClient,
multidevice::SoftwareFeatureState::kSupported);
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kInstantTetheringClient,
multidevice::SoftwareFeatureState::kSupported);
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kSmartLockClient,
multidevice::SoftwareFeatureState::kSupported);
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kPhoneHubClient,
multidevice::SoftwareFeatureState::kSupported);
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kWifiSyncClient,
multidevice::SoftwareFeatureState::kSupported);
// Verify that all features are unsupported.
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
mojom::Feature::kBetterTogetherSuite);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
mojom::Feature::kInstantTethering);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
mojom::Feature::kSmartLock);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
mojom::Feature::kPhoneHub);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
mojom::Feature::kPhoneHubNotifications);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
mojom::Feature::kPhoneHubTaskContinuation);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
mojom::Feature::kWifiSync);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
mojom::Feature::kEche);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
mojom::Feature::kPhoneHubCameraRoll);
}
TEST_F(MultiDeviceSetupFeatureStateManagerImplTest, BetterTogetherSuite) {
SetupFeatureStateManager();
TryAllUnverifiedHostStatesAndVerifyFeatureState(
mojom::Feature::kBetterTogetherSuite);
SetVerifiedHost();
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
mojom::Feature::kBetterTogetherSuite);
// Add support for the suite; it should still remain unsupported, since there
// are no sub-features which are supported.
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kBetterTogetherClient,
multidevice::SoftwareFeatureState::kSupported);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
mojom::Feature::kBetterTogetherSuite);
// Add support for child features.
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kInstantTetheringClient,
multidevice::SoftwareFeatureState::kSupported);
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kSmartLockClient,
multidevice::SoftwareFeatureState::kSupported);
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kPhoneHubClient,
multidevice::SoftwareFeatureState::kSupported);
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kWifiSyncClient,
multidevice::SoftwareFeatureState::kSupported);
// Now, the suite should be considered enabled.
VerifyFeatureState(mojom::FeatureState::kEnabledByUser,
mojom::Feature::kBetterTogetherSuite);
VerifyFeatureStateChange(5u /* expected_index */,
mojom::Feature::kBetterTogetherSuite,
mojom::FeatureState::kEnabledByUser);
test_pref_service()->SetBoolean(kBetterTogetherSuiteEnabledPrefName, false);
VerifyFeatureState(mojom::FeatureState::kDisabledByUser,
mojom::Feature::kBetterTogetherSuite);
VerifyFeatureStateChange(6u /* expected_index */,
mojom::Feature::kBetterTogetherSuite,
mojom::FeatureState::kDisabledByUser);
// Set all features to prohibited. This should cause the Better Together suite
// to become prohibited as well.
test_pref_service()->SetBoolean(kInstantTetheringAllowedPrefName, false);
test_pref_service()->SetBoolean(kSmartLockAllowedPrefName, false);
test_pref_service()->SetBoolean(kPhoneHubAllowedPrefName, false);
test_pref_service()->SetBoolean(kWifiSyncAllowedPrefName, false);
VerifyFeatureState(mojom::FeatureState::kProhibitedByPolicy,
mojom::Feature::kBetterTogetherSuite);
VerifyFeatureStateChange(10u /* expected_index */,
mojom::Feature::kBetterTogetherSuite,
mojom::FeatureState::kProhibitedByPolicy);
}
TEST_F(MultiDeviceSetupFeatureStateManagerImplTest,
BetterTogetherSuiteForSecondaryUsers) {
SetupFeatureStateManager(/*is_secondary_user=*/true);
TryAllUnverifiedHostStatesAndVerifyFeatureState(
mojom::Feature::kBetterTogetherSuite);
SetVerifiedHost();
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
mojom::Feature::kBetterTogetherSuite);
// Add support for the suite; it should still remain unsupported, since there
// are no sub-features which are supported.
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kBetterTogetherClient,
multidevice::SoftwareFeatureState::kSupported);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
mojom::Feature::kBetterTogetherSuite);
// Add support for child features.
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kInstantTetheringClient,
multidevice::SoftwareFeatureState::kSupported);
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kSmartLockClient,
multidevice::SoftwareFeatureState::kSupported);
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kPhoneHubClient,
multidevice::SoftwareFeatureState::kSupported);
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kWifiSyncClient,
multidevice::SoftwareFeatureState::kSupported);
// Now, the suite should be considered enabled.
VerifyFeatureState(mojom::FeatureState::kEnabledByUser,
mojom::Feature::kBetterTogetherSuite);
VerifyFeatureStateChange(4u /* expected_index */,
mojom::Feature::kBetterTogetherSuite,
mojom::FeatureState::kEnabledByUser);
test_pref_service()->SetBoolean(kBetterTogetherSuiteEnabledPrefName, false);
VerifyFeatureState(mojom::FeatureState::kDisabledByUser,
mojom::Feature::kBetterTogetherSuite);
VerifyFeatureStateChange(5u /* expected_index */,
mojom::Feature::kBetterTogetherSuite,
mojom::FeatureState::kDisabledByUser);
// Set all features to prohibited. This should cause the Better Together suite
// to become prohibited as well.
test_pref_service()->SetBoolean(kInstantTetheringAllowedPrefName, false);
test_pref_service()->SetBoolean(kSmartLockAllowedPrefName, false);
test_pref_service()->SetBoolean(kPhoneHubAllowedPrefName, false);
test_pref_service()->SetBoolean(kWifiSyncAllowedPrefName, false);
VerifyFeatureState(mojom::FeatureState::kProhibitedByPolicy,
mojom::Feature::kBetterTogetherSuite);
VerifyFeatureStateChange(9u /* expected_index */,
mojom::Feature::kBetterTogetherSuite,
mojom::FeatureState::kProhibitedByPolicy);
}
TEST_F(MultiDeviceSetupFeatureStateManagerImplTest, InstantTethering) {
SetupFeatureStateManager();
TryAllUnverifiedHostStatesAndVerifyFeatureState(
mojom::Feature::kInstantTethering);
SetVerifiedHost();
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
mojom::Feature::kInstantTethering);
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kInstantTetheringClient,
multidevice::SoftwareFeatureState::kSupported);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByPhone,
mojom::Feature::kInstantTethering);
VerifyFeatureStateChange(2u /* expected_index */,
mojom::Feature::kInstantTethering,
mojom::FeatureState::kNotSupportedByPhone);
SetSoftwareFeatureState(false /* use_local_device */,
multidevice::SoftwareFeature::kInstantTetheringHost,
multidevice::SoftwareFeatureState::kEnabled);
VerifyFeatureState(mojom::FeatureState::kEnabledByUser,
mojom::Feature::kInstantTethering);
VerifyFeatureStateChange(3u /* expected_index */,
mojom::Feature::kInstantTethering,
mojom::FeatureState::kEnabledByUser);
MakeBetterTogetherSuiteDisabledByUser();
VerifyFeatureState(mojom::FeatureState::kUnavailableSuiteDisabled,
mojom::Feature::kInstantTethering);
VerifyFeatureStateChange(5u /* expected_index */,
mojom::Feature::kInstantTethering,
mojom::FeatureState::kUnavailableSuiteDisabled);
test_pref_service()->SetBoolean(kInstantTetheringEnabledPrefName, false);
VerifyFeatureState(mojom::FeatureState::kDisabledByUser,
mojom::Feature::kInstantTethering);
VerifyFeatureStateChange(6u /* expected_index */,
mojom::Feature::kInstantTethering,
mojom::FeatureState::kDisabledByUser);
test_pref_service()->SetBoolean(kInstantTetheringAllowedPrefName, false);
VerifyFeatureState(mojom::FeatureState::kProhibitedByPolicy,
mojom::Feature::kInstantTethering);
VerifyFeatureStateChange(7u /* expected_index */,
mojom::Feature::kInstantTethering,
mojom::FeatureState::kProhibitedByPolicy);
}
TEST_F(MultiDeviceSetupFeatureStateManagerImplTest, SmartLock) {
SetupFeatureStateManager();
TryAllUnverifiedHostStatesAndVerifyFeatureState(mojom::Feature::kSmartLock);
SetVerifiedHost();
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
mojom::Feature::kSmartLock);
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kSmartLockClient,
multidevice::SoftwareFeatureState::kSupported);
VerifyFeatureState(mojom::FeatureState::kUnavailableInsufficientSecurity,
mojom::Feature::kSmartLock);
VerifyFeatureStateChange(
2u /* expected_index */, mojom::Feature::kSmartLock,
mojom::FeatureState::kUnavailableInsufficientSecurity);
SetSoftwareFeatureState(false /* use_local_device */,
multidevice::SoftwareFeature::kSmartLockHost,
multidevice::SoftwareFeatureState::kEnabled);
VerifyFeatureState(mojom::FeatureState::kEnabledByUser,
mojom::Feature::kSmartLock);
VerifyFeatureStateChange(3u /* expected_index */, mojom::Feature::kSmartLock,
mojom::FeatureState::kEnabledByUser);
MakeBetterTogetherSuiteDisabledByUser();
VerifyFeatureState(mojom::FeatureState::kUnavailableSuiteDisabled,
mojom::Feature::kSmartLock);
VerifyFeatureStateChange(5u /* expected_index */, mojom::Feature::kSmartLock,
mojom::FeatureState::kUnavailableSuiteDisabled);
test_pref_service()->SetBoolean(kSmartLockEnabledPrefName, false);
VerifyFeatureState(mojom::FeatureState::kDisabledByUser,
mojom::Feature::kSmartLock);
VerifyFeatureStateChange(6u /* expected_index */, mojom::Feature::kSmartLock,
mojom::FeatureState::kDisabledByUser);
test_pref_service()->SetBoolean(kSmartLockAllowedPrefName, false);
VerifyFeatureState(mojom::FeatureState::kProhibitedByPolicy,
mojom::Feature::kSmartLock);
VerifyFeatureStateChange(7u /* expected_index */, mojom::Feature::kSmartLock,
mojom::FeatureState::kProhibitedByPolicy);
}
TEST_F(MultiDeviceSetupFeatureStateManagerImplTest,
PhoneHubBluetoothAddressNotSynced) {
SetupFeatureStateManager(/*is_secondary_user=*/false,
/*empty_mac_address=*/true);
const std::vector<mojom::Feature> kAllPhoneHubFeatures{
mojom::Feature::kPhoneHub, mojom::Feature::kPhoneHubCameraRoll,
mojom::Feature::kPhoneHubNotifications,
mojom::Feature::kPhoneHubTaskContinuation, mojom::Feature::kEche};
for (const auto& phone_hub_feature : kAllPhoneHubFeatures) {
TryAllUnverifiedHostStatesAndVerifyFeatureState(phone_hub_feature);
}
SetVerifiedHost();
for (const auto& phone_hub_feature : kAllPhoneHubFeatures) {
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
phone_hub_feature);
}
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kPhoneHubClient,
multidevice::SoftwareFeatureState::kSupported);
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kEcheClient,
multidevice::SoftwareFeatureState::kSupported);
for (const auto& phone_hub_feature : kAllPhoneHubFeatures) {
VerifyFeatureState(mojom::FeatureState::kNotSupportedByPhone,
phone_hub_feature);
}
// This pref is disabled for existing Better Together users; they must go to
// settings to explicitly enable PhoneHub.
test_pref_service()->SetBoolean(kPhoneHubEnabledPrefName, true);
SetSoftwareFeatureState(false /* use_local_device */,
multidevice::SoftwareFeature::kPhoneHubHost,
multidevice::SoftwareFeatureState::kEnabled);
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kEcheHost,
multidevice::SoftwareFeatureState::kSupported);
for (const auto& phone_hub_feature : kAllPhoneHubFeatures) {
VerifyFeatureState(mojom::FeatureState::kNotSupportedByPhone,
phone_hub_feature);
}
VerifyFeatureStateChange(kAllPhoneHubFeatures.size() * 2 /* expected_index */,
mojom::Feature::kPhoneHub,
mojom::FeatureState::kNotSupportedByPhone);
MakeBetterTogetherSuiteDisabledByUser(
/*expected_state_upon_disabling=*/mojom::FeatureState::kDisabledByUser);
for (const auto& phone_hub_feature : kAllPhoneHubFeatures) {
VerifyFeatureState(mojom::FeatureState::kNotSupportedByPhone,
phone_hub_feature);
}
VerifyFeatureStateChange(
kAllPhoneHubFeatures.size() * 2 + 1 /* expected_index */,
mojom::Feature::kPhoneHub, mojom::FeatureState::kNotSupportedByPhone);
test_pref_service()->SetBoolean(kPhoneHubNotificationsEnabledPrefName, false);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByPhone,
mojom::Feature::kPhoneHubNotifications);
test_pref_service()->SetBoolean(kPhoneHubNotificationsEnabledPrefName, true);
test_pref_service()->SetBoolean(kPhoneHubEnabledPrefName, false);
for (const auto& phone_hub_feature : kAllPhoneHubFeatures) {
VerifyFeatureState(mojom::FeatureState::kNotSupportedByPhone,
phone_hub_feature);
}
test_pref_service()->SetBoolean(kPhoneHubNotificationsAllowedPrefName, false);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByPhone,
mojom::Feature::kPhoneHubNotifications);
VerifyFeatureStateChange(
kAllPhoneHubFeatures.size() * 2 + 2 /* expected_index */,
mojom::Feature::kPhoneHubNotifications,
mojom::FeatureState::kNotSupportedByPhone);
// Prohibiting Phone Hub implicitly prohibits all of its sub-features.
test_pref_service()->SetBoolean(kPhoneHubAllowedPrefName, false);
for (const auto& phone_hub_feature : kAllPhoneHubFeatures) {
VerifyFeatureState(mojom::FeatureState::kProhibitedByPolicy,
phone_hub_feature);
}
VerifyFeatureStateChange(
kAllPhoneHubFeatures.size() * 2 + 3 /* expected_index */,
mojom::Feature::kPhoneHub, mojom::FeatureState::kProhibitedByPolicy);
}
TEST_F(MultiDeviceSetupFeatureStateManagerImplTest, PhoneHubForSecondaryUsers) {
SetupFeatureStateManager(/*is_secondary_user=*/true);
const std::vector<mojom::Feature> kAllPhoneHubFeatures{
mojom::Feature::kPhoneHub, mojom::Feature::kPhoneHubCameraRoll,
mojom::Feature::kPhoneHubNotifications,
mojom::Feature::kPhoneHubTaskContinuation, mojom::Feature::kEche};
for (const auto& phone_hub_feature : kAllPhoneHubFeatures) {
TryAllUnverifiedHostStatesAndVerifyFeatureState(phone_hub_feature);
}
SetVerifiedHost();
for (const auto& phone_hub_feature : kAllPhoneHubFeatures) {
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
phone_hub_feature);
}
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kPhoneHubClient,
multidevice::SoftwareFeatureState::kSupported);
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kEcheClient,
multidevice::SoftwareFeatureState::kSupported);
for (const auto& phone_hub_feature : kAllPhoneHubFeatures) {
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
phone_hub_feature);
}
// This pref should be disabled for existing Better Together users;
// they must go to settings to explicitly enable PhoneHub.
test_pref_service()->SetBoolean(kPhoneHubEnabledPrefName, true);
SetSoftwareFeatureState(false /* use_local_device */,
multidevice::SoftwareFeature::kPhoneHubHost,
multidevice::SoftwareFeatureState::kEnabled);
SetSoftwareFeatureState(false /* use_local_device */,
multidevice::SoftwareFeature::kEcheHost,
multidevice::SoftwareFeatureState::kEnabled);
for (const auto& phone_hub_feature : kAllPhoneHubFeatures) {
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
phone_hub_feature);
}
MakeBetterTogetherSuiteDisabledByUser(
/*expected_state_upon_disabling=*/mojom::FeatureState::
kNotSupportedByChromebook);
for (const auto& phone_hub_feature : kAllPhoneHubFeatures) {
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
phone_hub_feature);
}
test_pref_service()->SetBoolean(kPhoneHubNotificationsEnabledPrefName, false);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
mojom::Feature::kPhoneHubNotifications);
test_pref_service()->SetBoolean(kPhoneHubNotificationsEnabledPrefName, true);
test_pref_service()->SetBoolean(kPhoneHubEnabledPrefName, false);
for (const auto& phone_hub_feature : kAllPhoneHubFeatures) {
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
phone_hub_feature);
}
test_pref_service()->SetBoolean(kPhoneHubNotificationsAllowedPrefName, false);
VerifyFeatureState(mojom::FeatureState::kProhibitedByPolicy,
mojom::Feature::kPhoneHubNotifications);
VerifyFeatureStateChange(kAllPhoneHubFeatures.size() * 2 /* expected_index */,
mojom::Feature::kPhoneHubNotifications,
mojom::FeatureState::kProhibitedByPolicy);
// Prohibiting Phone Hub implicitly prohibits all of its sub-features.
test_pref_service()->SetBoolean(kPhoneHubAllowedPrefName, false);
for (const auto& phone_hub_feature : kAllPhoneHubFeatures) {
VerifyFeatureState(mojom::FeatureState::kProhibitedByPolicy,
phone_hub_feature);
}
VerifyFeatureStateChange(
kAllPhoneHubFeatures.size() * 2 + 1 /* expected_index */,
mojom::Feature::kPhoneHub, mojom::FeatureState::kProhibitedByPolicy);
}
TEST_F(MultiDeviceSetupFeatureStateManagerImplTest, PhoneHub) {
SetupFeatureStateManager();
const std::vector<mojom::Feature> kAllPhoneHubFeatures{
mojom::Feature::kPhoneHub, mojom::Feature::kPhoneHubNotifications,
mojom::Feature::kPhoneHubTaskContinuation};
for (const auto& phone_hub_feature : kAllPhoneHubFeatures) {
TryAllUnverifiedHostStatesAndVerifyFeatureState(phone_hub_feature);
}
SetVerifiedHost();
for (const auto& phone_hub_feature : kAllPhoneHubFeatures) {
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
phone_hub_feature);
}
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kPhoneHubClient,
multidevice::SoftwareFeatureState::kSupported);
for (const auto& phone_hub_feature : kAllPhoneHubFeatures) {
VerifyFeatureState(mojom::FeatureState::kNotSupportedByPhone,
phone_hub_feature);
}
VerifyFeatureStateChange(kAllPhoneHubFeatures.size() * 2 /* expected_index */,
mojom::Feature::kPhoneHub,
mojom::FeatureState::kNotSupportedByPhone);
// The top-level Phone Hub enabled pref is disabled for existing Better
// Together users; they must go to settings to explicitly enable PhoneHub.
// Likewise, the Phone Hub notifications enabled pref is disabled by default
// to ensure the phone grants access.
test_pref_service()->SetBoolean(kPhoneHubEnabledPrefName, true);
test_pref_service()->SetBoolean(kPhoneHubNotificationsEnabledPrefName, true);
SetSoftwareFeatureState(false /* use_local_device */,
multidevice::SoftwareFeature::kPhoneHubHost,
multidevice::SoftwareFeatureState::kEnabled);
for (const auto& phone_hub_feature : kAllPhoneHubFeatures) {
VerifyFeatureState(mojom::FeatureState::kEnabledByUser, phone_hub_feature);
}
VerifyFeatureStateChange(
kAllPhoneHubFeatures.size() * 2 + 1 /* expected_index */,
mojom::Feature::kPhoneHub, mojom::FeatureState::kEnabledByUser);
MakeBetterTogetherSuiteDisabledByUser();
for (const auto& phone_hub_feature : kAllPhoneHubFeatures) {
VerifyFeatureState(mojom::FeatureState::kUnavailableSuiteDisabled,
phone_hub_feature);
}
VerifyFeatureStateChange(
kAllPhoneHubFeatures.size() * 2 + 3 /* expected_index */,
mojom::Feature::kPhoneHub,
mojom::FeatureState::kUnavailableSuiteDisabled);
test_pref_service()->SetBoolean(kPhoneHubNotificationsEnabledPrefName, false);
VerifyFeatureState(mojom::FeatureState::kDisabledByUser,
mojom::Feature::kPhoneHubNotifications);
VerifyFeatureStateChange(
kAllPhoneHubFeatures.size() * 2 + 4 /* expected_index */,
mojom::Feature::kPhoneHubNotifications,
mojom::FeatureState::kDisabledByUser);
// Re-enable Phone Hub notifications, then disable Phone Hub, which implicitly
// implicitly makes all of its sub-features unavailable.
test_pref_service()->SetBoolean(kPhoneHubNotificationsEnabledPrefName, true);
test_pref_service()->SetBoolean(kPhoneHubEnabledPrefName, false);
VerifyFeatureState(mojom::FeatureState::kDisabledByUser,
mojom::Feature::kPhoneHub);
VerifyFeatureState(mojom::FeatureState::kUnavailableTopLevelFeatureDisabled,
mojom::Feature::kPhoneHubNotifications);
VerifyFeatureState(mojom::FeatureState::kUnavailableTopLevelFeatureDisabled,
mojom::Feature::kPhoneHubTaskContinuation);
VerifyFeatureStateChange(
kAllPhoneHubFeatures.size() * 2 + 6 /* expected_index */,
mojom::Feature::kPhoneHub, mojom::FeatureState::kDisabledByUser);
test_pref_service()->SetBoolean(kPhoneHubNotificationsAllowedPrefName, false);
VerifyFeatureState(mojom::FeatureState::kProhibitedByPolicy,
mojom::Feature::kPhoneHubNotifications);
VerifyFeatureStateChange(
kAllPhoneHubFeatures.size() * 2 + 7 /* expected_index */,
mojom::Feature::kPhoneHubNotifications,
mojom::FeatureState::kProhibitedByPolicy);
// Prohibiting Phone Hub implicitly prohibits all of its sub-features.
test_pref_service()->SetBoolean(kPhoneHubAllowedPrefName, false);
for (const auto& phone_hub_feature : kAllPhoneHubFeatures) {
VerifyFeatureState(mojom::FeatureState::kProhibitedByPolicy,
phone_hub_feature);
}
VerifyFeatureStateChange(
kAllPhoneHubFeatures.size() * 2 + 8 /* expected_index */,
mojom::Feature::kPhoneHub, mojom::FeatureState::kProhibitedByPolicy);
}
TEST_F(MultiDeviceSetupFeatureStateManagerImplTest, CameraRoll) {
SetupFeatureStateManager();
TryAllUnverifiedHostStatesAndVerifyFeatureState(
mojom::Feature::kPhoneHubCameraRoll);
SetVerifiedHost();
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
mojom::Feature::kPhoneHub);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
mojom::Feature::kPhoneHubCameraRoll);
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kPhoneHubClient,
multidevice::SoftwareFeatureState::kSupported);
SetSoftwareFeatureState(
true /* use_local_device */,
multidevice::SoftwareFeature::kPhoneHubCameraRollClient,
multidevice::SoftwareFeatureState::kSupported);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByPhone,
mojom::Feature::kPhoneHub);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByPhone,
mojom::Feature::kPhoneHubCameraRoll);
SetSoftwareFeatureState(false /* use_local_device */,
multidevice::SoftwareFeature::kPhoneHubHost,
multidevice::SoftwareFeatureState::kEnabled);
SetSoftwareFeatureState(false /* use_local_device */,
multidevice::SoftwareFeature::kPhoneHubCameraRollHost,
multidevice::SoftwareFeatureState::kEnabled);
VerifyFeatureState(mojom::FeatureState::kDisabledByUser,
mojom::Feature::kPhoneHub);
VerifyFeatureState(mojom::FeatureState::kDisabledByUser,
mojom::Feature::kPhoneHubCameraRoll);
// Camera Roll does not automatically enable with Phone Hub
test_pref_service()->SetBoolean(kPhoneHubEnabledPrefName, true);
VerifyFeatureState(mojom::FeatureState::kEnabledByUser,
mojom::Feature::kPhoneHub);
VerifyFeatureState(mojom::FeatureState::kDisabledByUser,
mojom::Feature::kPhoneHubCameraRoll);
// Enable Camera Roll
test_pref_service()->SetBoolean(kPhoneHubCameraRollEnabledPrefName, true);
VerifyFeatureState(mojom::FeatureState::kEnabledByUser,
mojom::Feature::kPhoneHub);
VerifyFeatureState(mojom::FeatureState::kEnabledByUser,
mojom::Feature::kPhoneHubCameraRoll);
// Camera Roll is automatically disabled when Phone Hub is disabled
test_pref_service()->SetBoolean(kPhoneHubEnabledPrefName, false);
VerifyFeatureState(mojom::FeatureState::kDisabledByUser,
mojom::Feature::kPhoneHub);
VerifyFeatureState(mojom::FeatureState::kUnavailableTopLevelFeatureDisabled,
mojom::Feature::kPhoneHubCameraRoll);
// Camera Roll restores its previous state when Phone Hub is enabled
test_pref_service()->SetBoolean(kPhoneHubEnabledPrefName, true);
VerifyFeatureState(mojom::FeatureState::kEnabledByUser,
mojom::Feature::kPhoneHub);
VerifyFeatureState(mojom::FeatureState::kEnabledByUser,
mojom::Feature::kPhoneHubCameraRoll);
// Prohibiting Camera Roll does not prohibit Phone Hub
test_pref_service()->SetBoolean(kPhoneHubCameraRollAllowedPrefName, false);
VerifyFeatureState(mojom::FeatureState::kEnabledByUser,
mojom::Feature::kPhoneHub);
VerifyFeatureState(mojom::FeatureState::kProhibitedByPolicy,
mojom::Feature::kPhoneHubCameraRoll);
// Prohibiting Phone Hub does prohibit Camera Roll
test_pref_service()->SetBoolean(kPhoneHubCameraRollAllowedPrefName, true);
test_pref_service()->SetBoolean(kPhoneHubAllowedPrefName, false);
VerifyFeatureState(mojom::FeatureState::kProhibitedByPolicy,
mojom::Feature::kPhoneHub);
VerifyFeatureState(mojom::FeatureState::kProhibitedByPolicy,
mojom::Feature::kPhoneHubCameraRoll);
}
TEST_F(MultiDeviceSetupFeatureStateManagerImplTest, WifiSync) {
SetupFeatureStateManager();
// Set the initial global state to disabled, so that the wifi sync feature
// state will be |kDisabledByUser| when it becomes supported on both the host
// and client devices.
global_state_feature_managers()[mojom::Feature::kWifiSync]
->SetIsFeatureEnabled(false);
TryAllUnverifiedHostStatesAndVerifyFeatureState(mojom::Feature::kWifiSync);
SetVerifiedHost();
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
mojom::Feature::kWifiSync);
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kWifiSyncClient,
multidevice::SoftwareFeatureState::kSupported);
VerifyFeatureState(mojom::FeatureState::kDisabledByUser,
mojom::Feature::kWifiSync);
VerifyFeatureStateChange(2u /* expected_index */, mojom::Feature::kWifiSync,
mojom::FeatureState::kDisabledByUser);
// The GlobalStateFeatureManager should be updated when the host state changes
// to |kEnabled|. It will then update the feature state to |kEnabledByUser|.
global_state_feature_managers()[mojom::Feature::kWifiSync]
->SetIsFeatureEnabled(true);
SetSoftwareFeatureState(false /* use_local_device */,
multidevice::SoftwareFeature::kWifiSyncHost,
multidevice::SoftwareFeatureState::kEnabled);
VerifyFeatureState(mojom::FeatureState::kEnabledByUser,
mojom::Feature::kWifiSync);
VerifyFeatureStateChange(3u /* expected_index */, mojom::Feature::kWifiSync,
mojom::FeatureState::kEnabledByUser);
// Simulate user toggling the wifi sync state, and verify that the
// GlobalStateFeatureManager was updated accordingly.
manager()->SetFeatureEnabledState(mojom::Feature::kWifiSync, false);
VerifyFeatureState(mojom::FeatureState::kDisabledByUser,
mojom::Feature::kWifiSync);
VerifyFeatureStateChange(4u /* expected_index */, mojom::Feature::kWifiSync,
mojom::FeatureState::kDisabledByUser);
EXPECT_FALSE(global_state_feature_managers()[mojom::Feature::kWifiSync]
->IsFeatureEnabled());
manager()->SetFeatureEnabledState(mojom::Feature::kWifiSync, true);
VerifyFeatureState(mojom::FeatureState::kEnabledByUser,
mojom::Feature::kWifiSync);
VerifyFeatureStateChange(5u /* expected_index */, mojom::Feature::kWifiSync,
mojom::FeatureState::kEnabledByUser);
EXPECT_TRUE(global_state_feature_managers()[mojom::Feature::kWifiSync]
->IsFeatureEnabled());
MakeBetterTogetherSuiteDisabledByUser();
VerifyFeatureState(mojom::FeatureState::kUnavailableSuiteDisabled,
mojom::Feature::kWifiSync);
VerifyFeatureStateChange(7u /* expected_index */, mojom::Feature::kWifiSync,
mojom::FeatureState::kUnavailableSuiteDisabled);
test_pref_service()->SetBoolean(kWifiSyncAllowedPrefName, false);
VerifyFeatureState(mojom::FeatureState::kProhibitedByPolicy,
mojom::Feature::kWifiSync);
VerifyFeatureStateChange(8u /* expected_index */, mojom::Feature::kWifiSync,
mojom::FeatureState::kProhibitedByPolicy);
}
TEST_F(MultiDeviceSetupFeatureStateManagerImplTest, Eche) {
SetupFeatureStateManager();
TryAllUnverifiedHostStatesAndVerifyFeatureState(mojom::Feature::kEche);
SetVerifiedHost();
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kPhoneHubClient,
multidevice::SoftwareFeatureState::kSupported);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByPhone,
mojom::Feature::kEche);
VerifyFeatureStateChange(2u /* expected_index */, mojom::Feature::kEche,
mojom::FeatureState::kNotSupportedByPhone);
SetSoftwareFeatureState(false /* use_local_device */,
multidevice::SoftwareFeature::kPhoneHubHost,
multidevice::SoftwareFeatureState::kEnabled);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
mojom::Feature::kEche);
VerifyFeatureStateChange(3u /* expected_index */, mojom::Feature::kEche,
mojom::FeatureState::kNotSupportedByChromebook);
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kEcheClient,
multidevice::SoftwareFeatureState::kSupported);
VerifyFeatureStateChange(4u /* expected_index */, mojom::Feature::kEche,
mojom::FeatureState::kNotSupportedByPhone);
// The top-level Phone Hub enabled pref is disabled for existing Better
// Together users; they must go to settings to explicitly enable PhoneHub.
test_pref_service()->SetBoolean(kEcheEnabledPrefName, true);
SetSoftwareFeatureState(false /* use_local_device */,
multidevice::SoftwareFeature::kEcheHost,
multidevice::SoftwareFeatureState::kSupported);
VerifyFeatureState(mojom::FeatureState::kUnavailableTopLevelFeatureDisabled,
mojom::Feature::kEche);
VerifyFeatureStateChange(
5u /* expected_index */, mojom::Feature::kEche,
mojom::FeatureState::kUnavailableTopLevelFeatureDisabled);
test_pref_service()->SetBoolean(kPhoneHubEnabledPrefName, true);
VerifyFeatureState(mojom::FeatureState::kEnabledByUser,
mojom::Feature::kEche);
VerifyFeatureStateChange(6u /* expected_index */, mojom::Feature::kEche,
mojom::FeatureState::kEnabledByUser);
MakeBetterTogetherSuiteDisabledByUser();
VerifyFeatureState(mojom::FeatureState::kUnavailableSuiteDisabled,
mojom::Feature::kEche);
VerifyFeatureStateChange(8u /* expected_index */, mojom::Feature::kEche,
mojom::FeatureState::kUnavailableSuiteDisabled);
test_pref_service()->SetBoolean(kEcheEnabledPrefName, false);
VerifyFeatureState(mojom::FeatureState::kDisabledByUser,
mojom::Feature::kEche);
VerifyFeatureStateChange(9u /* expected_index */, mojom::Feature::kEche,
mojom::FeatureState::kDisabledByUser);
// Re-enable Eche, then disable Phone Hub, which implicitly
// makes Eche unavailable.
test_pref_service()->SetBoolean(kEcheEnabledPrefName, true);
test_pref_service()->SetBoolean(kPhoneHubEnabledPrefName, false);
VerifyFeatureState(mojom::FeatureState::kUnavailableTopLevelFeatureDisabled,
mojom::Feature::kEche);
VerifyFeatureStateChange(
11u /* expected_index */, mojom::Feature::kEche,
mojom::FeatureState::kUnavailableTopLevelFeatureDisabled);
// Prohibiting Phone Hub implicitly prohibits Eche features.
test_pref_service()->SetBoolean(kPhoneHubAllowedPrefName, false);
VerifyFeatureState(mojom::FeatureState::kProhibitedByPolicy,
mojom::Feature::kEche);
VerifyFeatureStateChange(12u /* expected_index */, mojom::Feature::kEche,
mojom::FeatureState::kProhibitedByPolicy);
}
TEST_F(MultiDeviceSetupFeatureStateManagerImplTest,
EcheSupportReceivedFromPhoneHub) {
SetupFeatureStateManager();
TryAllUnverifiedHostStatesAndVerifyFeatureState(mojom::Feature::kEche);
SetVerifiedHost();
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kPhoneHubClient,
multidevice::SoftwareFeatureState::kSupported);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByPhone,
mojom::Feature::kEche);
VerifyFeatureStateChange(2u /* expected_index */, mojom::Feature::kEche,
mojom::FeatureState::kNotSupportedByPhone);
SetSoftwareFeatureState(false /* use_local_device */,
multidevice::SoftwareFeature::kPhoneHubHost,
multidevice::SoftwareFeatureState::kEnabled);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByChromebook,
mojom::Feature::kEche);
VerifyFeatureStateChange(3u /* expected_index */, mojom::Feature::kEche,
mojom::FeatureState::kNotSupportedByChromebook);
SetSoftwareFeatureState(true /* use_local_device */,
multidevice::SoftwareFeature::kEcheClient,
multidevice::SoftwareFeatureState::kSupported);
VerifyFeatureStateChange(4u /* expected_index */, mojom::Feature::kEche,
mojom::FeatureState::kNotSupportedByPhone);
// The top-level Phone Hub enabled pref is disabled for existing Better
// Together users; they must go to settings to explicitly enable PhoneHub.
test_pref_service()->SetBoolean(kEcheEnabledPrefName, true);
SetSoftwareFeatureState(false /* use_local_device */,
multidevice::SoftwareFeature::kEcheHost,
multidevice::SoftwareFeatureState::kSupported);
VerifyFeatureState(mojom::FeatureState::kUnavailableTopLevelFeatureDisabled,
mojom::Feature::kEche);
VerifyFeatureStateChange(
5u /* expected_index */, mojom::Feature::kEche,
mojom::FeatureState::kUnavailableTopLevelFeatureDisabled);
test_pref_service()->SetBoolean(kPhoneHubEnabledPrefName, true);
VerifyFeatureState(mojom::FeatureState::kEnabledByUser,
mojom::Feature::kEche);
VerifyFeatureStateChange(6u /* expected_index */, mojom::Feature::kEche,
mojom::FeatureState::kEnabledByUser);
// Simulate messages received from PhoneHub which communicate Eche support.
// No feature state change should occur yet.
test_pref_service()->SetInteger(
kEcheOverriddenSupportReceivedFromPhoneHubPrefName,
static_cast<int>(EcheSupportReceivedFromPhoneHub::kNotSpecified));
VerifyFeatureState(mojom::FeatureState::kEnabledByUser,
mojom::Feature::kEche);
// When the PhoneHub message does not specify support, the value of
// SoftwareFeature::kEcheHost is consulted, like other features.
SetSoftwareFeatureState(false /* use_local_device */,
multidevice::SoftwareFeature::kEcheHost,
multidevice::SoftwareFeatureState::kNotSupported);
VerifyFeatureState(mojom::FeatureState::kNotSupportedByPhone,
mojom::Feature::kEche);
VerifyFeatureStateChange(7u /* expected_index */, mojom::Feature::kEche,
mojom::FeatureState::kNotSupportedByPhone);
// Receiving signal of Eche support from PhoneHub should override the value
// of SoftwareFeature::kEcheHost.
test_pref_service()->SetInteger(
kEcheOverriddenSupportReceivedFromPhoneHubPrefName,
static_cast<int>(EcheSupportReceivedFromPhoneHub::kSupported));
VerifyFeatureState(mojom::FeatureState::kEnabledByUser,
mojom::Feature::kEche);
VerifyFeatureStateChange(8u /* expected_index */, mojom::Feature::kEche,
mojom::FeatureState::kEnabledByUser);
// Return SoftwareFeature::kEcheHost to "supported" to prepare for next
// change, but no feature state change should occur yet.
SetSoftwareFeatureState(false /* use_local_device */,
multidevice::SoftwareFeature::kEcheHost,
multidevice::SoftwareFeatureState::kSupported);
VerifyFeatureState(mojom::FeatureState::kEnabledByUser,
mojom::Feature::kEche);
// Receiving signal of Eche support from PhoneHub should override the value
// of SoftwareFeature::kEcheHost.
test_pref_service()->SetInteger(
kEcheOverriddenSupportReceivedFromPhoneHubPrefName,
static_cast<int>(EcheSupportReceivedFromPhoneHub::kNotSupported));
VerifyFeatureState(mojom::FeatureState::kNotSupportedByPhone,
mojom::Feature::kEche);
VerifyFeatureStateChange(9u /* expected_index */, mojom::Feature::kEche,
mojom::FeatureState::kNotSupportedByPhone);
}
} // namespace multidevice_setup
} // namespace ash