eche_feature_status_provider.cc 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/webui/eche_app_ui/eche_feature_status_provider.h"
  5. #include "ash/components/multidevice/logging/logging.h"
  6. #include "ash/components/multidevice/remote_device_ref.h"
  7. #include "ash/components/multidevice/software_feature.h"
  8. #include "ash/components/multidevice/software_feature_state.h"
  9. #include "ash/components/phonehub/feature_status.h"
  10. #include "ash/components/phonehub/phone_hub_manager.h"
  11. #include "ash/services/device_sync/public/cpp/device_sync_client.h"
  12. namespace ash {
  13. namespace eche_app {
  14. namespace {
  15. using multidevice::RemoteDeviceRef;
  16. using multidevice::RemoteDeviceRefList;
  17. using multidevice::SoftwareFeature;
  18. using multidevice::SoftwareFeatureState;
  19. using multidevice_setup::mojom::Feature;
  20. using multidevice_setup::mojom::FeatureState;
  21. using multidevice_setup::mojom::HostStatus;
  22. bool IsEnabledHost(const RemoteDeviceRef& device) {
  23. return device.GetSoftwareFeatureState(SoftwareFeature::kBetterTogetherHost) !=
  24. SoftwareFeatureState::kNotSupported &&
  25. device.GetSoftwareFeatureState(SoftwareFeature::kEcheHost) ==
  26. SoftwareFeatureState::kEnabled;
  27. }
  28. bool IsEligibleForFeature(
  29. const absl::optional<RemoteDeviceRef>& local_device,
  30. multidevice_setup::MultiDeviceSetupClient::HostStatusWithDevice host_status,
  31. const RemoteDeviceRefList& remote_devices,
  32. FeatureState feature_state) {
  33. if (feature_state == FeatureState::kProhibitedByPolicy)
  34. return false;
  35. if (feature_state == FeatureState::kNotSupportedByPhone)
  36. return false;
  37. if (!local_device)
  38. return false;
  39. if (local_device->GetSoftwareFeatureState(SoftwareFeature::kEcheClient) ==
  40. SoftwareFeatureState::kNotSupported)
  41. return false;
  42. if (host_status.first == HostStatus::kNoEligibleHosts)
  43. return false;
  44. if (host_status.second.has_value()) {
  45. return IsEnabledHost(*(host_status.second));
  46. }
  47. for (const RemoteDeviceRef& device : remote_devices) {
  48. if (IsEnabledHost(device))
  49. return true;
  50. }
  51. return false;
  52. }
  53. bool IsFeatureDisabledByUser(FeatureState feature_state) {
  54. return feature_state == FeatureState::kDisabledByUser ||
  55. feature_state == FeatureState::kUnavailableSuiteDisabled ||
  56. feature_state == FeatureState::kUnavailableTopLevelFeatureDisabled;
  57. }
  58. } // namespace
  59. EcheFeatureStatusProvider::EcheFeatureStatusProvider(
  60. phonehub::PhoneHubManager* phone_hub_manager,
  61. device_sync::DeviceSyncClient* device_sync_client,
  62. multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client,
  63. secure_channel::ConnectionManager* connection_manager)
  64. : phone_hub_feature_status_provider_(
  65. phone_hub_manager->GetFeatureStatusProvider()),
  66. device_sync_client_(device_sync_client),
  67. multidevice_setup_client_(multidevice_setup_client),
  68. connection_manager_(connection_manager),
  69. current_phone_hub_feature_status_(
  70. phone_hub_feature_status_provider_->GetStatus()),
  71. status_(ComputeStatus()) {
  72. phone_hub_feature_status_provider_->AddObserver(this);
  73. connection_manager_->AddObserver(this);
  74. multidevice_setup_client_->AddObserver(this);
  75. }
  76. EcheFeatureStatusProvider::~EcheFeatureStatusProvider() {
  77. phone_hub_feature_status_provider_->RemoveObserver(this);
  78. connection_manager_->RemoveObserver(this);
  79. multidevice_setup_client_->RemoveObserver(this);
  80. }
  81. FeatureStatus EcheFeatureStatusProvider::GetStatus() const {
  82. return *status_;
  83. }
  84. // Listening for changes in Phone Hub state.
  85. void EcheFeatureStatusProvider::OnFeatureStatusChanged() {
  86. current_phone_hub_feature_status_ =
  87. phone_hub_feature_status_provider_->GetStatus();
  88. UpdateStatus();
  89. }
  90. void EcheFeatureStatusProvider::OnConnectionStatusChanged() {
  91. UpdateStatus();
  92. }
  93. void EcheFeatureStatusProvider::OnHostStatusChanged(
  94. const multidevice_setup::MultiDeviceSetupClient::HostStatusWithDevice&
  95. host_device_with_status) {
  96. UpdateStatus();
  97. }
  98. void EcheFeatureStatusProvider::OnFeatureStatesChanged(
  99. const multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap&
  100. feature_states_map) {
  101. UpdateStatus();
  102. }
  103. void EcheFeatureStatusProvider::UpdateStatus() {
  104. DCHECK(status_.has_value());
  105. FeatureStatus computed_status = ComputeStatus();
  106. if (computed_status == *status_)
  107. return;
  108. PA_LOG(INFO) << "Eche feature status: " << *status_ << " => "
  109. << computed_status;
  110. *status_ = computed_status;
  111. NotifyStatusChanged();
  112. }
  113. FeatureStatus EcheFeatureStatusProvider::ComputeStatus() {
  114. // If PhoneHub is in some degree of unavailability, return that Eche is
  115. // unavailable.
  116. switch (current_phone_hub_feature_status_) {
  117. case phonehub::FeatureStatus::kNotEligibleForFeature:
  118. [[fallthrough]];
  119. case phonehub::FeatureStatus::kEligiblePhoneButNotSetUp:
  120. [[fallthrough]];
  121. case phonehub::FeatureStatus::kPhoneSelectedAndPendingSetup:
  122. [[fallthrough]];
  123. case phonehub::FeatureStatus::kDisabled:
  124. [[fallthrough]];
  125. case phonehub::FeatureStatus::kUnavailableBluetoothOff:
  126. return FeatureStatus::kDependentFeature;
  127. case phonehub::FeatureStatus::kEnabledAndConnecting:
  128. [[fallthrough]];
  129. case phonehub::FeatureStatus::kEnabledButDisconnected:
  130. [[fallthrough]];
  131. // The device is in a suspended state.
  132. case phonehub::FeatureStatus::kLockOrSuspended:
  133. return FeatureStatus::kDependentFeaturePending;
  134. case phonehub::FeatureStatus::kEnabledAndConnected:
  135. break;
  136. }
  137. FeatureState feature_state =
  138. multidevice_setup_client_->GetFeatureState(Feature::kEche);
  139. if (!device_sync_client_->is_ready()) {
  140. return FeatureStatus::kIneligible;
  141. }
  142. if (!IsEligibleForFeature(device_sync_client_->GetLocalDeviceMetadata(),
  143. multidevice_setup_client_->GetHostStatus(),
  144. device_sync_client_->GetSyncedDevices(),
  145. feature_state)) {
  146. return FeatureStatus::kIneligible;
  147. }
  148. if (IsFeatureDisabledByUser(feature_state))
  149. return FeatureStatus::kDisabled;
  150. switch (connection_manager_->GetStatus()) {
  151. case secure_channel::ConnectionManager::Status::kDisconnected:
  152. return FeatureStatus::kDisconnected;
  153. case secure_channel::ConnectionManager::Status::kConnecting:
  154. return FeatureStatus::kConnecting;
  155. case secure_channel::ConnectionManager::Status::kConnected:
  156. return FeatureStatus::kConnected;
  157. }
  158. PA_LOG(INFO) << "Unexpected feature status state, returning default";
  159. return FeatureStatus::kDisconnected;
  160. }
  161. } // namespace eche_app
  162. } // namespace ash