chromium/ash/quick_pair/ui/fast_pair/fast_pair_notification_controller_unittest.cc

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/quick_pair/ui/fast_pair/fast_pair_notification_controller.h"

#include "ash/test/ash_test_base.h"
#include "base/memory/weak_ptr.h"
#include "base/test/mock_callback.h"
#include "chromeos/ash/services/quick_pair/fast_pair_data_parser.h"
#include "chromeos/ash/services/quick_pair/mock_quick_pair_process_manager.h"
#include "chromeos/ash/services/quick_pair/quick_pair_process.h"
#include "chromeos/ash/services/quick_pair/quick_pair_process_manager.h"
#include "chromeos/ash/services/quick_pair/quick_pair_process_manager_impl.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/message_center/fake_message_center.h"
#include "ui/message_center/message_center.h"

namespace {

const char16_t kTestDeviceName[] = u"Pixel Buds";
const char16_t kTestAppName[] = u"JBLTools";
const char16_t kTestEmail[] = u"[email protected]";
const char kFastPairErrorNotificationId[] =
    "cros_fast_pair_error_notification_id";
const char kFastPairDiscoveryGuestNotificationId[] =
    "cros_fast_pair_discovery_guest_notification_id";
const char kFastPairApplicationAvailableNotificationId[] =
    "cros_fast_pair_application_available_notification_id";
const char kFastPairApplicationInstalledNotificationId[] =
    "cros_fast_pair_application_installed_notification_id";
const char kFastPairDiscoveryUserNotificationId[] =
    "cros_fast_pair_discovery_user_notification_id";
const char kFastPairPairingNotificationId[] =
    "cros_fast_pair_pairing_notification_id";
const char kFastPairAssociateAccountNotificationId[] =
    "cros_fast_pair_associate_account_notification_id";
const char kFastPairDiscoverySubsequentNotificationId[] =
    "cros_fast_pair_discovery_subsequent_notification_id";

constexpr base::TimeDelta kNotificationShortTimeDuration = base::Seconds(5);
constexpr base::TimeDelta kNotificationTimeout = base::Seconds(12);

class TestMessageCenter : public message_center::FakeMessageCenter {
 public:
  TestMessageCenter() = default;

  TestMessageCenter(const TestMessageCenter&) = delete;
  TestMessageCenter& operator=(const TestMessageCenter&) = delete;

  ~TestMessageCenter() override = default;

  void SetAddNotificationCallback(base::OnceClosure add_notification_callback) {
    add_notification_callback_ = std::move(add_notification_callback);
  }

  // message_center::FakeMessageCenter:
  void AddNotification(
      std::unique_ptr<message_center::Notification> notification) override {
    EXPECT_FALSE(notification_);
    notification_ = std::move(notification);
    if (add_notification_callback_) {
      std::move(add_notification_callback_).Run();
    }
  }

  void RemoveNotification(const std::string& id, bool by_user) override {
    if (notification_)
      notification_->delegate()->Close(by_user);
  }

  void RemoveNotificationsForNotifierId(
      const message_center::NotifierId& notifier_id) override {
    if (notification_)
      notification_->delegate()->Close(/*by_user=*/false);
  }

  message_center::Notification* FindVisibleNotificationById(
      const std::string& id) override {
    if (notification_) {
      EXPECT_EQ(notification_->id(), id);
      return notification_.get();
    }
    return nullptr;
  }

  void ClickOnNotificationButton(const std::string& id,
                                 int button_index) override {
    EXPECT_TRUE(notification_);
    EXPECT_EQ(id, notification_->id());

    notification_->delegate()->Click(/*button_index=*/button_index,
                                     /*reply=*/std::nullopt);
  }

 private:
  std::unique_ptr<message_center::Notification> notification_;
  base::OnceClosure add_notification_callback_;
};

}  // namespace

namespace ash {
namespace quick_pair {

class FastPairNotificationControllerTest : public AshTestBase {
 public:
  FastPairNotificationControllerTest()
      : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}

  void SetUp() override {
    AshTestBase::SetUp();

    fast_pair_notification_controller_ =
        std::make_unique<FastPairNotificationController>(&test_message_center_);
  }

  void TearDown() override {
    fast_pair_notification_controller_.reset();
    AshTestBase::TearDown();
  }

 protected:
  TestMessageCenter test_message_center_;
  std::unique_ptr<FastPairNotificationController>
      fast_pair_notification_controller_;
};

TEST_F(FastPairNotificationControllerTest,
       ShowErrorNotification_SettingsClicked) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairErrorNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> launch_bluetooth_pairing_callback;
  EXPECT_CALL(launch_bluetooth_pairing_callback, Run).Times(1);

  fast_pair_notification_controller_->ShowErrorNotification(
      kTestDeviceName,
      /*device_image=*/gfx::Image(), launch_bluetooth_pairing_callback.Get(),
      on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairErrorNotificationId));
  test_message_center_.ClickOnNotificationButton(
      /*id=*/kFastPairErrorNotificationId, /*button_index=*/0);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowErrorNotification_RemovedByUser) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairErrorNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> launch_bluetooth_pairing_callback;
  EXPECT_CALL(on_close,
              Run(FastPairNotificationDismissReason::kDismissedByUser))
      .Times(1);
  EXPECT_CALL(launch_bluetooth_pairing_callback, Run).Times(0);

  fast_pair_notification_controller_->ShowErrorNotification(
      kTestDeviceName,
      /*device_image=*/gfx::Image(), launch_bluetooth_pairing_callback.Get(),
      on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairErrorNotificationId));
  test_message_center_.RemoveNotification(
      /*id=*/kFastPairErrorNotificationId, /*by_user=*/true);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest, ShowErrorNotification_RemovedByOS) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairErrorNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> launch_bluetooth_pairing_callback;
  EXPECT_CALL(on_close, Run(FastPairNotificationDismissReason::kDismissedByOs))
      .Times(1);
  EXPECT_CALL(launch_bluetooth_pairing_callback, Run).Times(0);

  fast_pair_notification_controller_->ShowErrorNotification(
      kTestDeviceName,
      /*device_image=*/gfx::Image(), launch_bluetooth_pairing_callback.Get(),
      on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairErrorNotificationId));
  test_message_center_.RemoveNotification(
      /*id=*/kFastPairErrorNotificationId, /*by_user=*/false);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowUserDiscoveryNotification_ConnectClicked) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryUserNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_connect_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  EXPECT_CALL(on_connect_clicked, Run).Times(1);
  EXPECT_CALL(on_learn_more_clicked, Run).Times(0);

  fast_pair_notification_controller_->ShowUserDiscoveryNotification(
      kTestDeviceName, kTestEmail,
      /*device_image=*/gfx::Image(), on_connect_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryUserNotificationId));
  test_message_center_.ClickOnNotificationButton(
      /*id=*/kFastPairDiscoveryUserNotificationId, /*button_index=*/0);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowUserDiscoveryNotification_LearnMoreClicked) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryUserNotificationId));

  base::MockCallback<base::RepeatingClosure> on_connect_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  EXPECT_CALL(on_connect_clicked, Run).Times(0);
  EXPECT_CALL(on_learn_more_clicked, Run).Times(1);

  fast_pair_notification_controller_->ShowUserDiscoveryNotification(
      kTestDeviceName, kTestEmail,
      /*device_image=*/gfx::Image(), on_connect_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryUserNotificationId));
  test_message_center_.ClickOnNotificationButton(
      /*id=*/kFastPairDiscoveryUserNotificationId, /*button_index=*/1);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowUserDiscoveryNotification_RemovedByUser) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryUserNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_connect_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  EXPECT_CALL(on_connect_clicked, Run).Times(0);
  EXPECT_CALL(on_learn_more_clicked, Run).Times(0);
  EXPECT_CALL(on_close,
              Run(FastPairNotificationDismissReason::kDismissedByUser))
      .Times(1);

  fast_pair_notification_controller_->ShowUserDiscoveryNotification(
      kTestDeviceName, kTestEmail,
      /*device_image=*/gfx::Image(), on_connect_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryUserNotificationId));
  test_message_center_.RemoveNotification(
      /*id=*/kFastPairDiscoveryUserNotificationId, /*by_user=*/true);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowUserDiscoveryNotification_RemovedByTimeout) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryUserNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_connect_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  fast_pair_notification_controller_->ShowUserDiscoveryNotification(
      kTestDeviceName, kTestEmail,
      /*device_image=*/gfx::Image(), on_connect_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();
  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryUserNotificationId));

  EXPECT_CALL(on_connect_clicked, Run).Times(0);
  EXPECT_CALL(on_learn_more_clicked, Run).Times(0);
  EXPECT_CALL(on_close,
              Run(FastPairNotificationDismissReason::kDismissedByTimeout))
      .Times(1);
  task_environment()->FastForwardBy(kNotificationTimeout);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowUserDiscoveryNotification_ExtendTimeout) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryUserNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_connect_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  fast_pair_notification_controller_->ShowUserDiscoveryNotification(
      kTestDeviceName, kTestEmail,
      /*device_image=*/gfx::Image(), on_connect_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();
  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryUserNotificationId));
  task_environment()->FastForwardBy(kNotificationShortTimeDuration);

  // Extend the notification to simulate the same device being found again. We
  // expect the notification to still be shown after the initial 12 second
  // timeout since the timeout should have been reset.
  fast_pair_notification_controller_->ExtendNotification();
  task_environment()->FastForwardBy(kNotificationTimeout);
  base::RunLoop().RunUntilIdle();
  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryUserNotificationId));
}

TEST_F(FastPairNotificationControllerTest,
       ShowUserDiscoveryNotification_RemovedByOS) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryUserNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_connect_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  EXPECT_CALL(on_connect_clicked, Run).Times(0);
  EXPECT_CALL(on_learn_more_clicked, Run).Times(0);
  EXPECT_CALL(on_close, Run(FastPairNotificationDismissReason::kDismissedByOs))
      .Times(1);

  fast_pair_notification_controller_->ShowUserDiscoveryNotification(
      kTestDeviceName, kTestEmail,
      /*device_image=*/gfx::Image(), on_connect_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryUserNotificationId));
  test_message_center_.RemoveNotification(
      /*id=*/kFastPairDiscoveryUserNotificationId, /*by_user=*/false);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowGuestDiscoveryNotification_ConnectClicked) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryGuestNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_connect_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  EXPECT_CALL(on_connect_clicked, Run).Times(1);
  EXPECT_CALL(on_learn_more_clicked, Run).Times(0);

  fast_pair_notification_controller_->ShowGuestDiscoveryNotification(
      kTestDeviceName,
      /*device_image=*/gfx::Image(), on_connect_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryGuestNotificationId));
  test_message_center_.ClickOnNotificationButton(
      /*id=*/kFastPairDiscoveryGuestNotificationId, /*button_index=*/0);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowGuestDiscoveryNotification_LearnMoreClicked) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryGuestNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_connect_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  EXPECT_CALL(on_connect_clicked, Run).Times(0);
  EXPECT_CALL(on_learn_more_clicked, Run).Times(1);

  fast_pair_notification_controller_->ShowGuestDiscoveryNotification(
      kTestDeviceName,
      /*device_image=*/gfx::Image(), on_connect_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryGuestNotificationId));
  test_message_center_.ClickOnNotificationButton(
      /*id=*/kFastPairDiscoveryGuestNotificationId, /*button_index=*/1);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowGuestDiscoveryNotification_RemovedByUser) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryGuestNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_connect_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  EXPECT_CALL(on_connect_clicked, Run).Times(0);
  EXPECT_CALL(on_learn_more_clicked, Run).Times(0);
  EXPECT_CALL(on_close,
              Run(FastPairNotificationDismissReason::kDismissedByUser))
      .Times(1);

  fast_pair_notification_controller_->ShowGuestDiscoveryNotification(
      kTestDeviceName,
      /*device_image=*/gfx::Image(), on_connect_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryGuestNotificationId));
  test_message_center_.RemoveNotification(
      /*id=*/kFastPairDiscoveryGuestNotificationId, /*by_user=*/true);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowGuestDiscoveryNotification_RemovedByOS) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryGuestNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_connect_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  EXPECT_CALL(on_connect_clicked, Run).Times(0);
  EXPECT_CALL(on_learn_more_clicked, Run).Times(0);
  EXPECT_CALL(on_close, Run(FastPairNotificationDismissReason::kDismissedByOs))
      .Times(1);

  fast_pair_notification_controller_->ShowGuestDiscoveryNotification(
      kTestDeviceName,
      /*device_image=*/gfx::Image(), on_connect_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryGuestNotificationId));
  test_message_center_.RemoveNotification(
      /*id=*/kFastPairDiscoveryGuestNotificationId, /*by_user=*/false);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowGuestDiscoveryNotification_RemovedByTimeout) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryGuestNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_connect_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  fast_pair_notification_controller_->ShowGuestDiscoveryNotification(
      kTestDeviceName,
      /*device_image=*/gfx::Image(), on_connect_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();
  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryGuestNotificationId));

  EXPECT_CALL(on_connect_clicked, Run).Times(0);
  EXPECT_CALL(on_learn_more_clicked, Run).Times(0);
  EXPECT_CALL(on_close,
              Run(FastPairNotificationDismissReason::kDismissedByTimeout))
      .Times(1);
  task_environment()->FastForwardBy(kNotificationTimeout);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowGuestDiscoveryNotification_ExtendTimeout) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryGuestNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_connect_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  fast_pair_notification_controller_->ShowGuestDiscoveryNotification(
      kTestDeviceName,
      /*device_image=*/gfx::Image(), on_connect_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();
  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryGuestNotificationId));
  task_environment()->FastForwardBy(kNotificationShortTimeDuration);

  // Extend the notification to simulate the same device being found again. We
  // expect the notification to still be shown after the initial 12 second
  // timeout since the timeout should have been reset.
  fast_pair_notification_controller_->ExtendNotification();
  base::RunLoop().RunUntilIdle();
  task_environment()->FastForwardBy(kNotificationTimeout);
  base::RunLoop().RunUntilIdle();
  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryGuestNotificationId));
}

TEST_F(FastPairNotificationControllerTest,
       ShowApplicationAvailableNotification_DownloadClicked) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairApplicationAvailableNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_download_clicked;
  EXPECT_CALL(on_download_clicked, Run).Times(1);
  EXPECT_CALL(on_close, Run).Times(0);

  fast_pair_notification_controller_->ShowApplicationAvailableNotification(
      kTestDeviceName,
      /*device_image=*/gfx::Image(), on_download_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairApplicationAvailableNotificationId));
  test_message_center_.ClickOnNotificationButton(
      /*id=*/kFastPairApplicationAvailableNotificationId, /*button_index=*/0);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowApplicationAvailableNotification_RemovedByUser) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairApplicationAvailableNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_download_clicked;
  EXPECT_CALL(on_download_clicked, Run).Times(0);
  EXPECT_CALL(on_close,
              Run(FastPairNotificationDismissReason::kDismissedByUser))
      .Times(1);

  fast_pair_notification_controller_->ShowApplicationAvailableNotification(
      kTestDeviceName,
      /*device_image=*/gfx::Image(), on_download_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairApplicationAvailableNotificationId));
  test_message_center_.RemoveNotification(
      /*id=*/kFastPairApplicationAvailableNotificationId, /*by_user=*/true);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowApplicationAvailableNotification_RemovedByOS) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairApplicationAvailableNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_download_clicked;
  EXPECT_CALL(on_download_clicked, Run).Times(0);
  EXPECT_CALL(on_close, Run(FastPairNotificationDismissReason::kDismissedByOs))
      .Times(1);

  fast_pair_notification_controller_->ShowApplicationAvailableNotification(
      kTestDeviceName,
      /*device_image=*/gfx::Image(), on_download_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairApplicationAvailableNotificationId));
  test_message_center_.RemoveNotification(
      /*id=*/kFastPairApplicationAvailableNotificationId, /*by_user=*/false);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowApplicationInstalledNotification_SetupClicked) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairApplicationInstalledNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_setup_clicked;
  EXPECT_CALL(on_setup_clicked, Run).Times(1);
  EXPECT_CALL(on_close, Run).Times(0);

  fast_pair_notification_controller_->ShowApplicationInstalledNotification(
      kTestDeviceName,
      /*device_image=*/gfx::Image(), kTestAppName, on_setup_clicked.Get(),
      on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairApplicationInstalledNotificationId));
  test_message_center_.ClickOnNotificationButton(
      /*id=*/kFastPairApplicationInstalledNotificationId, /*button_index=*/0);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowApplicationInstalledNotification_RemovedByUser) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairApplicationInstalledNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_setup_clicked;
  EXPECT_CALL(on_setup_clicked, Run).Times(0);
  EXPECT_CALL(on_close,
              Run(FastPairNotificationDismissReason::kDismissedByUser))
      .Times(1);

  fast_pair_notification_controller_->ShowApplicationInstalledNotification(
      kTestDeviceName,
      /*device_image=*/gfx::Image(), kTestAppName, on_setup_clicked.Get(),
      on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairApplicationInstalledNotificationId));
  test_message_center_.RemoveNotification(
      /*id=*/kFastPairApplicationInstalledNotificationId, /*by_user=*/true);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowApplicationInstalledNotification_RemovedByOS) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairApplicationInstalledNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_setup_clicked;
  EXPECT_CALL(on_setup_clicked, Run).Times(0);
  EXPECT_CALL(on_close, Run(FastPairNotificationDismissReason::kDismissedByOs))
      .Times(1);

  fast_pair_notification_controller_->ShowApplicationInstalledNotification(
      kTestDeviceName,
      /*device_image=*/gfx::Image(), kTestAppName, on_setup_clicked.Get(),
      on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairApplicationInstalledNotificationId));
  test_message_center_.RemoveNotification(
      /*id=*/kFastPairApplicationInstalledNotificationId, /*by_user=*/false);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest, ShowPairingNotification) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairPairingNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  fast_pair_notification_controller_->ShowPairingNotification(
      kTestDeviceName,
      /*device_image=*/gfx::Image(), on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairPairingNotificationId));
}

TEST_F(FastPairNotificationControllerTest,
       ShowAssociateAccount_ConnectClicked) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairAssociateAccountNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_save_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  EXPECT_CALL(on_save_clicked, Run).Times(1);
  EXPECT_CALL(on_learn_more_clicked, Run).Times(0);

  fast_pair_notification_controller_->ShowAssociateAccount(
      kTestDeviceName, kTestEmail,
      /*device_image=*/gfx::Image(), on_save_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairAssociateAccountNotificationId));
  test_message_center_.ClickOnNotificationButton(
      /*id=*/kFastPairAssociateAccountNotificationId, /*button_index=*/0);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowAssociateAccount_LearnMoreClicked) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairAssociateAccountNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_save_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  EXPECT_CALL(on_save_clicked, Run).Times(0);
  EXPECT_CALL(on_learn_more_clicked, Run).Times(1);

  fast_pair_notification_controller_->ShowAssociateAccount(
      kTestDeviceName, kTestEmail,
      /*device_image=*/gfx::Image(), on_save_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairAssociateAccountNotificationId));
  test_message_center_.ClickOnNotificationButton(
      /*id=*/kFastPairAssociateAccountNotificationId, /*button_index=*/1);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest, ShowAssociateAccount_RemovedByUser) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairAssociateAccountNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_save_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  EXPECT_CALL(on_save_clicked, Run).Times(0);
  EXPECT_CALL(on_learn_more_clicked, Run).Times(0);
  EXPECT_CALL(on_close,
              Run(FastPairNotificationDismissReason::kDismissedByUser))
      .Times(1);

  fast_pair_notification_controller_->ShowAssociateAccount(
      kTestDeviceName, kTestEmail,
      /*device_image=*/gfx::Image(), on_save_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairAssociateAccountNotificationId));
  test_message_center_.RemoveNotification(
      /*id=*/kFastPairAssociateAccountNotificationId, /*by_user=*/true);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest, ShowAssociateAccount_RemovedByOS) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairAssociateAccountNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_save_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  EXPECT_CALL(on_save_clicked, Run).Times(0);
  EXPECT_CALL(on_learn_more_clicked, Run).Times(0);
  EXPECT_CALL(on_close, Run(FastPairNotificationDismissReason::kDismissedByOs))
      .Times(1);

  fast_pair_notification_controller_->ShowAssociateAccount(
      kTestDeviceName, kTestEmail,
      /*device_image=*/gfx::Image(), on_save_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairAssociateAccountNotificationId));
  test_message_center_.RemoveNotification(
      /*id=*/kFastPairAssociateAccountNotificationId, /*by_user=*/false);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowAssociateAccountNotification_RemovedByTimeout) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairAssociateAccountNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_save_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  fast_pair_notification_controller_->ShowAssociateAccount(
      kTestDeviceName, kTestEmail,
      /*device_image=*/gfx::Image(), on_save_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();
  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairAssociateAccountNotificationId));

  EXPECT_CALL(on_save_clicked, Run).Times(0);
  EXPECT_CALL(on_learn_more_clicked, Run).Times(0);
  EXPECT_CALL(on_close,
              Run(FastPairNotificationDismissReason::kDismissedByTimeout))
      .Times(1);
  task_environment()->FastForwardBy(kNotificationTimeout);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowAssociateAccountNotification_ExtendTimeout) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairAssociateAccountNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_save_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  fast_pair_notification_controller_->ShowAssociateAccount(
      kTestDeviceName, kTestEmail,
      /*device_image=*/gfx::Image(), on_save_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();
  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairAssociateAccountNotificationId));
  task_environment()->FastForwardBy(kNotificationShortTimeDuration);

  // Extend the notification to simulate the same device being found again. We
  // expect the notification to still be shown after the initial 12 second
  // timeout since the timeout should have been reset.
  fast_pair_notification_controller_->ExtendNotification();
  base::RunLoop().RunUntilIdle();
  task_environment()->FastForwardBy(kNotificationTimeout);
  base::RunLoop().RunUntilIdle();
  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairAssociateAccountNotificationId));
}
TEST_F(FastPairNotificationControllerTest,
       ShowSubsequentDiscoveryNotification_ConnectClicked) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoverySubsequentNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_connect_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  EXPECT_CALL(on_connect_clicked, Run).Times(1);
  EXPECT_CALL(on_learn_more_clicked, Run).Times(0);

  fast_pair_notification_controller_->ShowSubsequentDiscoveryNotification(
      kTestDeviceName, kTestEmail,
      /*device_image=*/gfx::Image(), on_connect_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoverySubsequentNotificationId));
  test_message_center_.ClickOnNotificationButton(
      /*id=*/kFastPairDiscoverySubsequentNotificationId, /*button_index=*/0);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowSubsequentDiscoveryNotification_LearnMoreClicked) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoveryUserNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_connect_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  EXPECT_CALL(on_connect_clicked, Run).Times(0);
  EXPECT_CALL(on_learn_more_clicked, Run).Times(1);

  fast_pair_notification_controller_->ShowSubsequentDiscoveryNotification(
      kTestDeviceName, kTestEmail,
      /*device_image=*/gfx::Image(), on_connect_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoverySubsequentNotificationId));
  test_message_center_.ClickOnNotificationButton(
      /*id=*/kFastPairDiscoverySubsequentNotificationId, /*button_index=*/1);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowSubsequentDiscoveryNotification_RemovedByUser) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoverySubsequentNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_connect_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  EXPECT_CALL(on_connect_clicked, Run).Times(0);
  EXPECT_CALL(on_learn_more_clicked, Run).Times(0);
  EXPECT_CALL(on_close,
              Run(FastPairNotificationDismissReason::kDismissedByUser))
      .Times(1);

  fast_pair_notification_controller_->ShowSubsequentDiscoveryNotification(
      kTestDeviceName, kTestEmail,
      /*device_image=*/gfx::Image(), on_connect_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoverySubsequentNotificationId));
  test_message_center_.RemoveNotification(
      /*id=*/kFastPairDiscoverySubsequentNotificationId, /*by_user=*/true);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowSubsequentDiscoveryNotification_RemovedByOS) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoverySubsequentNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_connect_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  EXPECT_CALL(on_connect_clicked, Run).Times(0);
  EXPECT_CALL(on_learn_more_clicked, Run).Times(0);
  EXPECT_CALL(on_close, Run(FastPairNotificationDismissReason::kDismissedByOs))
      .Times(1);

  fast_pair_notification_controller_->ShowSubsequentDiscoveryNotification(
      kTestDeviceName, kTestEmail,
      /*device_image=*/gfx::Image(), on_connect_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoverySubsequentNotificationId));
  test_message_center_.RemoveNotification(
      /*id=*/kFastPairDiscoverySubsequentNotificationId, /*by_user=*/false);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowSubsequentDiscoveryNotification_RemovedByTimeout) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoverySubsequentNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_connect_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  fast_pair_notification_controller_->ShowSubsequentDiscoveryNotification(
      kTestDeviceName, kTestEmail,
      /*device_image=*/gfx::Image(), on_connect_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();
  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoverySubsequentNotificationId));

  EXPECT_CALL(on_connect_clicked, Run).Times(0);
  EXPECT_CALL(on_learn_more_clicked, Run).Times(0);
  EXPECT_CALL(on_close,
              Run(FastPairNotificationDismissReason::kDismissedByTimeout))
      .Times(1);
  task_environment()->FastForwardBy(kNotificationTimeout);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotificationControllerTest,
       ShowSubsequentDiscoveryNotification_ExtendTimeout) {
  EXPECT_FALSE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoverySubsequentNotificationId));

  base::MockCallback<
      base::OnceCallback<void(FastPairNotificationDismissReason)>>
      on_close;
  base::MockCallback<base::RepeatingClosure> on_connect_clicked;
  base::MockCallback<base::RepeatingClosure> on_learn_more_clicked;
  fast_pair_notification_controller_->ShowSubsequentDiscoveryNotification(
      kTestDeviceName, kTestEmail,
      /*device_image=*/gfx::Image(), on_connect_clicked.Get(),
      on_learn_more_clicked.Get(), on_close.Get());
  base::RunLoop().RunUntilIdle();
  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoverySubsequentNotificationId));
  task_environment()->FastForwardBy(kNotificationShortTimeDuration);

  // Extend the notification to simulate the same device being found again. We
  // expect the notification to still be shown after the initial 12 second
  // timeout since the timeout should have been reset.
  fast_pair_notification_controller_->ExtendNotification();
  task_environment()->FastForwardBy(kNotificationTimeout);
  base::RunLoop().RunUntilIdle();
  EXPECT_TRUE(test_message_center_.FindVisibleNotificationById(
      kFastPairDiscoverySubsequentNotificationId));
}

}  // namespace quick_pair
}  // namespace ash