recent_apps_interaction_handler_impl_unittest.cc 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  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/components/phonehub/recent_apps_interaction_handler_impl.h"
  5. #include <memory>
  6. #include "ash/components/phonehub/fake_multidevice_feature_access_manager.h"
  7. #include "ash/components/phonehub/icon_decoder.h"
  8. #include "ash/components/phonehub/icon_decoder_impl.h"
  9. #include "ash/components/phonehub/notification.h"
  10. #include "ash/components/phonehub/pref_names.h"
  11. #include "ash/constants/ash_features.h"
  12. #include "ash/services/multidevice_setup/public/cpp/fake_multidevice_setup_client.h"
  13. #include "ash/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
  14. #include "base/test/scoped_feature_list.h"
  15. #include "components/prefs/testing_pref_service.h"
  16. #include "testing/gtest/include/gtest/gtest.h"
  17. #include "third_party/skia/include/core/SkColor.h"
  18. namespace ash {
  19. namespace phonehub {
  20. namespace {
  21. using FeatureState = multidevice_setup::mojom::FeatureState;
  22. using HostStatus = multidevice_setup::mojom::HostStatus;
  23. // Garbage color for the purpose of verification in these tests.
  24. const SkColor kIconColor = SkColorSetRGB(0x12, 0x34, 0x56);
  25. const char kIconColorR[] = "icon_color_r";
  26. const char kIconColorG[] = "icon_color_g";
  27. const char kIconColorB[] = "icon_color_b";
  28. const char kIconIsMonochrome[] = "icon_is_monochrome";
  29. class FakeClickHandler : public RecentAppClickObserver {
  30. public:
  31. FakeClickHandler() = default;
  32. ~FakeClickHandler() override = default;
  33. std::string get_package_name() { return package_name; }
  34. void OnRecentAppClicked(
  35. const Notification::AppMetadata& app_metadata) override {
  36. package_name = app_metadata.package_name;
  37. }
  38. private:
  39. std::string package_name;
  40. };
  41. } // namespace
  42. class RecentAppsInteractionHandlerTest : public testing::Test {
  43. class TestDecoderDelegate : public IconDecoderImpl::DecoderDelegate {
  44. public:
  45. TestDecoderDelegate() = default;
  46. ~TestDecoderDelegate() override = default;
  47. void Decode(const IconDecoder::DecodingData& data,
  48. data_decoder::DecodeImageCallback callback) override {
  49. pending_callbacks_[data.id] = std::move(callback);
  50. }
  51. void CompleteRequest(const unsigned long id) {
  52. SkBitmap test_bitmap;
  53. test_bitmap.allocN32Pixels(id % 10, 1);
  54. std::move(pending_callbacks_.at(id)).Run(test_bitmap);
  55. pending_callbacks_.erase(id);
  56. }
  57. void FailRequest(const unsigned long id) {
  58. SkBitmap test_bitmap;
  59. std::move(pending_callbacks_.at(id)).Run(test_bitmap);
  60. pending_callbacks_.erase(id);
  61. }
  62. void CompleteAllRequests() {
  63. for (auto& it : pending_callbacks_)
  64. CompleteRequest(it.first);
  65. pending_callbacks_.clear();
  66. }
  67. private:
  68. base::flat_map<unsigned long, data_decoder::DecodeImageCallback>
  69. pending_callbacks_;
  70. };
  71. protected:
  72. RecentAppsInteractionHandlerTest() = default;
  73. RecentAppsInteractionHandlerTest(const RecentAppsInteractionHandlerTest&) =
  74. delete;
  75. RecentAppsInteractionHandlerTest& operator=(
  76. const RecentAppsInteractionHandlerTest&) = delete;
  77. ~RecentAppsInteractionHandlerTest() override = default;
  78. // testing::Test:
  79. void SetUp() override {
  80. feature_list_.InitWithFeatures(
  81. /*enabled_features=*/{features::kEcheSWA},
  82. /*disabled_features=*/{});
  83. RecentAppsInteractionHandlerImpl::RegisterPrefs(pref_service_.registry());
  84. fake_multidevice_setup_client_ =
  85. std::make_unique<multidevice_setup::FakeMultiDeviceSetupClient>();
  86. auto icon_decoder = std::make_unique<IconDecoderImpl>();
  87. icon_decoder.get()->decoder_delegate_ =
  88. std::make_unique<TestDecoderDelegate>();
  89. decoder_delegate_ = static_cast<TestDecoderDelegate*>(
  90. icon_decoder.get()->decoder_delegate_.get());
  91. interaction_handler_ = std::make_unique<RecentAppsInteractionHandlerImpl>(
  92. &pref_service_, fake_multidevice_setup_client_.get(),
  93. &fake_multidevice_feature_access_manager_, std::move(icon_decoder));
  94. interaction_handler_->AddRecentAppClickObserver(&fake_click_handler_);
  95. }
  96. void TearDown() override {
  97. interaction_handler_->RemoveRecentAppClickObserver(&fake_click_handler_);
  98. }
  99. void SaveRecentAppsToPref() {
  100. const char16_t app_visible_name1[] = u"Fake App";
  101. const char package_name1[] = "com.fakeapp";
  102. const int64_t expected_user_id1 = 1;
  103. auto app_metadata1 = Notification::AppMetadata(
  104. app_visible_name1, package_name1, gfx::Image(),
  105. /*icon_color=*/kIconColor, /*icon_is_monochrome=*/true,
  106. expected_user_id1);
  107. const char16_t app_visible_name2[] = u"Fake App2";
  108. const char package_name2[] = "com.fakeapp2";
  109. const int64_t expected_user_id2 = 2;
  110. auto app_metadata2 = Notification::AppMetadata(
  111. app_visible_name2, package_name2, gfx::Image(),
  112. /*icon_color=*/absl::nullopt, /*icon_is_monochrome=*/false,
  113. expected_user_id2);
  114. base::Value::List app_metadata_value_list;
  115. app_metadata_value_list.Append(app_metadata1.ToValue());
  116. app_metadata_value_list.Append(app_metadata2.ToValue());
  117. pref_service_.SetList(prefs::kRecentAppsHistory,
  118. std::move(app_metadata_value_list));
  119. }
  120. void SaveLegacyRecentAppToPref() {
  121. const char16_t app_visible_name1[] = u"Fake App";
  122. const char package_name1[] = "com.fakeapp";
  123. const int64_t expected_user_id1 = 1;
  124. base::Value app_metadata_value =
  125. Notification::AppMetadata(
  126. app_visible_name1, package_name1, gfx::Image(),
  127. /*icon_color=*/kIconColor, /*icon_is_monochrome=*/false,
  128. expected_user_id1)
  129. .ToValue();
  130. // Simulate an un-migrated preference without new fields.
  131. EXPECT_TRUE(app_metadata_value.GetDict().Remove(kIconIsMonochrome));
  132. EXPECT_TRUE(app_metadata_value.GetDict().Remove(kIconColorR));
  133. EXPECT_TRUE(app_metadata_value.GetDict().Remove(kIconColorG));
  134. EXPECT_TRUE(app_metadata_value.GetDict().Remove(kIconColorB));
  135. base::Value::List app_metadata_value_list;
  136. app_metadata_value_list.Append(std::move(app_metadata_value));
  137. pref_service_.SetList(prefs::kRecentAppsHistory,
  138. std::move(app_metadata_value_list));
  139. }
  140. std::string GetPackageName() {
  141. return fake_click_handler_.get_package_name();
  142. }
  143. RecentAppsInteractionHandlerImpl& handler() { return *interaction_handler_; }
  144. void SetEcheFeatureState(FeatureState feature_state) {
  145. fake_multidevice_setup_client_->SetFeatureState(
  146. multidevice_setup::mojom::Feature::kEche, feature_state);
  147. }
  148. void SetPhoneHubNotificationsFeatureState(FeatureState feature_state) {
  149. fake_multidevice_setup_client_->SetFeatureState(
  150. multidevice_setup::mojom::Feature::kPhoneHubNotifications,
  151. feature_state);
  152. }
  153. void SetHostStatus(HostStatus host_status) {
  154. fake_multidevice_setup_client_->SetHostStatusWithDevice(
  155. std::make_pair(host_status, absl::nullopt /* host_device */));
  156. }
  157. void SetNotificationAccess(bool enabled) {
  158. fake_multidevice_feature_access_manager_
  159. .SetNotificationAccessStatusInternal(
  160. enabled
  161. ? MultideviceFeatureAccessManager::AccessStatus::kAccessGranted
  162. : MultideviceFeatureAccessManager::AccessStatus::
  163. kAvailableButNotGranted,
  164. MultideviceFeatureAccessManager::AccessProhibitedReason::kUnknown);
  165. }
  166. void SetAppsAccessStatus(bool enabled) {
  167. fake_multidevice_feature_access_manager_.SetAppsAccessStatusInternal(
  168. enabled ? MultideviceFeatureAccessManager::AccessStatus::kAccessGranted
  169. : MultideviceFeatureAccessManager::AccessStatus::
  170. kAvailableButNotGranted);
  171. }
  172. std::vector<RecentAppsInteractionHandler::UserState> GetDefaultUserStates() {
  173. RecentAppsInteractionHandler::UserState user_state1;
  174. user_state1.user_id = 1;
  175. user_state1.is_enabled = true;
  176. RecentAppsInteractionHandler::UserState user_state2;
  177. user_state2.user_id = 2;
  178. user_state2.is_enabled = true;
  179. std::vector<RecentAppsInteractionHandler::UserState> user_states;
  180. user_states.push_back(user_state1);
  181. user_states.push_back(user_state2);
  182. return user_states;
  183. }
  184. std::vector<RecentAppsInteractionHandler::UserState>
  185. GetWorkProfileTurnedOffUserStates() {
  186. RecentAppsInteractionHandler::UserState user_state1;
  187. user_state1.user_id = 1;
  188. user_state1.is_enabled = true;
  189. RecentAppsInteractionHandler::UserState user_state2;
  190. user_state2.user_id = 2;
  191. user_state2.is_enabled = false;
  192. std::vector<RecentAppsInteractionHandler::UserState> user_states;
  193. user_states.push_back(user_state1);
  194. user_states.push_back(user_state2);
  195. return user_states;
  196. }
  197. void GenerateDefaultAppMetadata() {
  198. const base::Time now = base::Time::Now();
  199. const char16_t app_visible_name1[] = u"Fake App1";
  200. const char package_name1[] = "com.fakeapp1";
  201. const int64_t expected_user_id1 = 1;
  202. auto app_metadata1 = Notification::AppMetadata(
  203. app_visible_name1, package_name1, gfx::Image(),
  204. /*icon_color=*/absl::nullopt, /*icon_is_monochrome=*/true,
  205. expected_user_id1);
  206. const char16_t app_visible_name2[] = u"Fake App2";
  207. const char package_name2[] = "com.fakeapp2";
  208. const int64_t expected_user_id2 = 2;
  209. auto app_metadata2 = Notification::AppMetadata(
  210. app_visible_name2, package_name2, gfx::Image(),
  211. /*icon_color=*/absl::nullopt, /*icon_is_monochrome=*/true,
  212. expected_user_id2);
  213. handler().NotifyRecentAppAddedOrUpdated(app_metadata1, now);
  214. handler().NotifyRecentAppAddedOrUpdated(app_metadata2, now);
  215. }
  216. void GenerateAppMetadataWithDuplicateUserId() {
  217. const base::Time now = base::Time::Now();
  218. const char16_t app_visible_name1[] = u"Fake App1";
  219. const char package_name1[] = "com.fakeapp1";
  220. const int64_t expected_user_id = 1;
  221. auto app_metadata1 = Notification::AppMetadata(
  222. app_visible_name1, package_name1, gfx::Image(),
  223. /*icon_color=*/absl::nullopt, /*icon_is_monochrome=*/true,
  224. expected_user_id);
  225. const char16_t app_visible_name2[] = u"Fake App2";
  226. const char package_name2[] = "com.fakeapp2";
  227. auto app_metadata2 = Notification::AppMetadata(
  228. app_visible_name2, package_name2, gfx::Image(),
  229. /*icon_color=*/absl::nullopt, /*icon_is_monochrome=*/true,
  230. expected_user_id);
  231. handler().NotifyRecentAppAddedOrUpdated(app_metadata1, now);
  232. handler().NotifyRecentAppAddedOrUpdated(app_metadata2, now);
  233. }
  234. std::unique_ptr<multidevice_setup::FakeMultiDeviceSetupClient>
  235. fake_multidevice_setup_client_;
  236. private:
  237. FakeClickHandler fake_click_handler_;
  238. std::unique_ptr<RecentAppsInteractionHandlerImpl> interaction_handler_;
  239. TestingPrefServiceSimple pref_service_;
  240. FakeMultideviceFeatureAccessManager fake_multidevice_feature_access_manager_;
  241. base::test::ScopedFeatureList feature_list_;
  242. TestDecoderDelegate* decoder_delegate_;
  243. };
  244. TEST_F(RecentAppsInteractionHandlerTest, RecentAppsClicked) {
  245. const char16_t expected_app_visible_name[] = u"Fake App";
  246. const char expected_package_name[] = "com.fakeapp";
  247. const int64_t expected_user_id = 1;
  248. auto expected_app_metadata = Notification::AppMetadata(
  249. expected_app_visible_name, expected_package_name, gfx::Image(),
  250. /*icon_color=*/absl::nullopt, /*icon_is_monochrome=*/true,
  251. expected_user_id);
  252. handler().NotifyRecentAppClicked(expected_app_metadata);
  253. EXPECT_EQ(expected_package_name, GetPackageName());
  254. }
  255. TEST_F(RecentAppsInteractionHandlerTest, RecentAppsUpdated) {
  256. const char16_t app_visible_name1[] = u"Fake App";
  257. const char package_name1[] = "com.fakeapp";
  258. const int64_t expected_user_id1 = 1;
  259. auto app_metadata1 =
  260. Notification::AppMetadata(app_visible_name1, package_name1, gfx::Image(),
  261. /*icon_color=*/absl::nullopt,
  262. /*icon_is_monochrome=*/true, expected_user_id1);
  263. const char16_t app_visible_name2[] = u"Fake App2";
  264. const char package_name2[] = "com.fakeapp2";
  265. const int64_t expected_user_id2 = 2;
  266. auto app_metadata2 =
  267. Notification::AppMetadata(app_visible_name2, package_name2, gfx::Image(),
  268. /*icon_color=*/absl::nullopt,
  269. /*icon_is_monochrome=*/true, expected_user_id2);
  270. const base::Time now = base::Time::Now();
  271. handler().NotifyRecentAppAddedOrUpdated(app_metadata1, now);
  272. EXPECT_EQ(1U, handler().recent_app_metadata_list_for_testing()->size());
  273. EXPECT_EQ(now,
  274. handler().recent_app_metadata_list_for_testing()->at(0).second);
  275. // The same package name only update last accessed timestamp.
  276. const base::Time next_minute = base::Time::Now() + base::Minutes(1);
  277. handler().NotifyRecentAppAddedOrUpdated(app_metadata1, next_minute);
  278. EXPECT_EQ(1U, handler().recent_app_metadata_list_for_testing()->size());
  279. EXPECT_EQ(next_minute,
  280. handler().recent_app_metadata_list_for_testing()->at(0).second);
  281. const base::Time next_hour = base::Time::Now() + base::Hours(1);
  282. handler().NotifyRecentAppAddedOrUpdated(app_metadata2, next_hour);
  283. EXPECT_EQ(2U, handler().recent_app_metadata_list_for_testing()->size());
  284. }
  285. TEST_F(RecentAppsInteractionHandlerTest, SetStreamableApps) {
  286. proto::StreamableApps streamable_apps;
  287. auto* app1 = streamable_apps.add_apps();
  288. app1->set_visible_name("VisName1");
  289. app1->set_package_name("App1");
  290. app1->set_icon("icon1");
  291. auto* app2 = streamable_apps.add_apps();
  292. app2->set_visible_name("VisName2");
  293. app2->set_package_name("App2");
  294. app2->set_icon("icon2");
  295. handler().SetStreamableApps(streamable_apps);
  296. EXPECT_EQ(2U, handler().recent_app_metadata_list_for_testing()->size());
  297. EXPECT_EQ("App1", handler()
  298. .recent_app_metadata_list_for_testing()
  299. ->at(0)
  300. .first.package_name);
  301. EXPECT_EQ("App2", handler()
  302. .recent_app_metadata_list_for_testing()
  303. ->at(1)
  304. .first.package_name);
  305. }
  306. TEST_F(RecentAppsInteractionHandlerTest,
  307. SetStreamableApps_ClearsPreviousState) {
  308. proto::StreamableApps streamable_apps;
  309. auto* app1 = streamable_apps.add_apps();
  310. app1->set_visible_name("VisName1");
  311. app1->set_package_name("App1");
  312. app1->set_icon("icon1");
  313. auto* app2 = streamable_apps.add_apps();
  314. app2->set_visible_name("VisName2");
  315. app2->set_package_name("App2");
  316. app2->set_icon("icon2");
  317. handler().SetStreamableApps(streamable_apps);
  318. EXPECT_EQ(2U, handler().recent_app_metadata_list_for_testing()->size());
  319. EXPECT_EQ("App1", handler()
  320. .recent_app_metadata_list_for_testing()
  321. ->at(0)
  322. .first.package_name);
  323. EXPECT_EQ("App2", handler()
  324. .recent_app_metadata_list_for_testing()
  325. ->at(1)
  326. .first.package_name);
  327. proto::StreamableApps streamable_apps2;
  328. auto* app3 = streamable_apps2.add_apps();
  329. app3->set_visible_name("VisName3");
  330. app3->set_package_name("App3");
  331. app3->set_icon("icon3");
  332. handler().SetStreamableApps(streamable_apps2);
  333. EXPECT_EQ(1U, handler().recent_app_metadata_list_for_testing()->size());
  334. EXPECT_EQ("App3", handler()
  335. .recent_app_metadata_list_for_testing()
  336. ->at(0)
  337. .first.package_name);
  338. }
  339. TEST_F(RecentAppsInteractionHandlerTest, SetStreamableApps_EmptyList) {
  340. proto::StreamableApps streamable_apps;
  341. handler().SetStreamableApps(streamable_apps);
  342. EXPECT_TRUE(handler().recent_app_metadata_list_for_testing()->empty());
  343. }
  344. TEST_F(RecentAppsInteractionHandlerTest, FetchRecentAppMetadataList) {
  345. const char16_t app_visible_name1[] = u"Fake App";
  346. const char package_name1[] = "com.fakeapp";
  347. const int64_t expected_user_id1 = 1;
  348. auto app_metadata1 =
  349. Notification::AppMetadata(app_visible_name1, package_name1, gfx::Image(),
  350. /*icon_color=*/absl::nullopt,
  351. /*icon_is_monochrome=*/true, expected_user_id1);
  352. const char16_t app_visible_name2[] = u"Fake App2";
  353. const char package_name2[] = "com.fakeapp2";
  354. const int64_t expected_user_id2 = 1;
  355. auto app_metadata2 =
  356. Notification::AppMetadata(app_visible_name2, package_name2, gfx::Image(),
  357. /*icon_color=*/absl::nullopt,
  358. /*icon_is_monochrome=*/true, expected_user_id2);
  359. const char16_t app_visible_name3[] = u"Fake App3";
  360. const char package_name3[] = "com.fakeapp3";
  361. const int64_t expected_user_id3 = 1;
  362. auto app_metadata3 =
  363. Notification::AppMetadata(app_visible_name3, package_name3, gfx::Image(),
  364. /*icon_color=*/absl::nullopt,
  365. /*icon_is_monochrome=*/true, expected_user_id3);
  366. const base::Time now = base::Time::Now();
  367. const base::Time next_minute = base::Time::Now() + base::Minutes(1);
  368. const base::Time next_hour = base::Time::Now() + base::Hours(1);
  369. handler().NotifyRecentAppAddedOrUpdated(app_metadata1, now);
  370. handler().NotifyRecentAppAddedOrUpdated(app_metadata2, next_minute);
  371. handler().NotifyRecentAppAddedOrUpdated(app_metadata3, next_hour);
  372. std::vector<RecentAppsInteractionHandler::UserState> user_states =
  373. GetDefaultUserStates();
  374. handler().set_user_states(user_states);
  375. std::vector<Notification::AppMetadata> recent_apps_metadata_result =
  376. handler().FetchRecentAppMetadataList();
  377. EXPECT_EQ(3U, recent_apps_metadata_result.size());
  378. EXPECT_EQ(package_name3, recent_apps_metadata_result[0].package_name);
  379. EXPECT_EQ(package_name2, recent_apps_metadata_result[1].package_name);
  380. EXPECT_EQ(package_name1, recent_apps_metadata_result[2].package_name);
  381. const char16_t app_visible_name4[] = u"Fake App4";
  382. const char package_name4[] = "com.fakeapp4";
  383. const int64_t expected_user_id4 = 1;
  384. auto app_metadata4 =
  385. Notification::AppMetadata(app_visible_name4, package_name4, gfx::Image(),
  386. /*icon_color=*/absl::nullopt,
  387. /*icon_is_monochrome=*/true, expected_user_id4);
  388. const char16_t app_visible_name5[] = u"Fake App5";
  389. const char package_name5[] = "com.fakeapp5";
  390. const int64_t expected_user_id5 = 1;
  391. auto app_metadata5 =
  392. Notification::AppMetadata(app_visible_name5, package_name5, gfx::Image(),
  393. /*icon_color=*/absl::nullopt,
  394. /*icon_is_monochrome=*/true, expected_user_id5);
  395. const char16_t app_visible_name6[] = u"Fake App6";
  396. const char package_name6[] = "com.fakeapp6";
  397. const int64_t expected_user_id6 = 1;
  398. auto app_metadata6 =
  399. Notification::AppMetadata(app_visible_name6, package_name6, gfx::Image(),
  400. /*icon_color=*/absl::nullopt,
  401. /*icon_is_monochrome=*/true, expected_user_id6);
  402. const base::Time next_two_hour = base::Time::Now() + base::Hours(2);
  403. const base::Time next_three_hour = base::Time::Now() + base::Hours(3);
  404. const base::Time next_four_hour = base::Time::Now() + base::Hours(4);
  405. handler().NotifyRecentAppAddedOrUpdated(app_metadata4, next_two_hour);
  406. handler().NotifyRecentAppAddedOrUpdated(app_metadata5, next_three_hour);
  407. handler().NotifyRecentAppAddedOrUpdated(app_metadata6, next_four_hour);
  408. const size_t max_most_recent_apps = 5;
  409. recent_apps_metadata_result = handler().FetchRecentAppMetadataList();
  410. EXPECT_EQ(max_most_recent_apps, recent_apps_metadata_result.size());
  411. EXPECT_EQ(package_name6, recent_apps_metadata_result[0].package_name);
  412. EXPECT_EQ(package_name5, recent_apps_metadata_result[1].package_name);
  413. EXPECT_EQ(package_name4, recent_apps_metadata_result[2].package_name);
  414. EXPECT_EQ(package_name3, recent_apps_metadata_result[3].package_name);
  415. EXPECT_EQ(package_name2, recent_apps_metadata_result[4].package_name);
  416. }
  417. TEST_F(RecentAppsInteractionHandlerTest,
  418. FetchRecentAppMetadataListFromPreference) {
  419. SaveRecentAppsToPref();
  420. std::vector<RecentAppsInteractionHandler::UserState> user_states =
  421. GetDefaultUserStates();
  422. handler().set_user_states(user_states);
  423. const char package_name1[] = "com.fakeapp";
  424. const char package_name2[] = "com.fakeapp2";
  425. const size_t number_of_recent_apps_in_preference = 2;
  426. std::vector<Notification::AppMetadata> recent_apps_metadata_result =
  427. handler().FetchRecentAppMetadataList();
  428. EXPECT_EQ(number_of_recent_apps_in_preference,
  429. recent_apps_metadata_result.size());
  430. EXPECT_EQ(package_name1, recent_apps_metadata_result[0].package_name);
  431. EXPECT_EQ(package_name2, recent_apps_metadata_result[1].package_name);
  432. // Check de/serialization of icon metadata
  433. EXPECT_TRUE(recent_apps_metadata_result[0].icon_color.has_value());
  434. EXPECT_TRUE(*recent_apps_metadata_result[0].icon_color == kIconColor);
  435. EXPECT_TRUE(recent_apps_metadata_result[0].icon_is_monochrome);
  436. EXPECT_FALSE(recent_apps_metadata_result[1].icon_color.has_value());
  437. EXPECT_FALSE(recent_apps_metadata_result[1].icon_is_monochrome);
  438. }
  439. TEST_F(RecentAppsInteractionHandlerTest,
  440. FetchRecentAppMetadataListFromPreferenceBackwardsCompat) {
  441. SaveLegacyRecentAppToPref();
  442. std::vector<RecentAppsInteractionHandler::UserState> user_states =
  443. GetDefaultUserStates();
  444. handler().set_user_states(user_states);
  445. std::vector<Notification::AppMetadata> recent_apps_metadata_result =
  446. handler().FetchRecentAppMetadataList();
  447. EXPECT_EQ(1u, recent_apps_metadata_result.size());
  448. // Check that new fields are appropriately filled in with safe defaults.
  449. EXPECT_FALSE(recent_apps_metadata_result[0].icon_color.has_value());
  450. EXPECT_FALSE(recent_apps_metadata_result[0].icon_is_monochrome);
  451. }
  452. TEST_F(RecentAppsInteractionHandlerTest,
  453. OnFeatureStatesChangedToDisabledWithEmptyRecentAppsList) {
  454. SetEcheFeatureState(FeatureState::kDisabledByUser);
  455. EXPECT_EQ(RecentAppsInteractionHandler::RecentAppsUiState::HIDDEN,
  456. handler().ui_state());
  457. }
  458. TEST_F(RecentAppsInteractionHandlerTest,
  459. OnFeatureStatesChangedToDisabledWithNonEmptyRecentAppsList) {
  460. const base::Time now = base::Time::Now();
  461. const char16_t app_visible_name1[] = u"Fake App";
  462. const char package_name1[] = "com.fakeapp";
  463. const int64_t expected_user_id1 = 1;
  464. auto app_metadata1 =
  465. Notification::AppMetadata(app_visible_name1, package_name1, gfx::Image(),
  466. /*icon_color=*/absl::nullopt,
  467. /*icon_is_monochrome=*/true, expected_user_id1);
  468. handler().NotifyRecentAppAddedOrUpdated(app_metadata1, now);
  469. SetEcheFeatureState(FeatureState::kDisabledByUser);
  470. EXPECT_EQ(RecentAppsInteractionHandler::RecentAppsUiState::HIDDEN,
  471. handler().ui_state());
  472. }
  473. TEST_F(RecentAppsInteractionHandlerTest,
  474. OnFeatureStatesChangedToEnabledWithEmptyRecentAppsList) {
  475. SetEcheFeatureState(FeatureState::kEnabledByUser);
  476. SetPhoneHubNotificationsFeatureState(FeatureState::kEnabledByUser);
  477. SetAppsAccessStatus(true);
  478. SetNotificationAccess(true);
  479. EXPECT_EQ(RecentAppsInteractionHandler::RecentAppsUiState::PLACEHOLDER_VIEW,
  480. handler().ui_state());
  481. }
  482. TEST_F(RecentAppsInteractionHandlerTest,
  483. DisableNotificationAccessWithEmptyRecentAppsList) {
  484. SetEcheFeatureState(FeatureState::kEnabledByUser);
  485. SetPhoneHubNotificationsFeatureState(FeatureState::kEnabledByUser);
  486. SetAppsAccessStatus(true);
  487. SetNotificationAccess(true);
  488. EXPECT_EQ(RecentAppsInteractionHandler::RecentAppsUiState::PLACEHOLDER_VIEW,
  489. handler().ui_state());
  490. // Disable notification access permission on the host device.
  491. SetNotificationAccess(false);
  492. EXPECT_EQ(RecentAppsInteractionHandler::RecentAppsUiState::HIDDEN,
  493. handler().ui_state());
  494. // Disable notification access permission on the local device.
  495. SetNotificationAccess(true);
  496. SetPhoneHubNotificationsFeatureState(FeatureState::kDisabledByUser);
  497. EXPECT_EQ(RecentAppsInteractionHandler::RecentAppsUiState::HIDDEN,
  498. handler().ui_state());
  499. // Disable notification access permission on both devices.
  500. SetNotificationAccess(false);
  501. SetPhoneHubNotificationsFeatureState(FeatureState::kDisabledByUser);
  502. EXPECT_EQ(RecentAppsInteractionHandler::RecentAppsUiState::HIDDEN,
  503. handler().ui_state());
  504. // Enable notification access permission back on both devices.
  505. SetNotificationAccess(true);
  506. SetPhoneHubNotificationsFeatureState(FeatureState::kEnabledByUser);
  507. EXPECT_EQ(RecentAppsInteractionHandler::RecentAppsUiState::PLACEHOLDER_VIEW,
  508. handler().ui_state());
  509. }
  510. TEST_F(RecentAppsInteractionHandlerTest,
  511. OnFeatureStatesChangedToEnabledWithNonEmptyRecentAppsList) {
  512. const base::Time now = base::Time::Now();
  513. const char16_t app_visible_name1[] = u"Fake App";
  514. const char package_name1[] = "com.fakeapp";
  515. const int64_t expected_user_id1 = 1;
  516. auto app_metadata1 =
  517. Notification::AppMetadata(app_visible_name1, package_name1, gfx::Image(),
  518. /*icon_color=*/absl::nullopt,
  519. /*icon_is_monochrome=*/true, expected_user_id1);
  520. SetAppsAccessStatus(true);
  521. handler().NotifyRecentAppAddedOrUpdated(app_metadata1, now);
  522. SetEcheFeatureState(FeatureState::kEnabledByUser);
  523. EXPECT_EQ(RecentAppsInteractionHandler::RecentAppsUiState::ITEMS_VISIBLE,
  524. handler().ui_state());
  525. }
  526. TEST_F(RecentAppsInteractionHandlerTest,
  527. DisableNotificationAccessWithNonEmptyRecentAppsList) {
  528. const base::Time now = base::Time::Now();
  529. const char16_t app_visible_name1[] = u"Fake App";
  530. const char package_name1[] = "com.fakeapp";
  531. const int64_t expected_user_id1 = 1;
  532. auto app_metadata1 =
  533. Notification::AppMetadata(app_visible_name1, package_name1, gfx::Image(),
  534. /*icon_color=*/absl::nullopt,
  535. /*icon_is_monochrome=*/true, expected_user_id1);
  536. SetAppsAccessStatus(true);
  537. handler().NotifyRecentAppAddedOrUpdated(app_metadata1, now);
  538. SetEcheFeatureState(FeatureState::kEnabledByUser);
  539. EXPECT_EQ(RecentAppsInteractionHandler::RecentAppsUiState::ITEMS_VISIBLE,
  540. handler().ui_state());
  541. // Disable notification access permission on the host device.
  542. SetNotificationAccess(false);
  543. EXPECT_EQ(RecentAppsInteractionHandler::RecentAppsUiState::ITEMS_VISIBLE,
  544. handler().ui_state());
  545. // Disable notification access permission on the local device.
  546. SetNotificationAccess(true);
  547. SetPhoneHubNotificationsFeatureState(FeatureState::kDisabledByUser);
  548. EXPECT_EQ(RecentAppsInteractionHandler::RecentAppsUiState::ITEMS_VISIBLE,
  549. handler().ui_state());
  550. // Disable notification access permission on both devices.
  551. SetNotificationAccess(false);
  552. SetPhoneHubNotificationsFeatureState(FeatureState::kDisabledByUser);
  553. EXPECT_EQ(RecentAppsInteractionHandler::RecentAppsUiState::ITEMS_VISIBLE,
  554. handler().ui_state());
  555. }
  556. TEST_F(RecentAppsInteractionHandlerTest,
  557. UiStateChangedToVisibleWhenRecentAppBeAdded) {
  558. SetEcheFeatureState(FeatureState::kEnabledByUser);
  559. SetPhoneHubNotificationsFeatureState(FeatureState::kEnabledByUser);
  560. SetAppsAccessStatus(true);
  561. SetNotificationAccess(true);
  562. EXPECT_EQ(RecentAppsInteractionHandler::RecentAppsUiState::PLACEHOLDER_VIEW,
  563. handler().ui_state());
  564. const base::Time now = base::Time::Now();
  565. const char16_t app_visible_name1[] = u"Fake App";
  566. const char package_name1[] = "com.fakeapp";
  567. const int64_t expected_user_id1 = 1;
  568. auto app_metadata1 =
  569. Notification::AppMetadata(app_visible_name1, package_name1, gfx::Image(),
  570. /*icon_color=*/absl::nullopt,
  571. /*icon_is_monochrome=*/true, expected_user_id1);
  572. handler().NotifyRecentAppAddedOrUpdated(app_metadata1, now);
  573. EXPECT_EQ(RecentAppsInteractionHandler::RecentAppsUiState::ITEMS_VISIBLE,
  574. handler().ui_state());
  575. }
  576. TEST_F(RecentAppsInteractionHandlerTest, DisableAppsAccess) {
  577. GenerateDefaultAppMetadata();
  578. // The apps access has not been granted yet so the UI state always HIDDEN.
  579. SetAppsAccessStatus(true);
  580. SetPhoneHubNotificationsFeatureState(FeatureState::kEnabledByUser);
  581. SetNotificationAccess(true);
  582. EXPECT_EQ(RecentAppsInteractionHandler::RecentAppsUiState::HIDDEN,
  583. handler().ui_state());
  584. SetNotificationAccess(false);
  585. EXPECT_EQ(RecentAppsInteractionHandler::RecentAppsUiState::HIDDEN,
  586. handler().ui_state());
  587. // Disable notification access permission on the local device.
  588. SetNotificationAccess(true);
  589. SetPhoneHubNotificationsFeatureState(FeatureState::kDisabledByUser);
  590. EXPECT_EQ(RecentAppsInteractionHandler::RecentAppsUiState::HIDDEN,
  591. handler().ui_state());
  592. // Disable notification access permission on both devices.
  593. SetNotificationAccess(false);
  594. SetPhoneHubNotificationsFeatureState(FeatureState::kDisabledByUser);
  595. EXPECT_EQ(RecentAppsInteractionHandler::RecentAppsUiState::HIDDEN,
  596. handler().ui_state());
  597. // Enable notification access permission back on both devices.
  598. SetNotificationAccess(true);
  599. SetPhoneHubNotificationsFeatureState(FeatureState::kEnabledByUser);
  600. EXPECT_EQ(RecentAppsInteractionHandler::RecentAppsUiState::HIDDEN,
  601. handler().ui_state());
  602. }
  603. TEST_F(RecentAppsInteractionHandlerTest,
  604. PrefBeClearedWhenFeatureStatesChangedToUnavailableNoVerifiedHost) {
  605. SaveRecentAppsToPref();
  606. SetHostStatus(HostStatus::kHostSetButNotYetVerified);
  607. std::vector<Notification::AppMetadata> recent_apps_metadata_result =
  608. handler().FetchRecentAppMetadataList();
  609. EXPECT_EQ(recent_apps_metadata_result.size(), 0u);
  610. }
  611. TEST_F(
  612. RecentAppsInteractionHandlerTest,
  613. RecentAppsListBeClearedWhenFeatureStatesChangedToUnavailableNoVerifiedHost) {
  614. const base::Time now = base::Time::Now();
  615. const char16_t app_visible_name[] = u"Fake App";
  616. const char package_name[] = "com.fakeapp";
  617. const int64_t expected_user_id = 1;
  618. auto app_metadata =
  619. Notification::AppMetadata(app_visible_name, package_name, gfx::Image(),
  620. /*icon_color=*/absl::nullopt,
  621. /*icon_is_monochrome=*/true, expected_user_id);
  622. handler().NotifyRecentAppAddedOrUpdated(app_metadata, now);
  623. SetHostStatus(HostStatus::kHostSetButNotYetVerified);
  624. std::vector<Notification::AppMetadata> recent_apps_metadata_result =
  625. handler().FetchRecentAppMetadataList();
  626. EXPECT_EQ(recent_apps_metadata_result.size(), 0u);
  627. }
  628. TEST_F(RecentAppsInteractionHandlerTest,
  629. ShowAllRecentAppsOfAllUsersWithQuietModeOff) {
  630. GenerateDefaultAppMetadata();
  631. std::vector<RecentAppsInteractionHandler::UserState> user_states =
  632. GetDefaultUserStates();
  633. handler().set_user_states(user_states);
  634. std::vector<Notification::AppMetadata> recent_apps_metadata_result =
  635. handler().FetchRecentAppMetadataList();
  636. EXPECT_EQ(recent_apps_metadata_result.size(), 2u);
  637. EXPECT_EQ(1, recent_apps_metadata_result[0].user_id);
  638. EXPECT_EQ("com.fakeapp1", recent_apps_metadata_result[0].package_name);
  639. EXPECT_EQ(2, recent_apps_metadata_result[1].user_id);
  640. EXPECT_EQ("com.fakeapp2", recent_apps_metadata_result[1].package_name);
  641. }
  642. TEST_F(RecentAppsInteractionHandlerTest, ShowRecentAppsOfUserWithQuietModeOn) {
  643. GenerateDefaultAppMetadata();
  644. std::vector<RecentAppsInteractionHandler::UserState> user_states =
  645. GetWorkProfileTurnedOffUserStates();
  646. handler().set_user_states(user_states);
  647. std::vector<Notification::AppMetadata> recent_apps_metadata_result =
  648. handler().FetchRecentAppMetadataList();
  649. EXPECT_EQ(recent_apps_metadata_result.size(), 1u);
  650. EXPECT_EQ(1, recent_apps_metadata_result[0].user_id);
  651. EXPECT_EQ("com.fakeapp1", recent_apps_metadata_result[0].package_name);
  652. }
  653. TEST_F(RecentAppsInteractionHandlerTest, ShowRecentAppsWhenGetsEmptyUser) {
  654. GenerateDefaultAppMetadata();
  655. std::vector<RecentAppsInteractionHandler::UserState> user_states;
  656. handler().set_user_states(user_states);
  657. std::vector<Notification::AppMetadata> recent_apps_metadata_result =
  658. handler().FetchRecentAppMetadataList();
  659. EXPECT_EQ(recent_apps_metadata_result.size(), 2u);
  660. EXPECT_EQ(1, recent_apps_metadata_result[0].user_id);
  661. EXPECT_EQ(2, recent_apps_metadata_result[1].user_id);
  662. }
  663. TEST_F(RecentAppsInteractionHandlerTest, GetUserIdSet) {
  664. GenerateAppMetadataWithDuplicateUserId();
  665. std::vector<RecentAppsInteractionHandler::UserState> user_states;
  666. handler().set_user_states(user_states);
  667. std::vector<Notification::AppMetadata> recent_apps_metadata_result =
  668. handler().FetchRecentAppMetadataList();
  669. EXPECT_EQ(recent_apps_metadata_result.size(), 2u);
  670. EXPECT_EQ(1, recent_apps_metadata_result[0].user_id);
  671. EXPECT_EQ(1, recent_apps_metadata_result[1].user_id);
  672. }
  673. } // namespace phonehub
  674. } // namespace ash