chromium/ash/multi_device_setup/multi_device_notification_presenter.h

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

#ifndef ASH_MULTI_DEVICE_SETUP_MULTI_DEVICE_NOTIFICATION_PRESENTER_H_
#define ASH_MULTI_DEVICE_SETUP_MULTI_DEVICE_NOTIFICATION_PRESENTER_H_

#include <memory>
#include <string>

#include "ash/ash_export.h"
#include "ash/public/cpp/session/session_observer.h"
#include "base/auto_reset.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chromeos/ash/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "ui/message_center/message_center_observer.h"

namespace message_center {
class MessageCenter;
class Notification;
class RichNotificationData;
}  // namespace message_center

namespace ash {

// Presents notifications necessary for MultiDevice setup flow. It observes the
// MultiDeviceSetup mojo service to show a notification when
// (1) a potential host is found for someone who has not gone through the setup
//     flow before,
// (2) the host has switched for someone who has, or
// (3) a new Chromebook has been added to an account for someone who has.
//
// The behavior caused by clicking a notification depends its content as
// described above:
// (1) triggers the setup UI to appear to prompt setup flow and
// (2) & (3) open the Connected Devices subpage in Settings.
//
// Note that if one notification is showing and another one is triggered, the
// old text is replaced (if it's different) and the notification pops up again.
class ASH_EXPORT MultiDeviceNotificationPresenter
    : public multidevice_setup::mojom::AccountStatusChangeDelegate,
      public SessionObserver,
      public message_center::MessageCenterObserver {
 public:
  explicit MultiDeviceNotificationPresenter(
      message_center::MessageCenter* message_center);

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

  ~MultiDeviceNotificationPresenter() override;

  // Disables notifications for tests.
  static std::unique_ptr<base::AutoReset<bool>>
  DisableNotificationsForTesting();

  // Removes the notification created by NotifyPotentialHostExists() or does
  // nothing if that notification is not currently displayed.
  void RemoveMultiDeviceSetupNotification();

  void UpdateIsSetupNotificationInteracted(
      bool is_setup_notificaton_interacted);

  // MultiDevice setup notification ID. Public so it can be accessed from
  // phone_hub_tray.cc
  static const char kSetupNotificationId[];

 protected:
  // multidevice_setup::mojom::AccountStatusChangeDelegate:
  void OnPotentialHostExistsForNewUser() override;
  void OnNoLongerNewUser() override;
  void OnConnectedHostSwitchedForExistingUser(
      const std::string& new_host_device_name) override;
  void OnNewChromebookAddedForExistingUser(
      const std::string& new_host_device_name) override;
  void OnBecameEligibleForWifiSync() override;

  // SessionObserver:
  void OnUserSessionAdded(const AccountId& account_id) override;
  void OnSessionStateChanged(session_manager::SessionState state) override;

  // message_center::MessageCenterObserver
  void OnNotificationRemoved(const std::string& notification_id,
                             bool by_user) override;

  void OnNotificationClicked(
      const std::string& notification_id,
      const std::optional<int>& button_index,
      const std::optional<std::u16string>& reply) override;

 private:
  friend class MultiDeviceNotificationPresenterTest;

  // MultiDevice setup notification ID.
  static const char kWifiSyncNotificationId[];

  // Represents each possible MultiDevice setup notification that the setup flow
  // can show with a "none" option for the general state with no notification
  // present.
  enum class Status {
    kNoNotificationVisible,
    kNewUserNotificationVisible,
    kExistingUserHostSwitchedNotificationVisible,
    kExistingUserNewChromebookNotificationVisible
  };

  // Reflects MultiDeviceSetupNotification enum in enums.xml. Do not
  // rearrange.
  enum class NotificationType {
    kNewUserPotentialHostExists = 0,
    kExistingUserHostSwitched = 1,
    kExistingUserNewChromebookAdded = 2,
    // This is a legacy error case that is not expected to occur.
    kErrorUnknown = 3,
    kWifiSyncAnnouncement = 4,
    kMaxValue = kWifiSyncAnnouncement
  };

  static NotificationType GetMetricValueForNotification(
      Status notification_status);

  static std::string GetNotificationDescriptionForLogging(
      Status notification_status);

  void ObserveMultiDeviceSetupIfPossible();
  void ShowSetupNotification(const Status notification_status,
                             const std::u16string& title,
                             const std::u16string& message);
  void ShowNotification(const std::string& id,
                        const std::u16string& title,
                        const std::u16string& message,
                        message_center::RichNotificationData optional_fields);

  void FlushForTesting();

  // Indicates if Phone Hub icon is clicked when the setup notification is
  // visible. If the value is true, we do not log event to
  // MultiDevice.Setup.NotificationInteracted histogram.
  bool is_setup_notification_interacted_ = false;

  raw_ptr<message_center::MessageCenter> message_center_;

  // Notification currently showing or
  // Status::kNoNotificationVisible if there isn't one.
  Status notification_status_ = Status::kNoNotificationVisible;

  mojo::Remote<multidevice_setup::mojom::MultiDeviceSetup>
      multidevice_setup_remote_;
  mojo::Receiver<multidevice_setup::mojom::AccountStatusChangeDelegate>
      receiver_{this};

  base::WeakPtrFactory<MultiDeviceNotificationPresenter> weak_ptr_factory_{
      this};
};

}  // namespace ash

#endif  // ASH_MULTI_DEVICE_SETUP_MULTI_DEVICE_NOTIFICATION_PRESENTER_H_