account_status_change_delegate_notifier_impl.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. // Copyright 2018 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/services/multidevice_setup/account_status_change_delegate_notifier_impl.h"
  5. #include <set>
  6. #include <utility>
  7. #include "ash/components/multidevice/logging/logging.h"
  8. #include "ash/services/multidevice_setup/host_device_timestamp_manager.h"
  9. #include "ash/services/multidevice_setup/host_status_provider_impl.h"
  10. #include "base/memory/ptr_util.h"
  11. #include "base/time/clock.h"
  12. #include "components/prefs/pref_registry_simple.h"
  13. #include "components/prefs/pref_service.h"
  14. namespace ash {
  15. namespace multidevice_setup {
  16. namespace {
  17. const int64_t kTimestampNotSet = 0;
  18. const char kNoHost[] = "";
  19. } // namespace
  20. // static
  21. AccountStatusChangeDelegateNotifierImpl::Factory*
  22. AccountStatusChangeDelegateNotifierImpl::Factory::test_factory_ = nullptr;
  23. // static
  24. std::unique_ptr<AccountStatusChangeDelegateNotifier>
  25. AccountStatusChangeDelegateNotifierImpl::Factory::Create(
  26. HostStatusProvider* host_status_provider,
  27. PrefService* pref_service,
  28. HostDeviceTimestampManager* host_device_timestamp_manager,
  29. OobeCompletionTracker* oobe_completion_tracker,
  30. base::Clock* clock) {
  31. if (test_factory_) {
  32. return test_factory_->CreateInstance(host_status_provider, pref_service,
  33. host_device_timestamp_manager,
  34. oobe_completion_tracker, clock);
  35. }
  36. return base::WrapUnique(new AccountStatusChangeDelegateNotifierImpl(
  37. host_status_provider, pref_service, host_device_timestamp_manager,
  38. oobe_completion_tracker, clock));
  39. }
  40. // static
  41. void AccountStatusChangeDelegateNotifierImpl::Factory::SetFactoryForTesting(
  42. Factory* test_factory) {
  43. test_factory_ = test_factory;
  44. }
  45. AccountStatusChangeDelegateNotifierImpl::Factory::~Factory() = default;
  46. // static
  47. void AccountStatusChangeDelegateNotifierImpl::RegisterPrefs(
  48. PrefRegistrySimple* registry) {
  49. // Records the timestamps (in milliseconds since UNIX Epoch, aka JavaTime) of
  50. // the last instance the delegate was notified for each of the changes listed
  51. // in the class description.
  52. registry->RegisterInt64Pref(kNewUserPotentialHostExistsPrefName,
  53. kTimestampNotSet);
  54. registry->RegisterInt64Pref(kExistingUserHostSwitchedPrefName,
  55. kTimestampNotSet);
  56. registry->RegisterInt64Pref(kExistingUserChromebookAddedPrefName,
  57. kTimestampNotSet);
  58. registry->RegisterInt64Pref(kOobeSetupFlowTimestampPrefName,
  59. kTimestampNotSet);
  60. registry->RegisterStringPref(
  61. kVerifiedHostDeviceIdFromMostRecentHostStatusUpdatePrefName, kNoHost);
  62. }
  63. AccountStatusChangeDelegateNotifierImpl::
  64. ~AccountStatusChangeDelegateNotifierImpl() {
  65. host_status_provider_->RemoveObserver(this);
  66. oobe_completion_tracker_->RemoveObserver(this);
  67. }
  68. void AccountStatusChangeDelegateNotifierImpl::OnDelegateSet() {
  69. CheckForMultiDeviceEvents(host_status_provider_->GetHostWithStatus());
  70. }
  71. // static
  72. const char AccountStatusChangeDelegateNotifierImpl::
  73. kNewUserPotentialHostExistsPrefName[] =
  74. "multidevice_setup.new_user_potential_host_exists";
  75. // static
  76. const char AccountStatusChangeDelegateNotifierImpl::
  77. kExistingUserHostSwitchedPrefName[] =
  78. "multidevice_setup.existing_user_host_switched";
  79. // static
  80. const char AccountStatusChangeDelegateNotifierImpl::
  81. kExistingUserChromebookAddedPrefName[] =
  82. "multidevice_setup.existing_user_chromebook_added";
  83. // Note that, despite the pref string name, this pref only records the IDs of
  84. // verified hosts. In particular, if a host has been set but is waiting for
  85. // verification, it will not recorded.
  86. // static
  87. const char AccountStatusChangeDelegateNotifierImpl::
  88. kVerifiedHostDeviceIdFromMostRecentHostStatusUpdatePrefName[] =
  89. "multidevice_setup.host_device_id_from_most_recent_sync";
  90. // The timestamps (in milliseconds since UNIX Epoch, aka JavaTime) of the user
  91. // seeing setup flow in OOBE. If it is 0, the user did not see the setup flow in
  92. // OOBE.
  93. // static
  94. const char
  95. AccountStatusChangeDelegateNotifierImpl::kOobeSetupFlowTimestampPrefName[] =
  96. "multidevice_setup.oobe_setup_flow_timestamp ";
  97. AccountStatusChangeDelegateNotifierImpl::
  98. AccountStatusChangeDelegateNotifierImpl(
  99. HostStatusProvider* host_status_provider,
  100. PrefService* pref_service,
  101. HostDeviceTimestampManager* host_device_timestamp_manager,
  102. OobeCompletionTracker* oobe_completion_tracker,
  103. base::Clock* clock)
  104. : host_status_provider_(host_status_provider),
  105. pref_service_(pref_service),
  106. host_device_timestamp_manager_(host_device_timestamp_manager),
  107. oobe_completion_tracker_(oobe_completion_tracker),
  108. clock_(clock) {
  109. verified_host_device_id_from_most_recent_update_ =
  110. LoadHostDeviceIdFromEndOfPreviousSession();
  111. host_status_provider_->AddObserver(this);
  112. oobe_completion_tracker_->AddObserver(this);
  113. }
  114. void AccountStatusChangeDelegateNotifierImpl::OnHostStatusChange(
  115. const HostStatusProvider::HostStatusWithDevice& host_status_with_device) {
  116. CheckForMultiDeviceEvents(host_status_with_device);
  117. }
  118. void AccountStatusChangeDelegateNotifierImpl::OnOobeCompleted() {
  119. pref_service_->SetInt64(kOobeSetupFlowTimestampPrefName,
  120. clock_->Now().ToJavaTime());
  121. if (delegate())
  122. delegate()->OnNoLongerNewUser();
  123. }
  124. void AccountStatusChangeDelegateNotifierImpl::CheckForMultiDeviceEvents(
  125. const HostStatusProvider::HostStatusWithDevice& host_status_with_device) {
  126. if (!delegate()) {
  127. PA_LOG(WARNING)
  128. << "AccountStatusChangeDelegateNotifierImpl::"
  129. << "CheckForMultiDeviceEvents(): Tried to check for potential "
  130. << "events, but no delegate was set.";
  131. return;
  132. }
  133. // Track and update host status.
  134. absl::optional<mojom::HostStatus> host_status_before_update =
  135. host_status_from_most_recent_update_;
  136. host_status_from_most_recent_update_ = host_status_with_device.host_status();
  137. // Track and update verified host info.
  138. absl::optional<std::string> verified_host_device_id_before_update =
  139. verified_host_device_id_from_most_recent_update_;
  140. // Check if a host has been verified.
  141. if (host_status_with_device.host_status() ==
  142. mojom::HostStatus::kHostVerified) {
  143. verified_host_device_id_from_most_recent_update_ =
  144. host_status_with_device.host_device()->GetDeviceId();
  145. pref_service_->SetString(
  146. kVerifiedHostDeviceIdFromMostRecentHostStatusUpdatePrefName,
  147. *verified_host_device_id_from_most_recent_update_);
  148. } else {
  149. // No host set.
  150. verified_host_device_id_from_most_recent_update_.reset();
  151. pref_service_->SetString(
  152. kVerifiedHostDeviceIdFromMostRecentHostStatusUpdatePrefName, kNoHost);
  153. }
  154. CheckForNewUserPotentialHostExistsEvent(host_status_with_device);
  155. CheckForNoLongerNewUserEvent(host_status_with_device,
  156. host_status_before_update);
  157. CheckForExistingUserHostSwitchedEvent(host_status_with_device,
  158. verified_host_device_id_before_update);
  159. CheckForExistingUserChromebookAddedEvent(
  160. host_status_with_device, verified_host_device_id_before_update);
  161. }
  162. void AccountStatusChangeDelegateNotifierImpl::
  163. CheckForNewUserPotentialHostExistsEvent(
  164. const HostStatusProvider::HostStatusWithDevice&
  165. host_status_with_device) {
  166. // We do not notify the user if they already had a chance to go through setup
  167. // flow in OOBE.
  168. if (pref_service_->GetInt64(kOobeSetupFlowTimestampPrefName) !=
  169. kTimestampNotSet) {
  170. return;
  171. }
  172. // We only check for new user events if there is no enabled host.
  173. if (verified_host_device_id_from_most_recent_update_)
  174. return;
  175. // If the observer has been notified of a potential verified host in the past,
  176. // they are not considered a new user.
  177. if (pref_service_->GetInt64(kNewUserPotentialHostExistsPrefName) !=
  178. kTimestampNotSet ||
  179. pref_service_->GetInt64(kExistingUserChromebookAddedPrefName) !=
  180. kTimestampNotSet) {
  181. return;
  182. }
  183. // kEligibleHostExistsButNoHostSet is the only HostStatus that can describe
  184. // a new user.
  185. if (host_status_with_device.host_status() !=
  186. mojom::HostStatus::kEligibleHostExistsButNoHostSet) {
  187. return;
  188. }
  189. delegate()->OnPotentialHostExistsForNewUser();
  190. pref_service_->SetInt64(kNewUserPotentialHostExistsPrefName,
  191. clock_->Now().ToJavaTime());
  192. }
  193. void AccountStatusChangeDelegateNotifierImpl::CheckForNoLongerNewUserEvent(
  194. const HostStatusProvider::HostStatusWithDevice& host_status_with_device,
  195. const absl::optional<mojom::HostStatus> host_status_before_update) {
  196. // We are only looking for the case when the host status switched from
  197. // kEligibleHostExistsButNoHostSet to something else.
  198. if (host_status_with_device.host_status() ==
  199. mojom::HostStatus::kEligibleHostExistsButNoHostSet ||
  200. host_status_before_update !=
  201. mojom::HostStatus::kEligibleHostExistsButNoHostSet) {
  202. return;
  203. }
  204. // If the user has ever had a verified host, they have already left the 'new
  205. // user' state.
  206. if (pref_service_->GetInt64(kExistingUserChromebookAddedPrefName) !=
  207. kTimestampNotSet) {
  208. return;
  209. }
  210. delegate()->OnNoLongerNewUser();
  211. }
  212. void AccountStatusChangeDelegateNotifierImpl::
  213. CheckForExistingUserHostSwitchedEvent(
  214. const HostStatusProvider::HostStatusWithDevice& host_status_with_device,
  215. const absl::optional<std::string>&
  216. verified_host_device_id_before_update) {
  217. // The host switched event requires both a pre-update and a post-update
  218. // verified host.
  219. if (!verified_host_device_id_from_most_recent_update_ ||
  220. !verified_host_device_id_before_update) {
  221. return;
  222. }
  223. // If the host stayed the same, there was no switch.
  224. if (*verified_host_device_id_from_most_recent_update_ ==
  225. *verified_host_device_id_before_update) {
  226. return;
  227. }
  228. delegate()->OnConnectedHostSwitchedForExistingUser(
  229. host_status_with_device.host_device()->name());
  230. pref_service_->SetInt64(kExistingUserHostSwitchedPrefName,
  231. clock_->Now().ToJavaTime());
  232. }
  233. void AccountStatusChangeDelegateNotifierImpl::
  234. CheckForExistingUserChromebookAddedEvent(
  235. const HostStatusProvider::HostStatusWithDevice& host_status_with_device,
  236. const absl::optional<std::string>&
  237. verified_host_device_id_before_update) {
  238. // The Chromebook added event requires that a verified host was found by the
  239. // update, i.e. there was no verified host before the host status update but
  240. // afterward there was a verified host.
  241. if (!verified_host_device_id_from_most_recent_update_ ||
  242. verified_host_device_id_before_update) {
  243. return;
  244. }
  245. // This event is specific to setup taking place on a different Chromebook.
  246. if (host_device_timestamp_manager_->WasHostSetFromThisChromebook())
  247. return;
  248. delegate()->OnNewChromebookAddedForExistingUser(
  249. host_status_with_device.host_device()->name());
  250. pref_service_->SetInt64(kExistingUserChromebookAddedPrefName,
  251. clock_->Now().ToJavaTime());
  252. }
  253. absl::optional<std::string> AccountStatusChangeDelegateNotifierImpl::
  254. LoadHostDeviceIdFromEndOfPreviousSession() {
  255. std::string verified_host_device_id_from_most_recent_update =
  256. pref_service_->GetString(
  257. kVerifiedHostDeviceIdFromMostRecentHostStatusUpdatePrefName);
  258. if (verified_host_device_id_from_most_recent_update.empty())
  259. return absl::nullopt;
  260. return verified_host_device_id_from_most_recent_update;
  261. }
  262. } // namespace multidevice_setup
  263. } // namespace ash