chromium/ash/system/firmware_update/firmware_update_notification_controller.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/system/firmware_update/firmware_update_notification_controller.h"

#include <optional>

#include "ash/constants/ash_features.h"
#include "ash/constants/notifier_catalogs.h"
#include "ash/public/cpp/new_window_delegate.h"
#include "ash/public/cpp/notification_utils.h"
#include "ash/public/cpp/system_tray_client.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/model/system_tray_model.h"
#include "base/strings/utf_string_conversions.h"
#include "components/user_manager/user_type.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/public/cpp/notification.h"
#include "ui/message_center/public/cpp/notification_types.h"
#include "url/gurl.h"

namespace ash {

namespace {
const char kNotifierFirmwareUpdate[] = "ash.firmware_update";
const char kFirmwareUpdateNotificationId[] =
    "cros_firmware_update_notification_id";

// Represents the buttons in the notification.
enum ButtonIndex { kUpdate };

void ShowFirmwareUpdate() {
  Shell::Get()->system_tray_model()->client()->ShowFirmwareUpdate();
}

void RemoveNotification(const std::string& notification_id) {
  message_center::MessageCenter::Get()->RemoveNotification(notification_id,
                                                           /*from_user=*/true);
}

void OnFirmwareUpdateAvailableNotificationClicked(
    std::optional<int> button_index) {
  // Clicked on body.
  if (!button_index) {
    ShowFirmwareUpdate();
    RemoveNotification(kFirmwareUpdateNotificationId);
    return;
  }

  // TODO(michaelcheco): Add "Remind me later" button.
  switch (*button_index) {
    case ButtonIndex::kUpdate:
      ShowFirmwareUpdate();
      break;
  }
  RemoveNotification(kFirmwareUpdateNotificationId);
}

bool ShouldShowNotification() {
  const std::optional<user_manager::UserType> user_type =
      Shell::Get()->session_controller()->GetUserType();
  if (!user_type) {
    return false;
  }

  switch (*user_type) {
    case user_manager::UserType::kPublicAccount:
    case user_manager::UserType::kGuest:
    case user_manager::UserType::kKioskApp:
    case user_manager::UserType::kWebKioskApp:
      return false;
    case user_manager::UserType::kRegular:
    case user_manager::UserType::kChild:
      return true;
  }
}

}  // namespace

FirmwareUpdateNotificationController::FirmwareUpdateNotificationController(
    message_center::MessageCenter* message_center)
    : message_center_(message_center) {
  DCHECK(message_center_);
  if (ash::FirmwareUpdateManager::IsInitialized()) {
    ash::FirmwareUpdateManager::Get()->AddObserver(this);
  }
}

FirmwareUpdateNotificationController::~FirmwareUpdateNotificationController() {
  if (ash::FirmwareUpdateManager::IsInitialized()) {
    ash::FirmwareUpdateManager::Get()->RemoveObserver(this);
  }
}

void FirmwareUpdateNotificationController::NotifyFirmwareUpdateAvailable() {
  message_center::RichNotificationData optional;
  optional.buttons.push_back(
      message_center::ButtonInfo(l10n_util::GetStringUTF16(
          IDS_ASH_FIRMWARE_UPDATE_NOTIFICATION_UPDATE_BUTTON_TEXT)));
  std::unique_ptr<message_center::Notification> notification =
      CreateSystemNotificationPtr(
          message_center::NOTIFICATION_TYPE_SIMPLE,
          kFirmwareUpdateNotificationId,
          l10n_util::GetStringUTF16(
              IDS_ASH_FIRMWARE_UPDATE_NOTIFICATION_UPDATE_AVAILABLE_TITLE),
          l10n_util::GetStringUTF16(
              IDS_ASH_FIRMWARE_UPDATE_NOTIFICATION_UPDATE_AVAILABLE_BODY),
          /*display_source=*/std::u16string(), GURL(),
          message_center::NotifierId(
              message_center::NotifierType::SYSTEM_COMPONENT,
              kNotifierFirmwareUpdate,
              NotificationCatalogName::kFirmwareUpdate),
          optional,
          base::MakeRefCounted<message_center::HandleNotificationClickDelegate>(
              base::BindRepeating(
                  &OnFirmwareUpdateAvailableNotificationClicked)),
          kSettingsIcon,
          message_center::SystemNotificationWarningLevel::NORMAL);

  message_center_->AddNotification(std::move(notification));
}

void FirmwareUpdateNotificationController::OnFirmwareUpdateReceived() {
  if (should_show_notification_for_test_ || ShouldShowNotification()) {
    NotifyFirmwareUpdateAvailable();
  }
}

}  // namespace ash