quick_pair_metrics_logger.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. // Copyright 2021 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/quick_pair/keyed_service/quick_pair_metrics_logger.h"
  5. #include "ash/quick_pair/common/device.h"
  6. #include "ash/quick_pair/common/fast_pair/fast_pair_feature_usage_metrics_logger.h"
  7. #include "ash/quick_pair/common/fast_pair/fast_pair_metrics.h"
  8. #include "ash/quick_pair/common/logging.h"
  9. #include "base/containers/contains.h"
  10. #include "device/bluetooth/bluetooth_adapter_factory.h"
  11. namespace ash {
  12. namespace quick_pair {
  13. QuickPairMetricsLogger::QuickPairMetricsLogger(
  14. ScannerBroker* scanner_broker,
  15. PairerBroker* pairer_broker,
  16. UIBroker* ui_broker,
  17. RetroactivePairingDetector* retroactive_pairing_detector)
  18. : feature_usage_metrics_logger_(
  19. std::make_unique<FastPairFeatureUsageMetricsLogger>()) {
  20. device::BluetoothAdapterFactory::Get()->GetAdapter(base::BindOnce(
  21. &QuickPairMetricsLogger::OnGetAdapter, weak_ptr_factory_.GetWeakPtr()));
  22. scanner_broker_observation_.Observe(scanner_broker);
  23. retroactive_pairing_detector_observation_.Observe(
  24. retroactive_pairing_detector);
  25. pairer_broker_observation_.Observe(pairer_broker);
  26. ui_broker_observation_.Observe(ui_broker);
  27. }
  28. QuickPairMetricsLogger::~QuickPairMetricsLogger() = default;
  29. void QuickPairMetricsLogger::OnGetAdapter(
  30. scoped_refptr<device::BluetoothAdapter> adapter) {
  31. adapter_ = adapter;
  32. adapter_observation_.Observe(adapter_.get());
  33. }
  34. void QuickPairMetricsLogger::DevicePairedChanged(
  35. device::BluetoothAdapter* adapter,
  36. device::BluetoothDevice* device,
  37. bool new_paired_status) {
  38. // This event fires whenever a device pairing has changed with the adapter.
  39. // If the |new_paired_status| is false, it means a device was unpaired with
  40. // the adapter, so we early return since it would not be a device that has
  41. // been paired alternatively. If the device that was paired to that fires this
  42. // event is a device we just paired to with Fast Pair, then we early return
  43. // since it also wouldn't be one that was alternatively pair to. We want to
  44. // only continue our check here if we have a newly paired device that was
  45. // paired with classic Bluetooth pairing.
  46. const std::string& classic_address = device->GetAddress();
  47. if (!new_paired_status ||
  48. base::Contains(fast_pair_addresses_, classic_address)) {
  49. return;
  50. }
  51. RecordPairingMethod(PairingMethod::kSystemPairingUi);
  52. }
  53. void QuickPairMetricsLogger::OnDevicePaired(scoped_refptr<Device> device) {
  54. AttemptRecordingFastPairEngagementFlow(
  55. *device, FastPairEngagementFlowEvent::kPairingSucceeded);
  56. RecordPairingResult(*device, /*success=*/true);
  57. feature_usage_metrics_logger_->RecordUsage(/*success=*/true);
  58. base::TimeDelta total_pair_time =
  59. base::TimeTicks::Now() - device_pairing_start_timestamps_[device];
  60. AttemptRecordingTotalUxPairTime(*device, total_pair_time);
  61. RecordPairingMethod(PairingMethod::kFastPair);
  62. // The classic address is assigned to the Device during the
  63. // initial Fast Pair pairing protocol during the key exchange, and if it
  64. // doesn't exist, then it wasn't properly paired during initial Fast Pair
  65. // pairing. We want to save the addresses here in the event that the
  66. // Bluetooth adapter pairing event fires, so we can detect when a device
  67. // was paired solely via classic bluetooth, instead of Fast Pair.
  68. if (device->classic_address())
  69. fast_pair_addresses_.insert(device->classic_address().value());
  70. }
  71. void QuickPairMetricsLogger::OnPairFailure(scoped_refptr<Device> device,
  72. PairFailure failure) {
  73. AttemptRecordingFastPairEngagementFlow(
  74. *device, FastPairEngagementFlowEvent::kPairingFailed);
  75. base::TimeDelta total_pair_time =
  76. base::TimeTicks::Now() - device_pairing_start_timestamps_[device];
  77. device_pairing_start_timestamps_.erase(device);
  78. AttemptRecordingTotalUxPairTime(*device, total_pair_time);
  79. feature_usage_metrics_logger_->RecordUsage(/*success=*/false);
  80. RecordPairingFailureReason(*device, failure);
  81. RecordPairingResult(*device, /*success=*/false);
  82. }
  83. void QuickPairMetricsLogger::OnDiscoveryAction(scoped_refptr<Device> device,
  84. DiscoveryAction action) {
  85. switch (action) {
  86. case DiscoveryAction::kPairToDevice:
  87. if (base::Contains(discovery_learn_more_devices_, device)) {
  88. AttemptRecordingFastPairEngagementFlow(
  89. *device, FastPairEngagementFlowEvent::
  90. kDiscoveryUiConnectPressedAfterLearnMorePressed);
  91. discovery_learn_more_devices_.erase(device);
  92. break;
  93. }
  94. AttemptRecordingFastPairEngagementFlow(
  95. *device, FastPairEngagementFlowEvent::kDiscoveryUiConnectPressed);
  96. device_pairing_start_timestamps_[device] = base::TimeTicks::Now();
  97. break;
  98. case DiscoveryAction::kLearnMore:
  99. // We need to record whether or not the Discovery UI for this
  100. // device has had the Learn More button pressed because since the
  101. // Learn More button is not a terminal state, we need to record
  102. // if the subsequent terminal states were reached after the user
  103. // has learned more about saving their accounts. So we will check
  104. // this map when the user dismisses or saves their account in order
  105. // to capture whether or not the user elected to learn more beforehand.
  106. discovery_learn_more_devices_.insert(device);
  107. AttemptRecordingFastPairEngagementFlow(
  108. *device, FastPairEngagementFlowEvent::kDiscoveryUiLearnMorePressed);
  109. break;
  110. case DiscoveryAction::kDismissedByUser:
  111. if (base::Contains(discovery_learn_more_devices_, device)) {
  112. AttemptRecordingFastPairEngagementFlow(
  113. *device, FastPairEngagementFlowEvent::
  114. kDiscoveryUiDismissedByUserAfterLearnMorePressed);
  115. discovery_learn_more_devices_.erase(device);
  116. break;
  117. }
  118. AttemptRecordingFastPairEngagementFlow(
  119. *device, FastPairEngagementFlowEvent::kDiscoveryUiDismissedByUser);
  120. break;
  121. case DiscoveryAction::kDismissed:
  122. if (base::Contains(discovery_learn_more_devices_, device)) {
  123. AttemptRecordingFastPairEngagementFlow(
  124. *device, FastPairEngagementFlowEvent::
  125. kDiscoveryUiDismissedAfterLearnMorePressed);
  126. discovery_learn_more_devices_.erase(device);
  127. break;
  128. }
  129. AttemptRecordingFastPairEngagementFlow(
  130. *device, FastPairEngagementFlowEvent::kDiscoveryUiDismissed);
  131. break;
  132. }
  133. }
  134. void QuickPairMetricsLogger::OnPairingFailureAction(
  135. scoped_refptr<Device> device,
  136. PairingFailedAction action) {
  137. switch (action) {
  138. case PairingFailedAction::kNavigateToSettings:
  139. AttemptRecordingFastPairEngagementFlow(
  140. *device, FastPairEngagementFlowEvent::kErrorUiSettingsPressed);
  141. break;
  142. case PairingFailedAction::kDismissedByUser:
  143. AttemptRecordingFastPairEngagementFlow(
  144. *device, FastPairEngagementFlowEvent::kErrorUiDismissedByUser);
  145. break;
  146. case PairingFailedAction::kDismissed:
  147. AttemptRecordingFastPairEngagementFlow(
  148. *device, FastPairEngagementFlowEvent::kErrorUiDismissed);
  149. break;
  150. }
  151. }
  152. void QuickPairMetricsLogger::OnDeviceFound(scoped_refptr<Device> device) {
  153. AttemptRecordingFastPairEngagementFlow(
  154. *device, FastPairEngagementFlowEvent::kDiscoveryUiShown);
  155. }
  156. void QuickPairMetricsLogger::OnRetroactivePairFound(
  157. scoped_refptr<Device> device) {
  158. AttemptRecordingFastPairRetroactiveEngagementFlow(
  159. *device,
  160. FastPairRetroactiveEngagementFlowEvent::kAssociateAccountUiShown);
  161. }
  162. void QuickPairMetricsLogger::OnAssociateAccountAction(
  163. scoped_refptr<Device> device,
  164. AssociateAccountAction action) {
  165. switch (action) {
  166. case AssociateAccountAction::kAssoicateAccount:
  167. if (base::Contains(associate_account_learn_more_devices_, device)) {
  168. AttemptRecordingFastPairRetroactiveEngagementFlow(
  169. *device, FastPairRetroactiveEngagementFlowEvent::
  170. kAssociateAccountSavePressedAfterLearnMorePressed);
  171. associate_account_learn_more_devices_.erase(device);
  172. break;
  173. }
  174. AttemptRecordingFastPairRetroactiveEngagementFlow(
  175. *device,
  176. FastPairRetroactiveEngagementFlowEvent::kAssociateAccountSavePressed);
  177. break;
  178. case AssociateAccountAction::kLearnMore:
  179. // We need to record whether or not the Associate Account UI for this
  180. // device has had the Learn More button pressed because since the
  181. // Learn More button is not a terminal state, we need to record
  182. // if the subsequent terminal states were reached after the user
  183. // has learned more about saving their accounts. So we will check
  184. // this map when the user dismisses or saves their account in order
  185. // to capture whether or not the user elected to learn more beforehand.
  186. associate_account_learn_more_devices_.insert(device);
  187. AttemptRecordingFastPairRetroactiveEngagementFlow(
  188. *device, FastPairRetroactiveEngagementFlowEvent::
  189. kAssociateAccountLearnMorePressed);
  190. break;
  191. case AssociateAccountAction::kDismissedByUser:
  192. if (base::Contains(associate_account_learn_more_devices_, device)) {
  193. AttemptRecordingFastPairRetroactiveEngagementFlow(
  194. *device, FastPairRetroactiveEngagementFlowEvent::
  195. kAssociateAccountDismissedByUserAfterLearnMorePressed);
  196. associate_account_learn_more_devices_.erase(device);
  197. break;
  198. }
  199. AttemptRecordingFastPairRetroactiveEngagementFlow(
  200. *device, FastPairRetroactiveEngagementFlowEvent::
  201. kAssociateAccountUiDismissedByUser);
  202. break;
  203. case AssociateAccountAction::kDismissed:
  204. if (base::Contains(associate_account_learn_more_devices_, device)) {
  205. AttemptRecordingFastPairRetroactiveEngagementFlow(
  206. *device, FastPairRetroactiveEngagementFlowEvent::
  207. kAssociateAccountDismissedAfterLearnMorePressed);
  208. associate_account_learn_more_devices_.erase(device);
  209. break;
  210. }
  211. AttemptRecordingFastPairRetroactiveEngagementFlow(
  212. *device,
  213. FastPairRetroactiveEngagementFlowEvent::kAssociateAccountUiDismissed);
  214. break;
  215. }
  216. }
  217. void QuickPairMetricsLogger::OnAccountKeyWrite(
  218. scoped_refptr<Device> device,
  219. absl::optional<AccountKeyFailure> error) {
  220. if (device->protocol == Protocol::kFastPairRetroactive)
  221. RecordRetroactivePairingResult(/*success=*/!error.has_value());
  222. if (error.has_value()) {
  223. RecordAccountKeyResult(*device, /*success=*/false);
  224. RecordAccountKeyFailureReason(*device, error.value());
  225. feature_usage_metrics_logger_->RecordUsage(/*success=*/false);
  226. return;
  227. }
  228. RecordAccountKeyResult(*device, /*success=*/true);
  229. feature_usage_metrics_logger_->RecordUsage(/*success=*/true);
  230. }
  231. void QuickPairMetricsLogger::OnCompanionAppAction(scoped_refptr<Device> device,
  232. CompanionAppAction action) {}
  233. void QuickPairMetricsLogger::OnDeviceLost(scoped_refptr<Device> device) {}
  234. } // namespace quick_pair
  235. } // namespace ash