[go: nahoru, domu]

[Printing] Enrich CupsPrintingNotification for Web Printing API jobs

Jobs initiated by Isolated Web Apps (IWAs) via the Web Printing API do
not require a print dialog which allows these apps to print silently.
To keep the user aware of what is actually happening, it's necessary to
augment the existing printing notification with a few important details:
* The name of the initiating IWA;
* An option to revoke the IWA's permission to print.

To achieve the latter while preserving the existing behavior (open the
print management app on click), the notification is now equipped with
two buttons: one brings the user to the content settings page, and the
other opens the print management app as before.

Note that these changes only apply to jobs submitted via the Web
Printing API; for all others notifications follow the existing model.

On top of that, a few messages are updated to align with the modern
UX guidance:
* Printing started -> Printing...
* Printing complete -> Done

See go/advanced-printer-features-wd for details on wordsmithing.

Bug: b/302505962
Change-Id: Ie2c62ae1f9c271070a352a0d4f11cc5a00f7cafa
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5224206
Commit-Queue: Andrew Rayskiy <greengrape@google.com>
Reviewed-by: Dana Fried <dfried@chromium.org>
Reviewed-by: Benjamin Gordon <bmgordon@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1258479}
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index e379d74a..14ddd687 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -4756,10 +4756,10 @@
     Print
   </message>
   <message name="IDS_PRINT_JOB_PRINTING_NOTIFICATION_TITLE" desc="Title of the printing-in-progress notification.">
-    Printing started
+    Printing...
   </message>
   <message name="IDS_PRINT_JOB_DONE_NOTIFICATION_TITLE" desc="Title of the successful printing notification.">
-    Printing complete
+    Done
   </message>
   <message name="IDS_PRINT_JOB_ERROR_NOTIFICATION_TITLE" desc="Title of the error printing notification.">
     Couldn't print. Check printer and try again.
@@ -4794,17 +4794,29 @@
   <message name="IDS_PRINT_JOB_STOPPED_NOTIFICATION_TITLE" desc="Title of the error printing notification.">
     Printer has stopped
   </message>
-  <message name="IDS_PRINT_JOB_NOTIFICATION_MESSAGE" desc="Message of the print job notification.">
-    <ph name="PAGE_NUMBER">$1<ex>5</ex></ph> pages to <ph name="PRINTER_NAME">$2<ex>printer</ex></ph>
-  </message>
   <message name="IDS_PRINT_JOB_NOTIFICATION_CLIENT_UNAUTHORIZED_MESSAGE" desc="Message of the print job notification when client is unauthorized.">
     <ph name="PROFILE_USERNAME">$1</ph> is not authorized to print to <ph name="PRINTER_NAME">$2<ex>printer</ex></ph>. Please contact your administrator.
   </message>
   <message name="IDS_PRINT_JOB_NOTIFICATION_IDENTIFICATION_REQUIRED_MESSAGE" desc="Message of the print job notification when credentials is not sent to the printer.">
     Identification required to print to <ph name="PRINTER_NAME">$1<ex>printer</ex></ph>. Please contact your administrator.
   </message>
-  <message name="IDS_PRINT_JOB_NOTIFICATION_SINGLE_PAGE_MESSAGE" desc="Message of the print job notification for a single page.">
-    1 page to <ph name="PRINTER_NAME">$1<ex>printer</ex></ph>
+  <message name="IDS_PRINT_JOB_PRINTING_CONTENT_SETTINGS_PAGE" desc="Caption of the button in the printing notification that brings the user to the content settings page for Web Printing.">
+    Permissions
+  </message>
+  <message name="IDS_PRINT_JOB_PRINTING_PRINT_MANAGEMENT_PAGE" desc="Caption of the button in the printing notification that brings the user to the print management page.">
+    Print jobs
+  </message>
+  <message name="IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_IN_PROGRESS" desc="Message of the print job notification while printing is in progress.">
+    <ph name="APP_NAME">$1<ex>Application</ex></ph> is printing <ph name="PAGE_NUMBER">$2<ex>5</ex></ph> pages to <ph name="PRINTER_NAME">$3<ex>printer</ex></ph>
+  </message>
+  <message name="IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_IN_PROGRESS_SINGLE_PAGE" desc="Message of the print job notification while printing is in progress when there's only one page to print.">
+    <ph name="APP_NAME">$1<ex>Application</ex></ph> is printing 1 page to <ph name="PRINTER_NAME">$2<ex>printer</ex></ph>
+  </message>
+  <message name="IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_DONE" desc="Message of the print job notification when printing is finished.">
+    <ph name="APP_NAME">$1<ex>Application</ex></ph> has finished printing to <ph name="PRINTER_NAME">$2<ex>printer</ex></ph>
+  </message>
+  <message name="IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_INTERRUPTED" desc="Message of the print job notification when printing is interrupted.">
+    <ph name="APP_NAME">$1<ex>Application</ex></ph> is trying to print to <ph name="PRINTER_NAME">$2<ex>printer</ex></ph>
   </message>
 
   <!-- USB Printer Installation Notification -->
diff --git a/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_DONE_NOTIFICATION_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_DONE_NOTIFICATION_TITLE.png.sha1
new file mode 100644
index 0000000..7f3ef18
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_DONE_NOTIFICATION_TITLE.png.sha1
@@ -0,0 +1 @@
+860457324c8485eb220a49eedb7d24f046819688
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_DONE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_DONE.png.sha1
new file mode 100644
index 0000000..7f3ef18
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_DONE.png.sha1
@@ -0,0 +1 @@
+860457324c8485eb220a49eedb7d24f046819688
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_INTERRUPTED.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_INTERRUPTED.png.sha1
new file mode 100644
index 0000000..34a0574e
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_INTERRUPTED.png.sha1
@@ -0,0 +1 @@
+f1e9b01b072cd19ccf120f9cb8dfe9311ed5e144
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_IN_PROGRESS.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_IN_PROGRESS.png.sha1
new file mode 100644
index 0000000..502b0ca
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_IN_PROGRESS.png.sha1
@@ -0,0 +1 @@
+9fe4d6d3a96aff0e83d6f754a8b28d2a331e9bbc
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_IN_PROGRESS_SINGLE_PAGE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_IN_PROGRESS_SINGLE_PAGE.png.sha1
new file mode 100644
index 0000000..4430d77
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_IN_PROGRESS_SINGLE_PAGE.png.sha1
@@ -0,0 +1 @@
+edd5059bf59dfc060219be9b55bcb9bc05fbcc48
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_PRINTING_CONTENT_SETTINGS_PAGE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_PRINTING_CONTENT_SETTINGS_PAGE.png.sha1
new file mode 100644
index 0000000..cad4461
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_PRINTING_CONTENT_SETTINGS_PAGE.png.sha1
@@ -0,0 +1 @@
+9f9a99a3de3623ed515b7e59b3c4de8500bc42c1
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_PRINTING_NOTIFICATION_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_PRINTING_NOTIFICATION_TITLE.png.sha1
index f31e38d..cad4461 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_PRINTING_NOTIFICATION_TITLE.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_PRINTING_NOTIFICATION_TITLE.png.sha1
@@ -1 +1 @@
-9f03b9265cd9cc8df0907337872284d7205e612a
\ No newline at end of file
+9f9a99a3de3623ed515b7e59b3c4de8500bc42c1
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_PRINTING_PRINT_MANAGEMENT_PAGE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_PRINTING_PRINT_MANAGEMENT_PAGE.png.sha1
new file mode 100644
index 0000000..cad4461
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_PRINT_JOB_PRINTING_PRINT_MANAGEMENT_PAGE.png.sha1
@@ -0,0 +1 @@
+9f9a99a3de3623ed515b7e59b3c4de8500bc42c1
\ No newline at end of file
diff --git a/chrome/browser/ash/printing/cups_print_job_notification.cc b/chrome/browser/ash/printing/cups_print_job_notification.cc
index 45449cc..c4b869d12 100644
--- a/chrome/browser/ash/printing/cups_print_job_notification.cc
+++ b/chrome/browser/ash/printing/cups_print_job_notification.cc
@@ -37,6 +37,16 @@
 
 constexpr int64_t kSuccessTimeoutSeconds = 8;
 
+constexpr uint32_t kPrintManagementPageButtonIndex = 0;
+
+// This button only appears in notifications for print jobs initiated by the Web
+// Printing API.
+constexpr uint32_t kWebPrintingContentSettingsButtonIndex = 1;
+
+bool IsPrintJobInitiatedByWebPrintingAPI(const CupsPrintJob& job) {
+  return job.source() == crosapi::mojom::PrintJob::Source::kIsolatedWebApp;
+}
+
 }  // namespace
 
 CupsPrintJobNotification::CupsPrintJobNotification(
@@ -47,6 +57,8 @@
       notification_id_(print_job->GetUniqueId()),
       print_job_(print_job),
       profile_(profile),
+      is_web_printing_api_initiated_(
+          IsPrintJobInitiatedByWebPrintingAPI(*print_job)),
       success_timer_(std::make_unique<base::OneShotTimer>()) {
   // Create a notification for the print job. The title, body, and icon of the
   // notification will be updated in UpdateNotification().
@@ -63,6 +75,14 @@
       message_center::RichNotificationData(),
       base::MakeRefCounted<message_center::ThunkNotificationDelegate>(
           weak_factory_.GetWeakPtr()));
+  std::vector<message_center::ButtonInfo> buttons;
+  buttons.emplace_back(
+      l10n_util::GetStringUTF16(IDS_PRINT_JOB_PRINTING_PRINT_MANAGEMENT_PAGE));
+  if (is_web_printing_api_initiated_) {
+    buttons.emplace_back(l10n_util::GetStringUTF16(
+        IDS_PRINT_JOB_PRINTING_CONTENT_SETTINGS_PAGE));
+  }
+  notification_->set_buttons(buttons);
   UpdateNotification();
 }
 
@@ -86,13 +106,24 @@
 void CupsPrintJobNotification::Click(
     const std::optional<int>& button_index,
     const std::optional<std::u16string>& reply) {
-  // If we are in guest mode then we need to use the OffTheRecord profile to
-  // open the Print Manageament App. There is a check in Browser::Browser
-  // that only OffTheRecord profiles can open browser windows in guest mode.
-  chrome::ShowPrintManagementApp(
-      profile_->IsGuestSession()
-          ? profile_->GetPrimaryOTRProfile(/*create_if_needed=*/true)
-          : profile_.get());
+  if (!button_index) {
+    return;
+  }
+
+  switch (*button_index) {
+    case kPrintManagementPageButtonIndex:
+      chrome::ShowPrintManagementApp(profile_);
+      break;
+    case kWebPrintingContentSettingsButtonIndex:
+      CHECK(is_web_printing_api_initiated_)
+          << "Regular print jobs are not supposed to show permissions button.";
+      // Navigates to `chrome://settings/content/webPrinting`.
+      chrome::ShowContentSettingsExceptionsForProfile(
+          profile_, ContentSettingsType::WEB_PRINTING);
+      break;
+    default:
+      NOTREACHED();
+  }
 }
 
 message_center::Notification*
diff --git a/chrome/browser/ash/printing/cups_print_job_notification.h b/chrome/browser/ash/printing/cups_print_job_notification.h
index 3685bff..c0d921cf 100644
--- a/chrome/browser/ash/printing/cups_print_job_notification.h
+++ b/chrome/browser/ash/printing/cups_print_job_notification.h
@@ -64,6 +64,12 @@
   base::WeakPtr<CupsPrintJob> print_job_;
   raw_ptr<Profile> profile_;
 
+  // Whether this print job has been submitted via the Web Printing API.
+  // This field is separate from `print_job_` since the WeakPtr might expire
+  // while the notification is still being shown, which could affect the logic
+  // of handling clicks.
+  const bool is_web_printing_api_initiated_;
+
   // If the notification has been closed in the middle of printing or not. If it
   // is true, then prevent the following print job progress update after close,
   // and only show the print job done or failed notification.
diff --git a/chrome/browser/ash/printing/cups_print_job_notification_unittest.cc b/chrome/browser/ash/printing/cups_print_job_notification_unittest.cc
index c04902b..6fd6d05 100644
--- a/chrome/browser/ash/printing/cups_print_job_notification_unittest.cc
+++ b/chrome/browser/ash/printing/cups_print_job_notification_unittest.cc
@@ -5,11 +5,15 @@
 #include "chrome/browser/ash/printing/cups_print_job_notification_manager.h"
 
 #include "base/check_deref.h"
+#include "chrome/browser/apps/app_service/app_service_proxy.h"
+#include "chrome/browser/apps/app_service/app_service_test.h"
 #include "chrome/browser/ash/printing/cups_print_job.h"
 #include "chrome/browser/ash/printing/cups_print_job_notification.h"
 #include "chrome/browser/ash/printing/fake_cups_print_job_manager.h"
+#include "chrome/grit/branded_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/services/app_service/public/cpp/app_types.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -24,34 +28,88 @@
 using testing::Eq;
 using testing::Property;
 
+constexpr char kAppId[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+
+constexpr char kAppName[] = "app_name";
+constexpr char16_t kAppName16[] = u"app_name";
+
+constexpr char kPrinterName[] = "printer";
+constexpr char16_t kPrinterName16[] = u"printer";
+
 }  // namespace
 
-class CupsPrintJobNotificationTest : public testing::Test {
+class CupsPrintJobNotificationTest : public testing::Test,
+                                     public testing::WithParamInterface<bool> {
  protected:
   CupsPrintJobNotificationTest()
       : print_job_manager_(&profile_),
         notification_manager_(&profile_, &print_job_manager_) {}
 
+  void SetUp() override {
+    testing::Test::SetUp();
+
+    // Wait for AppServiceProxy to be ready.
+    app_service_test_.SetUp(&profile_);
+    if (IsWebPrintingTest()) {
+      AddIWA(kAppId, kAppName);
+    }
+  }
+
+  CupsPrintJob CreateCupsPrintJob(const std::string& printer_name,
+                                  uint32_t total_page_number) {
+    chromeos::Printer printer;
+    printer.set_display_name(printer_name);
+
+    if (IsWebPrintingTest()) {
+      return CupsPrintJob(
+          printer, /*job_id=*/0, /*document_title=*/std::string(),
+          total_page_number, crosapi::mojom::PrintJob::Source::kIsolatedWebApp,
+          /*source_id=*/kAppId, printing::proto::PrintSettings());
+    } else {
+      return CupsPrintJob(
+          printer, /*job_id=*/0, /*document_title=*/std::string(),
+          total_page_number, crosapi::mojom::PrintJob::Source::kUnknown,
+          /*source_id=*/std::string(), printing::proto::PrintSettings());
+    }
+  }
+
   std::unique_ptr<CupsPrintJobNotification> CreateNotificationForJob(
       base::WeakPtr<CupsPrintJob> job) {
     return std::make_unique<CupsPrintJobNotification>(&notification_manager_,
                                                       job, &profile_);
   }
 
+  std::u16string GetExpectedNotificationAppName() const {
+    return IsWebPrintingTest()
+               ? kAppName16
+               : l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME);
+  }
+
+ private:
+  bool IsWebPrintingTest() const { return GetParam(); }
+
+  void AddIWA(const std::string& app_id, const std::string& short_name) {
+    std::vector<apps::AppPtr> apps;
+    apps::AppPtr app = std::make_unique<apps::App>(apps::AppType::kWeb, app_id);
+    app->app_id = app_id;
+    app->readiness = apps::Readiness::kReady;
+    app->short_name = short_name;
+    apps.push_back(std::move(app));
+    app_service_test_.proxy()->OnApps(std::move(apps), apps::AppType::kWeb,
+                                      /*should_notify_initialized=*/false);
+  }
+
   content::BrowserTaskEnvironment task_environment_;
   TestingProfile profile_;
   FakeCupsPrintJobManager print_job_manager_;
   CupsPrintJobNotificationManager notification_manager_;
+
+  apps::AppServiceTest app_service_test_;
 };
 
 // Validates notification for the CLIENT_UNAUTHORIZED error.
-TEST_F(CupsPrintJobNotificationTest, ClientUnauthorized) {
-  chromeos::Printer printer;
-
-  printer.set_display_name("printer");
-  CupsPrintJob job(printer, 0, std::string(), /*total_page_number=*/1,
-                   crosapi::mojom::PrintJob::Source::kUnknown, std::string(),
-                   printing::proto::PrintSettings());
+TEST_P(CupsPrintJobNotificationTest, ClientUnauthorized) {
+  CupsPrintJob job = CreateCupsPrintJob(kPrinterName, /*total_page_number=*/1);
 
   // Create notification.
   auto cups_notification = CreateNotificationForJob(job.GetWeakPtr());
@@ -73,17 +131,12 @@
               &message_center::Notification::message,
               Eq(l10n_util::GetStringFUTF16(
                   IDS_PRINT_JOB_NOTIFICATION_IDENTIFICATION_REQUIRED_MESSAGE,
-                  u"printer")))));
+                  kPrinterName16)))));
 }
 
 // Validates notification for a running job.
-TEST_F(CupsPrintJobNotificationTest, RunningJob) {
-  chromeos::Printer printer;
-
-  printer.set_display_name("printer");
-  CupsPrintJob job(printer, 0, std::string(), /*total_page_number=*/10,
-                   crosapi::mojom::PrintJob::Source::kUnknown, std::string(),
-                   printing::proto::PrintSettings());
+TEST_P(CupsPrintJobNotificationTest, RunningJob) {
+  CupsPrintJob job = CreateCupsPrintJob(kPrinterName, /*total_page_number=*/10);
 
   // Create notification.
   auto cups_notification = CreateNotificationForJob(job.GetWeakPtr());
@@ -94,24 +147,21 @@
 
   const auto& notification =
       CHECK_DEREF(cups_notification->GetNotificationDataForTesting());
-  EXPECT_THAT(notification,
-              AllOf(Property(&message_center::Notification::title,
-                             Eq(l10n_util::GetStringUTF16(
-                                 IDS_PRINT_JOB_PRINTING_NOTIFICATION_TITLE))),
-                    Property(&message_center::Notification::message,
-                             Eq(l10n_util::GetStringFUTF16(
-                                 IDS_PRINT_JOB_NOTIFICATION_MESSAGE, u"10",
-                                 u"printer")))));
+  EXPECT_THAT(
+      notification,
+      AllOf(Property(&message_center::Notification::title,
+                     Eq(l10n_util::GetStringUTF16(
+                         IDS_PRINT_JOB_PRINTING_NOTIFICATION_TITLE))),
+            Property(&message_center::Notification::message,
+                     Eq(l10n_util::GetStringFUTF16(
+                         IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_IN_PROGRESS,
+                         GetExpectedNotificationAppName(), u"10",
+                         kPrinterName16)))));
 }
 
 // Validates notification for a running job with a single page.
-TEST_F(CupsPrintJobNotificationTest, RunningJobSinglePage) {
-  chromeos::Printer printer;
-
-  printer.set_display_name("printer");
-  CupsPrintJob job(printer, 0, std::string(), /*total_page_number=*/1,
-                   crosapi::mojom::PrintJob::Source::kUnknown, std::string(),
-                   printing::proto::PrintSettings());
+TEST_P(CupsPrintJobNotificationTest, RunningJobSinglePage) {
+  CupsPrintJob job = CreateCupsPrintJob(kPrinterName, /*total_page_number=*/1);
 
   // Create notification.
   auto cups_notification = CreateNotificationForJob(job.GetWeakPtr());
@@ -122,24 +172,22 @@
 
   const auto& notification =
       CHECK_DEREF(cups_notification->GetNotificationDataForTesting());
-  EXPECT_THAT(notification,
-              AllOf(Property(&message_center::Notification::title,
-                             Eq(l10n_util::GetStringUTF16(
-                                 IDS_PRINT_JOB_PRINTING_NOTIFICATION_TITLE))),
-                    Property(&message_center::Notification::message,
-                             Eq(l10n_util::GetStringFUTF16(
-                                 IDS_PRINT_JOB_NOTIFICATION_SINGLE_PAGE_MESSAGE,
-                                 u"printer")))));
+  EXPECT_THAT(
+      notification,
+      AllOf(
+          Property(&message_center::Notification::title,
+                   Eq(l10n_util::GetStringUTF16(
+                       IDS_PRINT_JOB_PRINTING_NOTIFICATION_TITLE))),
+          Property(
+              &message_center::Notification::message,
+              Eq(l10n_util::GetStringFUTF16(
+                  IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_IN_PROGRESS_SINGLE_PAGE,
+                  GetExpectedNotificationAppName(), kPrinterName16)))));
 }
 
 // Validates notification for a completed job.
-TEST_F(CupsPrintJobNotificationTest, JobDone) {
-  chromeos::Printer printer;
-
-  printer.set_display_name("printer");
-  CupsPrintJob job(printer, 0, std::string(), /*total_page_number=*/1,
-                   crosapi::mojom::PrintJob::Source::kUnknown, std::string(),
-                   printing::proto::PrintSettings());
+TEST_P(CupsPrintJobNotificationTest, JobDone) {
+  CupsPrintJob job = CreateCupsPrintJob(kPrinterName, /*total_page_number=*/1);
 
   // Create notification.
   auto cups_notification = CreateNotificationForJob(job.GetWeakPtr());
@@ -150,14 +198,19 @@
 
   const auto& notification =
       CHECK_DEREF(cups_notification->GetNotificationDataForTesting());
-  EXPECT_THAT(notification,
-              AllOf(Property(&message_center::Notification::title,
-                             Eq(l10n_util::GetStringUTF16(
-                                 IDS_PRINT_JOB_DONE_NOTIFICATION_TITLE))),
-                    Property(&message_center::Notification::message,
-                             Eq(l10n_util::GetStringFUTF16(
-                                 IDS_PRINT_JOB_NOTIFICATION_SINGLE_PAGE_MESSAGE,
-                                 u"printer")))));
+  EXPECT_THAT(
+      notification,
+      AllOf(Property(&message_center::Notification::title,
+                     Eq(l10n_util::GetStringUTF16(
+                         IDS_PRINT_JOB_DONE_NOTIFICATION_TITLE))),
+            Property(&message_center::Notification::message,
+                     Eq(l10n_util::GetStringFUTF16(
+                         IDS_PRINT_JOB_NOTIFICATION_APP_PRINTING_DONE,
+                         GetExpectedNotificationAppName(), kPrinterName16)))));
 }
 
+// The boolean controls whether the test is instantiated for Web Printing API
+// job notifications or regular job notifications.
+INSTANTIATE_TEST_SUITE_P(/**/, CupsPrintJobNotificationTest, testing::Bool());
+
 }  // namespace ash
diff --git a/chrome/browser/ash/printing/cups_print_job_notification_utils.cc b/chrome/browser/ash/printing/cups_print_job_notification_utils.cc
index 1d8a88ed..5bd11a9 100644
--- a/chrome/browser/ash/printing/cups_print_job_notification_utils.cc
+++ b/chrome/browser/ash/printing/cups_print_job_notification_utils.cc
@@ -6,10 +6,13 @@
 
 #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"
@@ -22,6 +25,23 @@
 
 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());
 
@@ -92,20 +112,45 @@
   }
 }
 
-std::u16string GetGenericNotificationBodyMessage(const CupsPrintJob& job) {
+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_MESSAGE, pages,
-                                      printer_name);
+    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_SINGLE_PAGE_MESSAGE, printer_name);
+        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 {
@@ -125,13 +170,15 @@
       notification->set_title(
           l10n_util::GetStringUTF16(IDS_PRINT_JOB_DONE_NOTIFICATION_TITLE));
       break;
-    case CupsPrintJob::State::STATE_CANCELLED:
     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();
+      break;
     default:
       break;
   }
@@ -152,12 +199,14 @@
       notification->set_accent_color_id(cros_tokens::kCrosSysPrimary);
       notification->set_vector_small_image(kNotificationPrintingDoneIcon);
       break;
-    case CupsPrintJob::State::STATE_CANCELLED:
     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();
+      break;
     case CupsPrintJob::State::STATE_NONE:
       break;
   }
@@ -171,7 +220,31 @@
         GetNotificationBodyMessageForUnauthorizedClient(job, profile));
     return;
   }
-  notification->set_message(GetGenericNotificationBodyMessage(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_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();
+      return;
+    case CupsPrintJob::State::STATE_NONE:
+      return;
+  }
 }
 
 }  // namespace printing::internal
diff --git a/chrome/browser/ui/chrome_pages.cc b/chrome/browser/ui/chrome_pages.cc
index b23f9823..f5aa2af 100644
--- a/chrome/browser/ui/chrome_pages.cc
+++ b/chrome/browser/ui/chrome_pages.cc
@@ -10,6 +10,7 @@
 
 #include "ash/webui/shortcut_customization_ui/url_constants.h"
 #include "base/containers/fixed_flat_map.h"
+#include "base/containers/map_util.h"
 #include "base/feature_list.h"
 #include "base/logging.h"
 #include "base/metrics/user_metrics.h"
@@ -202,7 +203,7 @@
   // will no longer be needed.
 
   static constexpr auto kSettingsPathOverrides =
-      base::MakeFixedFlatMap<ContentSettingsType, base::StringPiece>({
+      base::MakeFixedFlatMap<ContentSettingsType, std::string_view>({
           {ContentSettingsType::AUTOMATIC_DOWNLOADS, "automaticDownloads"},
           {ContentSettingsType::BACKGROUND_SYNC, "backgroundSync"},
           {ContentSettingsType::MEDIASTREAM_MIC, "microphone"},
@@ -212,14 +213,15 @@
           {ContentSettingsType::HID_CHOOSER_DATA, "hidDevices"},
           {ContentSettingsType::STORAGE_ACCESS, "storageAccess"},
           {ContentSettingsType::USB_CHOOSER_DATA, "usbDevices"},
+          {ContentSettingsType::WEB_PRINTING, "webPrinting"},
       });
 
-  const auto* it = kSettingsPathOverrides.find(type);
-
-  return base::StrCat({kContentSettingsSubPage, "/",
-                       (it == kSettingsPathOverrides.end())
-                           ? site_settings::ContentSettingsTypeToGroupName(type)
-                           : it->second});
+  const std::string_view* override =
+      base::FindOrNull(kSettingsPathOverrides, type);
+  return base::StrCat(
+      {kContentSettingsSubPage, "/",
+       override ? *override
+                : site_settings::ContentSettingsTypeToGroupName(type)});
 }
 
 bool SiteGURLIsValid(const GURL& url) {