| // Copyright 2024 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ash/printing/cups_print_job_notification_utils.h" |
| |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "chrome/app/vector_icons/vector_icons.h" |
| #include "chrome/browser/apps/app_service/app_service_proxy.h" |
| #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" |
| #include "chrome/browser/ash/printing/cups_print_job.h" |
| #include "chrome/browser/chromeos/printing/printer_error_codes.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/grit/branded_strings.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "components/prefs/pref_service.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/chromeos/styles/cros_tokens_color_mappings.h" |
| #include "ui/message_center/public/cpp/notification.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| using ::chromeos::PrinterErrorCode; |
| |
| std::u16string GetAppShortNameUTF16(Profile* profile, |
| const std::string& app_id) { |
| if (apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile)) { |
| std::optional<std::u16string> app_name; |
| apps::AppServiceProxyFactory::GetForProfile(profile) |
| ->AppRegistryCache() |
| .ForOneApp(app_id, [&app_name](const apps::AppUpdate& update) { |
| app_name = base::UTF8ToUTF16(update.ShortName()); |
| }); |
| if (app_name) { |
| return *app_name; |
| } |
| } |
| // If no app name could be inferred, go with `Chrome` as a fallback option. |
| return l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME); |
| } |
| |
| std::u16string GetNotificationTitleForFailure(const CupsPrintJob& job) { |
| DCHECK_EQ(CupsPrintJob::State::STATE_FAILED, job.state()); |
| |
| switch (job.error_code()) { |
| case PrinterErrorCode::CLIENT_UNAUTHORIZED: |
| return l10n_util::GetStringUTF16( |
| IDS_PRINT_JOB_AUTHORIZATION_ERROR_NOTIFICATION_TITLE); |
| case PrinterErrorCode::EXPIRED_CERTIFICATE: |
| return l10n_util::GetStringUTF16( |
| IDS_PRINT_JOB_EXPIRED_CERT_ERROR_NOTIFICATION_TITLE); |
| default: |
| return l10n_util::GetStringUTF16(IDS_PRINT_JOB_ERROR_NOTIFICATION_TITLE); |
| } |
| } |
| |
| std::u16string GetNotificationTitleForError(const CupsPrintJob& job) { |
| DCHECK_EQ(CupsPrintJob::State::STATE_ERROR, job.state()); |
| |
| switch (job.error_code()) { |
| case PrinterErrorCode::PAPER_JAM: |
| return l10n_util::GetStringUTF16( |
| IDS_PRINT_JOB_PAPER_JAM_NOTIFICATION_TITLE); |
| case PrinterErrorCode::OUT_OF_INK: |
| return l10n_util::GetStringUTF16( |
| IDS_PRINT_JOB_OUT_OF_INK_NOTIFICATION_TITLE); |
| case PrinterErrorCode::OUT_OF_PAPER: |
| return l10n_util::GetStringUTF16( |
| IDS_PRINT_JOB_OUT_OF_PAPER_NOTIFICATION_TITLE); |
| case PrinterErrorCode::DOOR_OPEN: |
| return l10n_util::GetStringUTF16( |
| IDS_PRINT_JOB_DOOR_OPEN_NOTIFICATION_TITLE); |
| case PrinterErrorCode::PRINTER_UNREACHABLE: |
| return l10n_util::GetStringUTF16( |
| IDS_PRINT_JOB_PRINTER_UNREACHABLE_NOTIFICATION_TITLE); |
| case PrinterErrorCode::TRAY_MISSING: |
| return l10n_util::GetStringUTF16( |
| IDS_PRINT_JOB_TRAY_MISSING_NOTIFICATION_TITLE); |
| case PrinterErrorCode::OUTPUT_FULL: |
| return l10n_util::GetStringUTF16( |
| IDS_PRINT_JOB_OUTPUT_FULL_NOTIFICATION_TITLE); |
| case PrinterErrorCode::STOPPED: |
| return l10n_util::GetStringUTF16( |
| IDS_PRINT_JOB_STOPPED_NOTIFICATION_TITLE); |
| case PrinterErrorCode::EXPIRED_CERTIFICATE: |
| return l10n_util::GetStringUTF16( |
| IDS_PRINT_JOB_EXPIRED_CERT_ERROR_NOTIFICATION_TITLE); |
| default: |
| return l10n_util::GetStringUTF16(IDS_PRINT_JOB_ERROR_NOTIFICATION_TITLE); |
| } |
| } |
| |
| std::u16string GetNotificationBodyMessageForUnauthorizedClient( |
| const CupsPrintJob& job, |
| const Profile& profile) { |
| const std::u16string printer_name = |
| base::UTF8ToUTF16(job.printer().display_name()); |
| bool send_username_and_filename_policy_enabled = |
| profile.GetPrefs()->GetBoolean( |
| prefs::kPrintingSendUsernameAndFilenameEnabled); |
| if (send_username_and_filename_policy_enabled) { |
| return l10n_util::GetStringFUTF16( |
| IDS_PRINT_JOB_NOTIFICATION_CLIENT_UNAUTHORIZED_MESSAGE, |
| base::UTF8ToUTF16(profile.GetProfileUserName()), printer_name); |
| } else { |
| return l10n_util::GetStringFUTF16( |
| IDS_PRINT_JOB_NOTIFICATION_IDENTIFICATION_REQUIRED_MESSAGE, |
| printer_name); |
| } |
| } |
| |
| std::u16string GetNotificationBodyMessageForInProgressJob( |
| const CupsPrintJob& job, |
| Profile& profile) { |
| const std::u16string printer_name = |
| base::UTF8ToUTF16(job.printer().display_name()); |
| auto app_name = GetAppShortNameUTF16(&profile, job.source_id()); |
| if (job.total_page_number() > 1) { |
| const std::u16string pages = |
| base::NumberToString16(job.total_page_number()); |
| return l10n_util::GetStringFUTF16( |
| IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_IN_PROGRESS, app_name, pages, |
| printer_name); |
| } else { |
| return l10n_util::GetStringFUTF16( |
| IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_IN_PROGRESS_SINGLE_PAGE, |
| app_name, printer_name); |
| } |
| } |
| |
| std::u16string GetNotificationBodyMessageForCompletedJob( |
| const CupsPrintJob& job, |
| Profile& profile) { |
| const std::u16string printer_name = |
| base::UTF8ToUTF16(job.printer().display_name()); |
| return l10n_util::GetStringFUTF16( |
| IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_DONE, |
| GetAppShortNameUTF16(&profile, job.source_id()), printer_name); |
| } |
| |
| std::u16string GetNotificationBodyMessageForInterruptedJob( |
| const CupsPrintJob& job, |
| Profile& profile) { |
| const std::u16string printer_name = |
| base::UTF8ToUTF16(job.printer().display_name()); |
| return l10n_util::GetStringFUTF16( |
| IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_INTERRUPTED, |
| GetAppShortNameUTF16(&profile, job.source_id()), printer_name); |
| } |
| |
| } // namespace |
| |
| namespace printing::internal { |
| |
| void UpdateNotificationTitle(message_center::Notification* notification, |
| const CupsPrintJob& job) { |
| switch (job.state()) { |
| case CupsPrintJob::State::STATE_WAITING: |
| case CupsPrintJob::State::STATE_STARTED: |
| case CupsPrintJob::State::STATE_PAGE_DONE: |
| case CupsPrintJob::State::STATE_SUSPENDED: |
| case CupsPrintJob::State::STATE_RESUMED: |
| notification->set_title( |
| l10n_util::GetStringUTF16(IDS_PRINT_JOB_PRINTING_NOTIFICATION_TITLE)); |
| break; |
| case CupsPrintJob::State::STATE_DOCUMENT_DONE: |
| notification->set_title( |
| l10n_util::GetStringUTF16(IDS_PRINT_JOB_DONE_NOTIFICATION_TITLE)); |
| break; |
| case CupsPrintJob::State::STATE_FAILED: |
| notification->set_title(GetNotificationTitleForFailure(job)); |
| break; |
| case CupsPrintJob::State::STATE_ERROR: |
| notification->set_title(GetNotificationTitleForError(job)); |
| break; |
| case CupsPrintJob::State::STATE_CANCELLED: |
| NOTREACHED(); |
| default: |
| break; |
| } |
| } |
| |
| void UpdateNotificationIcon(message_center::Notification* notification, |
| const CupsPrintJob& job) { |
| switch (job.state()) { |
| case CupsPrintJob::State::STATE_WAITING: |
| case CupsPrintJob::State::STATE_STARTED: |
| case CupsPrintJob::State::STATE_PAGE_DONE: |
| case CupsPrintJob::State::STATE_SUSPENDED: |
| case CupsPrintJob::State::STATE_RESUMED: |
| notification->set_accent_color_id(cros_tokens::kCrosSysPrimary); |
| notification->set_vector_small_image(kNotificationPrintingIcon); |
| break; |
| case CupsPrintJob::State::STATE_DOCUMENT_DONE: |
| notification->set_accent_color_id(cros_tokens::kCrosSysPrimary); |
| notification->set_vector_small_image(kNotificationPrintingDoneIcon); |
| break; |
| case CupsPrintJob::State::STATE_FAILED: |
| case CupsPrintJob::State::STATE_ERROR: |
| notification->set_accent_color_id(cros_tokens::kCrosSysError); |
| notification->set_vector_small_image(kNotificationPrintingWarningIcon); |
| break; |
| case CupsPrintJob::State::STATE_CANCELLED: |
| NOTREACHED(); |
| case CupsPrintJob::State::STATE_NONE: |
| break; |
| } |
| } |
| |
| void UpdateNotificationBodyMessage(message_center::Notification* notification, |
| const CupsPrintJob& job, |
| Profile& profile) { |
| if (job.error_code() == PrinterErrorCode::CLIENT_UNAUTHORIZED) { |
| notification->set_message( |
| GetNotificationBodyMessageForUnauthorizedClient(job, profile)); |
| return; |
| } |
| |
| switch (job.state()) { |
| case CupsPrintJob::State::STATE_WAITING: |
| case CupsPrintJob::State::STATE_STARTED: |
| case CupsPrintJob::State::STATE_PAGE_DONE: |
| case CupsPrintJob::State::STATE_SUSPENDED: |
| case CupsPrintJob::State::STATE_RESUMED: |
| notification->set_message( |
| GetNotificationBodyMessageForInProgressJob(job, profile)); |
| return; |
| case CupsPrintJob::State::STATE_DOCUMENT_DONE: |
| notification->set_message( |
| GetNotificationBodyMessageForCompletedJob(job, profile)); |
| return; |
| case CupsPrintJob::State::STATE_FAILED: |
| case CupsPrintJob::State::STATE_ERROR: |
| notification->set_message( |
| GetNotificationBodyMessageForInterruptedJob(job, profile)); |
| return; |
| case CupsPrintJob::State::STATE_CANCELLED: |
| NOTREACHED(); |
| case CupsPrintJob::State::STATE_NONE: |
| return; |
| } |
| } |
| |
| } // namespace printing::internal |
| |
| } // namespace ash |