Use chip framework for quiet notification prompt.

This CL adds the possibility to display a permission prompt in a less
prominent chip. Only requests from origins with an abusive reputation
will be scheduled for the quiet chip.

[Google internal] All test cases for the quiet chip.
https://docs.google.com/spreadsheets/d/1AxruYU2ZrqGN06sNtWxjmkr_a0EaG89vbJRHY4A36zA/edit?usp=sharing

Bug: 1177760
Change-Id: Iaf1a7204b56d64e3aedbdba4e68f7f82b62d43c3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2690644
Commit-Queue: Illia Klimov <[email protected]>
Reviewed-by: Balazs Engedy <[email protected]>
Reviewed-by: Caitlin Fischer <[email protected]>
Reviewed-by: Andy Paicu <[email protected]>
Reviewed-by: Bret Sepulveda <[email protected]>
Cr-Commit-Position: refs/heads/master@{#899187}
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 2f44446..1096917 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -6456,6 +6456,9 @@
      kOsDesktop,
      FEATURE_VALUE_TYPE(
          permissions::features::kPermissionChipRequestTypeSensitive)},
+    {"permission-quiet-chip", flag_descriptions::kPermissionQuietChipName,
+     flag_descriptions::kPermissionQuietChipDescription, kOsDesktop,
+     FEATURE_VALUE_TYPE(permissions::features::kPermissionQuietChip)},
 
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
     {"dice-web-signin-interception",
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index cf844437..0e4d5f3 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -4352,6 +4352,11 @@
     "expiry_milestone": 93
   },
   {
+    "name": "permission-quiet-chip",
+    "owners": [ "elklm", "engedy"],
+    "expiry_milestone": 100
+  },
+  {
     "name": "photo-picker-video-support",
     "owners": [ "finnur" ],
     "expiry_milestone": 92
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index c49aaaa..272a6fd 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2070,6 +2070,13 @@
     "chrome://flags/#quiet-notification-prompts and `Safe Browsing Enhanced "
     "Protection` to be enabled.";
 
+const char kPermissionQuietChipName[] = "Quiet Permission Chip Experiment";
+const char kPermissionQuietChipDescription[] =
+    "Enables an experimental permission prompt that uses the quiet chip "
+    "instead of the right-hand side address bar icon for quiet permission "
+    "prompts. Requires chrome://flags/#quiet-notification-prompts to be "
+    "enabled.";
+
 const char kPlaybackSpeedButtonName[] = "Playback Speed Button";
 const char kPlaybackSpeedButtonDescription[] =
     "Enable the playback speed button on the media controls.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index c79cf54..ccdbe9a 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1183,6 +1183,9 @@
 extern const char kPermissionPredictionsName[];
 extern const char kPermissionPredictionsDescription[];
 
+extern const char kPermissionQuietChipName[];
+extern const char kPermissionQuietChipDescription[];
+
 extern const char kPlaybackSpeedButtonName[];
 extern const char kPlaybackSpeedButtonDescription[];
 
diff --git a/chrome/browser/permissions/permission_request_manager_browsertest.cc b/chrome/browser/permissions/permission_request_manager_browsertest.cc
index b70466a..e44899c 100644
--- a/chrome/browser/permissions/permission_request_manager_browsertest.cc
+++ b/chrome/browser/permissions/permission_request_manager_browsertest.cc
@@ -826,7 +826,7 @@
   base::RunLoop().RunUntilIdle();
 
   permissions::MockPermissionRequest request2(
-      u"request2", permissions::RequestType::kGeolocation,
+      u"request2", permissions::RequestType::kMicStream,
       permissions::PermissionRequestGestureType::UNKNOWN);
   GetPermissionRequestManager()->AddRequest(source_frame, &request2);
   base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index a4809b6..c38cc96 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3992,6 +3992,8 @@
       "views/location_bar/omnibox_chip_button.h",
       "views/location_bar/permission_chip.cc",
       "views/location_bar/permission_chip.h",
+      "views/location_bar/permission_quiet_chip.cc",
+      "views/location_bar/permission_quiet_chip.h",
       "views/location_bar/permission_request_chip.cc",
       "views/location_bar/permission_request_chip.h",
       "views/location_bar/selected_keyword_view.cc",
diff --git a/chrome/browser/ui/content_settings/content_setting_image_model.cc b/chrome/browser/ui/content_settings/content_setting_image_model.cc
index 82ce975..2fa4777 100644
--- a/chrome/browser/ui/content_settings/content_setting_image_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_image_model.cc
@@ -22,9 +22,11 @@
 #include "chrome/browser/permissions/quiet_notification_permission_ui_state.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/blocked_content/framebust_block_tab_helper.h"
+#include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/content_settings/content_setting_image_model_states.h"
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/ui_features.h"
+#include "chrome/browser/ui/web_applications/app_browser_controller.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/chromium_strings.h"
@@ -35,6 +37,7 @@
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/content_settings/core/common/features.h"
 #include "components/no_state_prefetch/browser/no_state_prefetch_manager.h"
+#include "components/permissions/features.h"
 #include "components/permissions/permission_request_manager.h"
 #include "components/prefs/pref_service.h"
 #include "components/strings/grit/components_strings.h"
@@ -977,8 +980,21 @@
   auto* profile =
       Profile::FromBrowserContext(web_contents->GetBrowserContext());
 
-  if (!manager || !manager->ShouldCurrentRequestUseQuietUI())
+  // If `kPermissionQuietUIChip` is enabled, we shouldn't show the icon unless
+  // we're a PWA.
+  // TODO(crbug.com/1221189): Allow PermissionRequestManager to identify the
+  // correct UI style of a permission prompt.
+  const bool quiet_icon_allowed =
+      web_app::AppBrowserController::IsWebApp(
+          chrome::FindBrowserWithWebContents(web_contents)) ||
+      !base::FeatureList::IsEnabled(
+          permissions::features::kPermissionQuietChip);
+
+  if (!quiet_icon_allowed || !manager ||
+      !manager->ShouldCurrentRequestUseQuietUI()) {
     return false;
+  }
+
   // |manager| may be null in tests.
   // Show promo the first time a quiet prompt is shown to the user.
   set_should_show_promo(
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index c02d3168..ca31e38 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -56,6 +56,8 @@
 #include "chrome/browser/ui/views/location_bar/keyword_hint_view.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_layout.h"
 #include "chrome/browser/ui/views/location_bar/location_icon_view.h"
+#include "chrome/browser/ui/views/location_bar/permission_quiet_chip.h"
+#include "chrome/browser/ui/views/location_bar/permission_request_chip.h"
 #include "chrome/browser/ui/views/location_bar/selected_keyword_view.h"
 #include "chrome/browser/ui/views/location_bar/star_view.h"
 #include "chrome/browser/ui/views/page_action/page_action_icon_container.h"
@@ -819,12 +821,16 @@
 
 PermissionChip* LocationBarView::DisplayChip(
     permissions::PermissionPrompt::Delegate* delegate) {
-  DCHECK(!chip_);
   DCHECK(delegate);
-  // `chip_` must come first so it's in the correct place in the focus order.
-  chip_ = AddChildViewAt(
-      std::make_unique<PermissionRequestChip>(browser(), delegate), 0);
-  return chip_;
+  return AddChip(std::make_unique<PermissionRequestChip>(browser(), delegate));
+}
+
+PermissionChip* LocationBarView::DisplayQuietChip(
+    permissions::PermissionPrompt::Delegate* delegate,
+    bool should_expand) {
+  DCHECK(delegate);
+  return AddChip(std::make_unique<PermissionQuietChip>(browser(), delegate,
+                                                       should_expand));
 }
 
 void LocationBarView::FinalizeChip() {
@@ -914,6 +920,13 @@
       0, LocationBarView::GetAvailableTextHeight() - (bubble_padding * 2));
 }
 
+PermissionChip* LocationBarView::AddChip(std::unique_ptr<PermissionChip> chip) {
+  DCHECK(!chip_);
+  // `chip_` must come first so it's in the correct place in the focus order.
+  chip_ = AddChildViewAt(std::move(chip), 0);
+  return chip_;
+}
+
 int LocationBarView::GetMinimumLeadingWidth() const {
   // If the keyword bubble is showing, the view can collapse completely.
   if (ShouldShowKeywordBubble())
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h
index c2cd957..a62759d 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -25,7 +25,7 @@
 #include "chrome/browser/ui/views/extensions/extension_popup.h"
 #include "chrome/browser/ui/views/location_bar/content_setting_image_view.h"
 #include "chrome/browser/ui/views/location_bar/location_icon_view.h"
-#include "chrome/browser/ui/views/location_bar/permission_request_chip.h"
+#include "chrome/browser/ui/views/location_bar/permission_chip.h"
 #include "chrome/browser/ui/views/omnibox/omnibox_view_views.h"
 #include "chrome/browser/ui/views/page_action/page_action_icon_view.h"
 #include "components/security_state/core/security_state.h"
@@ -183,6 +183,11 @@
   PermissionChip* DisplayChip(
       permissions::PermissionPrompt::Delegate* delegate);
 
+  // Creates and displays an instance of PermissionQuietChip.
+  PermissionChip* DisplayQuietChip(
+      permissions::PermissionPrompt::Delegate* delegate,
+      bool should_expand);
+
   // Removes previously displayed PermissionChip.
   void FinalizeChip();
 
@@ -266,6 +271,9 @@
       geolocation_permission_observation_{this};
 #endif
 
+  // Adds `chip` as the first child view.
+  PermissionChip* AddChip(std::unique_ptr<PermissionChip> chip);
+
   // Returns the amount of space required to the left of the omnibox text.
   int GetMinimumLeadingWidth() const;
 
diff --git a/chrome/browser/ui/views/location_bar/omnibox_chip_button.cc b/chrome/browser/ui/views/location_bar/omnibox_chip_button.cc
index 2ed437d..63747e4 100644
--- a/chrome/browser/ui/views/location_bar/omnibox_chip_button.cc
+++ b/chrome/browser/ui/views/location_bar/omnibox_chip_button.cc
@@ -4,12 +4,10 @@
 
 #include "chrome/browser/ui/views/location_bar/omnibox_chip_button.h"
 
-#include "base/location.h"
-#include "base/time/time.h"
+#include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/layout_constants.h"
-#include "chrome/browser/ui/views/chrome_layout_provider.h"
-#include "components/vector_icons/vector_icons.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/base/theme_provider.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/native_theme/native_theme.h"
 #include "ui/views/controls/highlight_path_generator.h"
@@ -116,14 +114,16 @@
 }
 
 SkColor OmniboxChipButton::GetMainColor() {
-  ui::NativeTheme* native_theme = GetNativeTheme();
   switch (theme_) {
     case Theme::kBlue:
       // TODO(crbug.com/1003612): ui::NativeTheme::kColorId_ProminentButtonColor
       // does not always represent the blue color we need, but it is OK to use
       // for now.
-      return native_theme->GetSystemColor(
+      return GetNativeTheme()->GetSystemColor(
           ui::NativeTheme::kColorId_ProminentButtonColor);
+    case Theme::kGray:
+      return GetThemeProvider()->GetColor(
+          ThemeProperties::COLOR_OMNIBOX_TEXT_DIMMED);
   }
 }
 
diff --git a/chrome/browser/ui/views/location_bar/omnibox_chip_button.h b/chrome/browser/ui/views/location_bar/omnibox_chip_button.h
index 1b37b8e8..84316fe 100644
--- a/chrome/browser/ui/views/location_bar/omnibox_chip_button.h
+++ b/chrome/browser/ui/views/location_bar/omnibox_chip_button.h
@@ -26,7 +26,7 @@
   // of Chip.
   enum class Theme {
     kBlue,
-    // TODO(crbug.com/1177760): Other themes will follow.
+    kGray,
   };
 
   void AnimateCollapse();
@@ -49,6 +49,8 @@
   void SetTheme(Theme theme);
   void SetForceExpandedForTesting(bool force_expanded_for_testing);
 
+  Theme get_theme_for_testing() { return theme_; }
+
  private:
   int GetIconSize() const;
 
diff --git a/chrome/browser/ui/views/location_bar/permission_chip.cc b/chrome/browser/ui/views/location_bar/permission_chip.cc
index eb9a266..1bc10c0 100644
--- a/chrome/browser/ui/views/location_bar/permission_chip.cc
+++ b/chrome/browser/ui/views/location_bar/permission_chip.cc
@@ -55,28 +55,25 @@
 
 PermissionChip::PermissionChip(
     permissions::PermissionPrompt::Delegate* delegate,
-    const gfx::VectorIcon& icon,
-    std::u16string message,
-    bool should_start_open)
-    : delegate_(delegate), should_start_open_(should_start_open) {
-  DCHECK(delegate);
+    DisplayParams initializer)
+    : delegate_(delegate),
+      should_start_open_(initializer.should_start_open),
+      should_expand_(initializer.should_expand) {
+  DCHECK(delegate_);
   SetUseDefaultFillLayout(true);
 
   chip_button_ = AddChildView(std::make_unique<OmniboxChipButton>(
       base::BindRepeating(&PermissionChip::ChipButtonPressed,
                           base::Unretained(this)),
-      icon, message, true));
-
+      initializer.icon, initializer.message, initializer.is_prominent));
+  chip_button_->SetTheme(initializer.theme);
   chip_button_->SetButtonController(std::make_unique<BubbleButtonController>(
       chip_button_, this,
       std::make_unique<views::Button::DefaultButtonControllerDelegate>(
           chip_button_)));
-
   chip_button_->SetExpandAnimationEndedCallback(base::BindRepeating(
       &PermissionChip::ExpandAnimationEnded, base::Unretained(this)));
 
-  chip_button_->SetTheme(OmniboxChipButton::Theme::kBlue);
-
   Show(should_start_open_);
 }
 
@@ -125,7 +122,8 @@
 void PermissionChip::Show(bool always_open_bubble) {
   // TODO(olesiamarukhno): Add tests for animation logic.
   chip_button_->ResetAnimation();
-  if (!delegate_->WasCurrentRequestAlreadyDisplayed() || always_open_bubble) {
+  if (should_expand_ &&
+      (!delegate_->WasCurrentRequestAlreadyDisplayed() || always_open_bubble)) {
     chip_button_->AnimateExpand();
   } else {
     StartDismissTimer();
@@ -170,11 +168,18 @@
 }
 
 void PermissionChip::StartDismissTimer() {
-  if (base::FeatureList::IsEnabled(
-          permissions::features::kPermissionChipAutoDismiss)) {
-    auto delay = base::TimeDelta::FromMilliseconds(
-        permissions::features::kPermissionChipAutoDismissDelay.Get());
-    dismiss_timer_.Start(FROM_HERE, delay, this, &PermissionChip::Dismiss);
+  if (should_expand_) {
+    if (base::FeatureList::IsEnabled(
+            permissions::features::kPermissionChipAutoDismiss)) {
+      auto delay = base::TimeDelta::FromMilliseconds(
+          permissions::features::kPermissionChipAutoDismissDelay.Get());
+      dismiss_timer_.Start(FROM_HERE, delay, this, &PermissionChip::Dismiss);
+    }
+  } else {
+    // Abusive origins do not support expand animation, hence the dismiss timer
+    // should be longer.
+    dismiss_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(18), this,
+                         &PermissionChip::Dismiss);
   }
 }
 
diff --git a/chrome/browser/ui/views/location_bar/permission_chip.h b/chrome/browser/ui/views/location_bar/permission_chip.h
index 096880a0..e9b11213 100644
--- a/chrome/browser/ui/views/location_bar/permission_chip.h
+++ b/chrome/browser/ui/views/location_bar/permission_chip.h
@@ -28,12 +28,21 @@
 class PermissionChip : public views::AccessiblePaneView,
                        public views::WidgetObserver,
                        public BubbleOwnerDelegate {
+ protected:
+  // Holds all parameters needed for a chip initialization.
+  struct DisplayParams {
+    const gfx::VectorIcon& icon;
+    std::u16string message;
+    bool should_start_open;
+    bool is_prominent;
+    OmniboxChipButton::Theme theme;
+    bool should_expand;
+  };
+
  public:
   METADATA_HEADER(PermissionChip);
-  PermissionChip(permissions::PermissionPrompt::Delegate* delegate,
-                 const gfx::VectorIcon& icon,
-                 std::u16string message,
-                 bool should_start_open);
+  explicit PermissionChip(permissions::PermissionPrompt::Delegate* delegate,
+                          DisplayParams initializer);
   PermissionChip(const PermissionChip& chip) = delete;
   PermissionChip& operator=(const PermissionChip& chip) = delete;
   ~PermissionChip() override;
@@ -61,6 +70,8 @@
   GetPermissionPromptBubbleForTest() = 0;
 
   bool should_start_open_for_testing() { return should_start_open_; }
+  bool should_expand_for_testing() { return should_expand_; }
+  OmniboxChipButton* get_chip_button_for_testing() { return chip_button_; }
 
  protected:
   permissions::PermissionPrompt::Delegate* delegate() const {
@@ -76,6 +87,7 @@
   void Collapse(bool allow_restart);
   void StartDismissTimer();
   void Dismiss();
+
   void AnimateCollapse();
   void AnimateExpand();
 
@@ -92,6 +104,7 @@
   OmniboxChipButton* chip_button_ = nullptr;
 
   bool should_start_open_ = false;
+  bool should_expand_ = true;
 };
 
 #endif  // CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_PERMISSION_CHIP_H_
diff --git a/chrome/browser/ui/views/location_bar/permission_quiet_chip.cc b/chrome/browser/ui/views/location_bar/permission_quiet_chip.cc
new file mode 100644
index 0000000..a193dfa
--- /dev/null
+++ b/chrome/browser/ui/views/location_bar/permission_quiet_chip.cc
@@ -0,0 +1,133 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/location_bar/permission_quiet_chip.h"
+
+#include "base/location.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "chrome/browser/ui/views/permission_bubble/permission_prompt_bubble_view.h"
+#include "chrome/browser/ui/views/permission_bubble/permission_prompt_style.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/permissions/permission_request.h"
+#include "components/permissions/request_type.h"
+#include "components/strings/grit/components_strings.h"
+#include "components/vector_icons/vector_icons.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/events/event.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/views/accessibility/view_accessibility.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
+#include "ui/views/controls/button/button_controller.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/widget/widget.h"
+
+#include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
+#include "chrome/browser/ui/views/content_setting_bubble_contents.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
+
+namespace {
+
+const gfx::VectorIcon& GetPermissionIconId(
+    permissions::PermissionPrompt::Delegate* delegate) {
+  DCHECK(delegate);
+
+  if (delegate->Requests()[0]->GetRequestType() ==
+      permissions::RequestType::kNotifications) {
+    return vector_icons::kNotificationsOffIcon;
+  }
+
+  NOTREACHED();
+  return gfx::kNoneIcon;
+}
+
+std::u16string GetPermissionMessage(
+    permissions::PermissionPrompt::Delegate* delegate) {
+  DCHECK(delegate);
+
+  if (delegate->Requests()[0]->GetRequestType() ==
+      permissions::RequestType::kNotifications) {
+    return l10n_util::GetStringUTF16(IDS_NOTIFICATIONS_OFF_EXPLANATORY_TEXT);
+  }
+
+  NOTREACHED();
+  return std::u16string();
+}
+
+}  // namespace
+
+PermissionQuietChip::PermissionQuietChip(
+    Browser* browser,
+    permissions::PermissionPrompt::Delegate* delegate,
+    bool should_expand)
+    : PermissionChip(
+          delegate,
+          {GetPermissionIconId(delegate), GetPermissionMessage(delegate), false,
+           /*is_prominent=*/false, OmniboxChipButton::Theme::kGray,
+           /*should_expand=*/should_expand}),
+      browser_(browser) {
+  DCHECK_EQ(1u, delegate->Requests().size());
+  chip_shown_time_ = base::TimeTicks::Now();
+}
+
+PermissionQuietChip::~PermissionQuietChip() {
+  if (quiet_request_bubble_) {
+    views::Widget* widget = quiet_request_bubble_->GetWidget();
+    widget->RemoveObserver(this);
+    widget->Close();
+  }
+}
+
+void PermissionQuietChip::OpenBubble() {
+  // The prompt bubble is either not opened yet or already closed on
+  // deactivation.
+  DCHECK(!quiet_request_bubble_);
+
+  LocationBarView* lbv = GetLocationBarView();
+  content::WebContents* web_contents = lbv->GetContentSettingWebContents();
+
+  if (web_contents) {
+    quiet_request_bubble_ = new ContentSettingBubbleContents(
+        std::make_unique<ContentSettingNotificationsBubbleModel>(
+            lbv->GetContentSettingBubbleModelDelegate(), web_contents),
+        web_contents, lbv, views::BubbleBorder::TOP_LEFT);
+    quiet_request_bubble_->SetHighlightedButton(button());
+    views::Widget* bubble_widget =
+        views::BubbleDialogDelegateView::CreateBubble(quiet_request_bubble_);
+    bubble_widget->AddObserver(this);
+    bubble_widget->Show();
+  }
+
+  RecordChipButtonPressed();
+}
+
+views::BubbleDialogDelegateView*
+PermissionQuietChip::GetPermissionPromptBubbleForTest() {
+  return quiet_request_bubble_;
+}
+
+void PermissionQuietChip::OnWidgetClosing(views::Widget* widget) {
+  DCHECK_EQ(widget, quiet_request_bubble_->GetWidget());
+  PermissionChip::OnWidgetClosing(widget);
+  quiet_request_bubble_ = nullptr;
+}
+
+bool PermissionQuietChip::IsBubbleShowing() const {
+  return quiet_request_bubble_;
+}
+
+void PermissionQuietChip::RecordChipButtonPressed() {
+  base::UmaHistogramMediumTimes("Permissions.QuietChip.TimeToInteraction",
+                                base::TimeTicks::Now() - chip_shown_time_);
+}
+
+LocationBarView* PermissionQuietChip::GetLocationBarView() {
+  return BrowserView::GetBrowserViewForBrowser(browser_)->GetLocationBarView();
+}
+
+BEGIN_METADATA(PermissionQuietChip, views::View)
+END_METADATA
diff --git a/chrome/browser/ui/views/location_bar/permission_quiet_chip.h b/chrome/browser/ui/views/location_bar/permission_quiet_chip.h
new file mode 100644
index 0000000..e49bef8
--- /dev/null
+++ b/chrome/browser/ui/views/location_bar/permission_quiet_chip.h
@@ -0,0 +1,49 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_PERMISSION_QUIET_CHIP_H_
+#define CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_PERMISSION_QUIET_CHIP_H_
+
+#include "chrome/browser/ui/views/location_bar/permission_chip.h"
+
+class Browser;
+class LocationBarView;
+
+// A less prominent version of `PermissionRequestChip`. It is used to display a
+// permission request from origins with an abusive reputation, low acceptance
+// rate, or if a user manually enabled "quieter messaging" in
+// chrome://settings/content/notifications.
+class PermissionQuietChip : public PermissionChip {
+ public:
+  METADATA_HEADER(PermissionQuietChip);
+  PermissionQuietChip(Browser* browser,
+                      permissions::PermissionPrompt::Delegate* delegate,
+                      bool should_expand);
+  PermissionQuietChip(const PermissionQuietChip& chip) = delete;
+  PermissionQuietChip& operator=(const PermissionQuietChip& chip) = delete;
+  ~PermissionQuietChip() override;
+
+  // PermissionChip:
+  void OpenBubble() override;
+  views::BubbleDialogDelegateView* GetPermissionPromptBubbleForTest() override;
+
+  // views::WidgetObserver:
+  void OnWidgetClosing(views::Widget* widget) override;
+
+  // BubbleOwnerDelegate:
+  bool IsBubbleShowing() const override;
+
+ private:
+  void RecordChipButtonPressed();
+  LocationBarView* GetLocationBarView();
+
+  Browser* browser_ = nullptr;
+
+  // The time when the chip was displayed.
+  base::TimeTicks chip_shown_time_;
+
+  views::BubbleDialogDelegateView* quiet_request_bubble_ = nullptr;
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_PERMISSION_QUIET_CHIP_H_
diff --git a/chrome/browser/ui/views/location_bar/permission_request_chip.cc b/chrome/browser/ui/views/location_bar/permission_request_chip.cc
index 40c7e09..58a25bf7 100644
--- a/chrome/browser/ui/views/location_bar/permission_request_chip.cc
+++ b/chrome/browser/ui/views/location_bar/permission_request_chip.cc
@@ -25,6 +25,7 @@
 #include "ui/views/widget/widget.h"
 
 namespace {
+
 bool IsCameraPermission(permissions::RequestType type) {
   return type == permissions::RequestType::kCameraStream;
 }
@@ -112,10 +113,11 @@
 PermissionRequestChip::PermissionRequestChip(
     Browser* browser,
     permissions::PermissionPrompt::Delegate* delegate)
-    : PermissionChip(delegate,
-                     GetPermissionIconId(delegate),
-                     GetPermissionMessage(delegate),
-                     ShouldBubbleStartOpen(delegate)),
+    : PermissionChip(
+          delegate,
+          {GetPermissionIconId(delegate), GetPermissionMessage(delegate),
+           ShouldBubbleStartOpen(delegate), /*is_prominent=*/true,
+           OmniboxChipButton::Theme::kBlue, /*should_expand=*/true}),
       browser_(browser) {
   chip_shown_time_ = base::TimeTicks::Now();
   VerifyCameraAndMicRequest(delegate);
@@ -159,7 +161,7 @@
 }
 
 void PermissionRequestChip::RecordChipButtonPressed() {
-    base::UmaHistogramLongTimes("Permissions.Chip.TimeToInteraction",
+  base::UmaHistogramMediumTimes("Permissions.Chip.TimeToInteraction",
                                 base::TimeTicks::Now() - chip_shown_time_);
 }
 
diff --git a/chrome/browser/ui/views/permission_bubble/permission_prompt_bubble_view_browsertest.cc b/chrome/browser/ui/views/permission_bubble/permission_prompt_bubble_view_browsertest.cc
index 4c85bad..0db4616e 100644
--- a/chrome/browser/ui/views/permission_bubble/permission_prompt_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/permission_bubble/permission_prompt_bubble_view_browsertest.cc
@@ -109,7 +109,7 @@
     }
     base::RunLoop().RunUntilIdle();
 
-    PermissionChip* chip = GetPermissionRequestChipView();
+    PermissionChip* chip = GetChip();
     if (chip) {
       views::test::ButtonTestApi(chip->button())
           .NotifyClick(ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(),
@@ -120,7 +120,7 @@
   }
 
   bool VerifyUi() override {
-    const bool should_close_on_deactivate = GetPermissionRequestChipView();
+    const bool should_close_on_deactivate = GetChip();
     views::Widget* prompt_widget = test_api_->GetPromptWindow();
     views::BubbleDialogDelegate* bubble_dialog =
         prompt_widget->widget_delegate()->AsBubbleDialogDelegate();
@@ -135,12 +135,24 @@
     return browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame();
   }
 
-  PermissionChip* GetPermissionRequestChipView() {
+  PermissionChip* GetChip() {
     BrowserView* browser_view =
         BrowserView::GetBrowserViewForBrowser(browser());
     return browser_view->toolbar()->location_bar()->chip();
   }
 
+  ContentSettingImageView& GetContentSettingImageView(
+      ContentSettingImageModel::ImageType image_type) {
+    LocationBarView* location_bar_view =
+        BrowserView::GetBrowserViewForBrowser(browser())->GetLocationBarView();
+    return **std::find_if(
+        location_bar_view->GetContentSettingViewsForTest().begin(),
+        location_bar_view->GetContentSettingViewsForTest().end(),
+        [image_type](ContentSettingImageView* view) {
+          return view->GetTypeForTesting() == image_type;
+        });
+  }
+
   permissions::PermissionRequest* MakeRegisterProtocolHandlerRequest() {
     std::string protocol = "mailto";
     ProtocolHandler handler =
@@ -217,10 +229,52 @@
     }
   }
 
-  void VerifyDisposition(permissions::PermissionPromptDisposition disposition) {
-    EXPECT_EQ(
-        test_api_->manager()->current_request_prompt_disposition_for_testing(),
-        disposition);
+  void ExpectQuietAbusiveChip() {
+    // PermissionChip lifetime is bound to a permission prompt view.
+    ASSERT_TRUE(test_api_->manager()->view_for_testing());
+    // The quiet chip will be shown even if the chip experiment is disabled.
+    PermissionChip* chip = GetChip();
+    ASSERT_TRUE(chip);
+
+    EXPECT_FALSE(chip->should_expand_for_testing());
+    EXPECT_FALSE(chip->get_chip_button_for_testing()->GetProminent());
+    EXPECT_FALSE(chip->get_chip_button_for_testing()->is_animating());
+    EXPECT_EQ(OmniboxChipButton::Theme::kGray,
+              chip->get_chip_button_for_testing()->get_theme_for_testing());
+  }
+
+  void ExpectQuietChip() {
+    // PermissionChip lifetime is bound to a permission prompt view.
+    ASSERT_TRUE(test_api_->manager()->view_for_testing());
+
+    // The quiet chip will be shown even if the chip experiment is disabled.
+    PermissionChip* chip = GetChip();
+    ASSERT_TRUE(chip);
+
+    EXPECT_TRUE(chip->should_expand_for_testing());
+    EXPECT_FALSE(chip->get_chip_button_for_testing()->GetProminent());
+    EXPECT_TRUE(chip->get_chip_button_for_testing()->is_animating());
+    EXPECT_EQ(OmniboxChipButton::Theme::kGray,
+              chip->get_chip_button_for_testing()->get_theme_for_testing());
+  }
+
+  void ExpectNormalChip() {
+    // PermissionChip lifetime is bound to a permission prompt view.
+    ASSERT_TRUE(test_api_->manager()->view_for_testing());
+    if (GetParam()) {
+      PermissionChip* chip = GetChip();
+      ASSERT_TRUE(chip);
+
+      EXPECT_TRUE(chip->should_expand_for_testing());
+      EXPECT_TRUE(chip->get_chip_button_for_testing()->GetProminent());
+      EXPECT_TRUE(chip->get_chip_button_for_testing()->is_animating());
+      EXPECT_EQ(OmniboxChipButton::Theme::kBlue,
+                chip->get_chip_button_for_testing()->get_theme_for_testing());
+
+    } else {
+      // Chip is disabled.
+      EXPECT_FALSE(GetChip());
+    }
   }
 
   base::test::ScopedFeatureList feature_list_;
@@ -237,7 +291,7 @@
 // AnnounceText doesn't go through the path that uses Event::kAlert. Therefore
 // we can't test it.
 #if !defined(OS_MAC)
-  PermissionChip* chip = GetPermissionRequestChipView();
+  PermissionChip* chip = GetChip();
   // If chip UI is used, two notifications will be announced: one that
   // permission was requested and second when bubble is opened.
   if (chip && !chip->should_start_open_for_testing()) {
@@ -414,15 +468,8 @@
     base::RunLoop().RunUntilIdle();
   }
 
-  LocationBarView* location_bar_view =
-      BrowserView::GetBrowserViewForBrowser(browser())->GetLocationBarView();
-  ContentSettingImageView& quiet_ui_icon = **std::find_if(
-      location_bar_view->GetContentSettingViewsForTest().begin(),
-      location_bar_view->GetContentSettingViewsForTest().end(),
-      [](ContentSettingImageView* view) {
-        return view->GetTypeForTesting() ==
-               ContentSettingImageModel::ImageType::NOTIFICATIONS_QUIET_PROMPT;
-      });
+  ContentSettingImageView& quiet_ui_icon = GetContentSettingImageView(
+      ContentSettingImageModel::ImageType::NOTIFICATIONS_QUIET_PROMPT);
 
   EXPECT_FALSE(quiet_ui_icon.GetVisible());
   // `ContentSettingImageView::AnimationEnded()` was not triggered and IPH is
@@ -517,7 +564,8 @@
                        DispositionNoAbusiveTest) {
   ShowUi("geolocation");
 
-  VerifyDisposition(
+  EXPECT_EQ(
+      test_api_->manager()->current_request_prompt_disposition_for_testing(),
       GetParam()
           ? permissions::PermissionPromptDisposition::LOCATION_BAR_LEFT_CHIP
           : permissions::PermissionPromptDisposition::ANCHORED_BUBBLE);
@@ -527,7 +575,8 @@
 
   ShowUi("notifications");
 
-  VerifyDisposition(
+  EXPECT_EQ(
+      test_api_->manager()->current_request_prompt_disposition_for_testing(),
       GetParam()
           ? permissions::PermissionPromptDisposition::LOCATION_BAR_LEFT_CHIP
           : permissions::PermissionPromptDisposition::ANCHORED_BUBBLE);
@@ -571,7 +620,8 @@
 
   ShowUi("geolocation");
 
-  VerifyDisposition(
+  EXPECT_EQ(
+      test_api_->manager()->current_request_prompt_disposition_for_testing(),
       GetParam()
           ? permissions::PermissionPromptDisposition::LOCATION_BAR_LEFT_CHIP
           : permissions::PermissionPromptDisposition::ANCHORED_BUBBLE);
@@ -581,7 +631,8 @@
 
   ShowUi("notifications");
 
-  VerifyDisposition(
+  EXPECT_EQ(
+      test_api_->manager()->current_request_prompt_disposition_for_testing(),
       permissions::PermissionPromptDisposition::LOCATION_BAR_RIGHT_STATIC_ICON);
 }
 
@@ -591,7 +642,8 @@
 
   ShowUi("geolocation");
 
-  VerifyDisposition(
+  EXPECT_EQ(
+      test_api_->manager()->current_request_prompt_disposition_for_testing(),
       GetParam()
           ? permissions::PermissionPromptDisposition::LOCATION_BAR_LEFT_CHIP
           : permissions::PermissionPromptDisposition::ANCHORED_BUBBLE);
@@ -601,7 +653,8 @@
 
   ShowUi("notifications");
 
-  VerifyDisposition(
+  EXPECT_EQ(
+      test_api_->manager()->current_request_prompt_disposition_for_testing(),
       permissions::PermissionPromptDisposition::LOCATION_BAR_RIGHT_STATIC_ICON);
 }
 
@@ -613,7 +666,8 @@
 
   ShowUi("geolocation");
 
-  VerifyDisposition(
+  EXPECT_EQ(
+      test_api_->manager()->current_request_prompt_disposition_for_testing(),
       GetParam()
           ? permissions::PermissionPromptDisposition::LOCATION_BAR_LEFT_CHIP
           : permissions::PermissionPromptDisposition::ANCHORED_BUBBLE);
@@ -623,8 +677,10 @@
 
   ShowUi("notifications");
 
-  VerifyDisposition(permissions::PermissionPromptDisposition::
-                        LOCATION_BAR_RIGHT_ANIMATED_ICON);
+  EXPECT_EQ(
+      test_api_->manager()->current_request_prompt_disposition_for_testing(),
+      permissions::PermissionPromptDisposition::
+          LOCATION_BAR_RIGHT_ANIMATED_ICON);
 }
 
 // For `QuietUiReason::kPredictedVeryUnlikelyGrant` reputation we show an
@@ -636,7 +692,8 @@
 
   ShowUi("geolocation");
 
-  VerifyDisposition(
+  EXPECT_EQ(
+      test_api_->manager()->current_request_prompt_disposition_for_testing(),
       GetParam()
           ? permissions::PermissionPromptDisposition::LOCATION_BAR_LEFT_CHIP
           : permissions::PermissionPromptDisposition::ANCHORED_BUBBLE);
@@ -646,8 +703,10 @@
 
   ShowUi("notifications");
 
-  VerifyDisposition(permissions::PermissionPromptDisposition::
-                        LOCATION_BAR_RIGHT_ANIMATED_ICON);
+  EXPECT_EQ(
+      test_api_->manager()->current_request_prompt_disposition_for_testing(),
+      permissions::PermissionPromptDisposition::
+          LOCATION_BAR_RIGHT_ANIMATED_ICON);
 }
 
 // For `QuietUiReason::kTriggeredDueToAbusiveRequests` reputation we show a
@@ -659,7 +718,8 @@
 
   ShowUi("geolocation");
 
-  VerifyDisposition(
+  EXPECT_EQ(
+      test_api_->manager()->current_request_prompt_disposition_for_testing(),
       GetParam()
           ? permissions::PermissionPromptDisposition::LOCATION_BAR_LEFT_CHIP
           : permissions::PermissionPromptDisposition::ANCHORED_BUBBLE);
@@ -669,17 +729,161 @@
 
   ShowUi("notifications");
 
-  VerifyDisposition(
+  EXPECT_EQ(
+      test_api_->manager()->current_request_prompt_disposition_for_testing(),
       permissions::PermissionPromptDisposition::LOCATION_BAR_RIGHT_STATIC_ICON);
 }
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         PermissionPromptBubbleViewQuietUiBrowserTest,
-                         ::testing::Values(false, true));
+class QuietChipPermissionPromptBubbleViewBrowserTest
+    : public PermissionPromptBubbleViewQuietUiBrowserTest {
+ public:
+  QuietChipPermissionPromptBubbleViewBrowserTest() {
+    scoped_feature_list_.InitAndEnableFeature(
+        permissions::features::kPermissionQuietChip);
+  }
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         PermissionPromptBubbleViewBrowserTest,
-                         ::testing::Values(false, true));
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_P(QuietChipPermissionPromptBubbleViewBrowserTest,
+                       LoudChipOrAnchoredBubbleIsShownForNonAbusiveRequests) {
+  SetCannedUiDecision(absl::nullopt, absl::nullopt);
+
+  ShowUi("geolocation");
+
+  EXPECT_EQ(
+      test_api_->manager()->current_request_prompt_disposition_for_testing(),
+      GetParam()
+          ? permissions::PermissionPromptDisposition::LOCATION_BAR_LEFT_CHIP
+          : permissions::PermissionPromptDisposition::ANCHORED_BUBBLE);
+
+  test_api_->manager()->Accept();
+  base::RunLoop().RunUntilIdle();
+
+  ShowUi("notifications");
+
+  EXPECT_EQ(
+      test_api_->manager()->current_request_prompt_disposition_for_testing(),
+      GetParam()
+          ? permissions::PermissionPromptDisposition::LOCATION_BAR_LEFT_CHIP
+          : permissions::PermissionPromptDisposition::ANCHORED_BUBBLE);
+}
+
+IN_PROC_BROWSER_TEST_P(QuietChipPermissionPromptBubbleViewBrowserTest,
+                       QuietChipIsShownForAbusiveRequests) {
+  for (QuietUiReason reason : {QuietUiReason::kTriggeredByCrowdDeny,
+                               QuietUiReason::kTriggeredDueToAbusiveRequests,
+                               QuietUiReason::kTriggeredDueToAbusiveContent}) {
+    SetCannedUiDecision(reason, absl::nullopt);
+
+    ShowUi("geolocation");
+
+    EXPECT_EQ(
+        test_api_->manager()->current_request_prompt_disposition_for_testing(),
+        GetParam()
+            ? permissions::PermissionPromptDisposition::LOCATION_BAR_LEFT_CHIP
+            : permissions::PermissionPromptDisposition::ANCHORED_BUBBLE);
+
+    test_api_->manager()->Accept();
+    base::RunLoop().RunUntilIdle();
+
+    ShowUi("notifications");
+
+    // Quiet Chip is enabled, that means a quiet chip will be shown even if the
+    // Chip experiment is disabled.
+    EXPECT_EQ(
+        test_api_->manager()->current_request_prompt_disposition_for_testing(),
+        permissions::PermissionPromptDisposition::LOCATION_BAR_LEFT_QUIET_CHIP);
+  }
+}
+
+// The quiet UI icon is verified to make sure that the quiet chip is not shown
+// when the quiet icon is shown.
+IN_PROC_BROWSER_TEST_P(QuietChipPermissionPromptBubbleViewBrowserTest,
+                       QuietChipIsNotShownForNonAbusiveRequests) {
+  SetCannedUiDecision(absl::nullopt, absl::nullopt);
+
+  ContentSettingImageView& quiet_ui_icon = GetContentSettingImageView(
+      ContentSettingImageModel::ImageType::NOTIFICATIONS_QUIET_PROMPT);
+  EXPECT_FALSE(quiet_ui_icon.GetVisible());
+  EXPECT_FALSE(GetChip());
+
+  ShowUi("geolocation");
+
+  EXPECT_FALSE(quiet_ui_icon.GetVisible());
+  ExpectNormalChip();
+
+  test_api_->manager()->Accept();
+  base::RunLoop().RunUntilIdle();
+
+  ShowUi("notifications");
+
+  EXPECT_FALSE(quiet_ui_icon.GetVisible());
+  ExpectNormalChip();
+
+  test_api_->manager()->Accept();
+  base::RunLoop().RunUntilIdle();
+}
+
+IN_PROC_BROWSER_TEST_P(QuietChipPermissionPromptBubbleViewBrowserTest,
+                       NotAnimatedQuietChipIsShownForAbusiveRequests) {
+  for (QuietUiReason reason : {QuietUiReason::kTriggeredByCrowdDeny,
+                               QuietUiReason::kTriggeredDueToAbusiveRequests,
+                               QuietUiReason::kTriggeredDueToAbusiveContent}) {
+    SetCannedUiDecision(reason, absl::nullopt);
+
+    ContentSettingImageView& quiet_ui_icon = GetContentSettingImageView(
+        ContentSettingImageModel::ImageType::NOTIFICATIONS_QUIET_PROMPT);
+    EXPECT_FALSE(quiet_ui_icon.GetVisible());
+    EXPECT_FALSE(GetChip());
+
+    ShowUi("geolocation");
+
+    EXPECT_FALSE(quiet_ui_icon.GetVisible());
+    ExpectNormalChip();
+
+    test_api_->manager()->Accept();
+    base::RunLoop().RunUntilIdle();
+
+    ShowUi("notifications");
+
+    EXPECT_FALSE(quiet_ui_icon.GetVisible());
+    ExpectQuietAbusiveChip();
+
+    test_api_->manager()->Accept();
+    base::RunLoop().RunUntilIdle();
+  }
+}
+
+IN_PROC_BROWSER_TEST_P(QuietChipPermissionPromptBubbleViewBrowserTest,
+                       AnimatedQuietChipIsShownForNonAbusiveRequests) {
+  for (QuietUiReason reason : {QuietUiReason::kEnabledInPrefs,
+                               QuietUiReason::kPredictedVeryUnlikelyGrant}) {
+    SetCannedUiDecision(reason, absl::nullopt);
+
+    ContentSettingImageView& quiet_ui_icon = GetContentSettingImageView(
+        ContentSettingImageModel::ImageType::NOTIFICATIONS_QUIET_PROMPT);
+    EXPECT_FALSE(quiet_ui_icon.GetVisible());
+    EXPECT_FALSE(GetChip());
+
+    ShowUi("geolocation");
+
+    EXPECT_FALSE(quiet_ui_icon.GetVisible());
+    ExpectNormalChip();
+
+    test_api_->manager()->Accept();
+    base::RunLoop().RunUntilIdle();
+
+    ShowUi("notifications");
+
+    EXPECT_FALSE(quiet_ui_icon.GetVisible());
+    ExpectQuietChip();
+
+    test_api_->manager()->Accept();
+    base::RunLoop().RunUntilIdle();
+  }
+}
 
 class OneTimePermissionPromptBubbleViewBrowserTest
     : public PermissionPromptBubbleViewBrowserTest {
@@ -699,8 +903,18 @@
   ShowAndVerifyUi();
 }
 
+// False / True values determine if the PermissionChip feature is
+// disabled/enabled.
+INSTANTIATE_TEST_SUITE_P(All,
+                         PermissionPromptBubbleViewBrowserTest,
+                         ::testing::Values(false, true));
+INSTANTIATE_TEST_SUITE_P(All,
+                         PermissionPromptBubbleViewQuietUiBrowserTest,
+                         ::testing::Values(false, true));
+INSTANTIATE_TEST_SUITE_P(All,
+                         QuietChipPermissionPromptBubbleViewBrowserTest,
+                         ::testing::Values(false, true));
 INSTANTIATE_TEST_SUITE_P(All,
                          OneTimePermissionPromptBubbleViewBrowserTest,
                          ::testing::Values(false, true));
-
 INSTANTIATE_TEST_SUITE_P(All, QuietUIPromoBrowserTest, ::testing::Values(true));
diff --git a/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc
index 16adbbb6..957230bc 100644
--- a/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc
+++ b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/permission_bubble/file_handling_permission_prompt.h"
 #include "chrome/browser/ui/views/permission_bubble/permission_prompt_bubble_view.h"
+#include "chrome/browser/ui/web_applications/app_browser_controller.h"
 #include "chrome/browser/web_launch/web_launch_files_helper.h"
 #include "components/permissions/features.h"
 #include "components/permissions/permission_request.h"
@@ -23,6 +24,27 @@
 #include "content/public/browser/web_contents.h"
 #include "ui/views/bubble/bubble_frame_view.h"
 
+namespace {
+
+bool IsFullScreenMode(content::WebContents* web_contents, Browser* browser) {
+  DCHECK(web_contents);
+  DCHECK(browser);
+
+  // PWA uses the title bar as a substitute for LocationBarView.
+  if (web_app::AppBrowserController::IsWebApp(browser))
+    return false;
+
+  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
+  if (!browser_view)
+    return false;
+
+  LocationBarView* location_bar = browser_view->GetLocationBarView();
+
+  return !location_bar || !location_bar->IsDrawn();
+}
+
+}  // namespace
+
 std::unique_ptr<permissions::PermissionPrompt> CreatePermissionPrompt(
     content::WebContents* web_contents,
     permissions::PermissionPrompt::Delegate* delegate) {
@@ -33,6 +55,14 @@
     return nullptr;
   }
 
+  permissions::PermissionRequestManager* manager =
+      permissions::PermissionRequestManager::FromWebContents(web_contents);
+
+  if (manager->ShouldDropCurrentRequestIfCannotShowQuietly() &&
+      IsFullScreenMode(web_contents, browser)) {
+    return nullptr;
+  }
+
   if (base::FeatureList::IsEnabled(features::kFileHandlingPermissionUiV2) &&
       delegate->Requests().size() == 1U &&
       delegate->Requests()[0]->GetRequestType() ==
@@ -51,29 +81,18 @@
       web_contents_(web_contents),
       delegate_(delegate),
       browser_(browser),
-      permission_requested_time_(base::TimeTicks::Now()) {
-  permissions::PermissionRequestManager* manager =
-      permissions::PermissionRequestManager::FromWebContents(web_contents_);
-  if (manager->ShouldCurrentRequestUseQuietUI()) {
-    prompt_style_ = PermissionPromptStyle::kQuiet;
-    // Shows the prompt as an indicator in the right side of the omnibox.
-    content_settings::UpdateLocationBarUiForWebContents(web_contents_);
+      permission_requested_time_(base::TimeTicks::Now()),
+      manager_(permissions::PermissionRequestManager::FromWebContents(
+          web_contents)) {
+  if (web_app::AppBrowserController::IsWebApp(browser_)) {
+    SelectPwaPrompt();
+  } else if (manager_->ShouldCurrentRequestUseQuietUI()) {
+    SelectQuietPrompt();
   } else {
-    LocationBarView* lbv = GetLocationBarView();
-    if (lbv && lbv->IsDrawn() && ShouldCurrentRequestUseChipUI()) {
-      ShowChipUI();
-    } else {
-      ShowBubble();
-    }
+    SelectNormalPrompt();
   }
 }
 
-void PermissionPromptImpl::OnWidgetClosing(views::Widget* widget) {
-  DCHECK_EQ(widget, prompt_bubble_->GetWidget());
-  widget->RemoveObserver(this);
-  prompt_bubble_ = nullptr;
-}
-
 PermissionPromptImpl::~PermissionPromptImpl() {
   switch (prompt_style_) {
     case PermissionPromptStyle::kBubbleOnly:
@@ -82,11 +101,12 @@
         prompt_bubble_->GetWidget()->Close();
       break;
     case PermissionPromptStyle::kChip:
+    case PermissionPromptStyle::kQuietChip:
       DCHECK(!prompt_bubble_);
       DCHECK(chip_);
       FinalizeChip();
       break;
-    case PermissionPromptStyle::kQuiet:
+    case PermissionPromptStyle::kLocationBarRightIcon:
       DCHECK(!prompt_bubble_);
       DCHECK(!chip_);
       content_settings::UpdateLocationBarUiForWebContents(web_contents_);
@@ -116,12 +136,12 @@
       if (!prompt_bubble_)
         return;
 
-      if (ShouldCurrentRequestUseChipUI() && is_location_bar_drawn) {
+      if (ShouldCurrentRequestUseChip() && is_location_bar_drawn) {
         // Change prompt style to chip to avoid dismissing request while
         // switching UI style.
         prompt_bubble_->SetPromptStyle(PermissionPromptStyle::kChip);
         prompt_bubble_->GetWidget()->Close();
-        ShowChipUI();
+        ShowChip();
         chip_->OpenBubble();
       } else {
         // If |browser_| changed, recreate bubble for correct browser.
@@ -147,47 +167,27 @@
         ShowBubble();
       }
       break;
-    case PermissionPromptStyle::kQuiet:
+    case PermissionPromptStyle::kQuietChip:
+      DCHECK(!prompt_bubble_);
+
+      if (!lbv->chip()) {
+        chip_ = lbv->DisplayQuietChip(
+            delegate_,
+            !permissions::PermissionUiSelector::ShouldSuppressAnimation(
+                manager_->ReasonForUsingQuietUi()));
+      }
+      // If there is fresh pending request shown as chip UI and location bar
+      // isn't visible anymore, show bubble UI instead.
+      if (!chip_->is_fully_collapsed() && !is_location_bar_drawn) {
+        FinalizeChip();
+        ShowBubble();
+      }
+      break;
+    case PermissionPromptStyle::kLocationBarRightIcon:
       break;
   }
 }
 
-LocationBarView* PermissionPromptImpl::GetLocationBarView() {
-  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser_);
-  return browser_view ? browser_view->GetLocationBarView() : nullptr;
-}
-
-void PermissionPromptImpl::ShowChipUI() {
-  LocationBarView* lbv = GetLocationBarView();
-  DCHECK(lbv);
-
-  chip_ = lbv->DisplayChip(delegate_);
-  prompt_style_ = PermissionPromptStyle::kChip;
-}
-
-void PermissionPromptImpl::ShowBubble() {
-  prompt_style_ = PermissionPromptStyle::kBubbleOnly;
-  prompt_bubble_ = new PermissionPromptBubbleView(
-      browser_, delegate_, permission_requested_time_, prompt_style_);
-  prompt_bubble_->Show();
-  prompt_bubble_->GetWidget()->AddObserver(this);
-}
-
-bool PermissionPromptImpl::ShouldCurrentRequestUseChipUI() {
-  if (!base::FeatureList::IsEnabled(permissions::features::kPermissionChip))
-    return false;
-
-  std::vector<permissions::PermissionRequest*> requests = delegate_->Requests();
-  return std::all_of(requests.begin(), requests.end(), [](auto* request) {
-    return request->GetChipText().has_value();
-  });
-}
-
-void PermissionPromptImpl::FinalizeChip() {
-  GetLocationBarView()->FinalizeChip();
-  chip_ = nullptr;
-}
-
 permissions::PermissionPrompt::TabSwitchingBehavior
 PermissionPromptImpl::GetTabSwitchingBehavior() {
   return permissions::PermissionPrompt::TabSwitchingBehavior::
@@ -201,11 +201,12 @@
       return permissions::PermissionPromptDisposition::ANCHORED_BUBBLE;
     case PermissionPromptStyle::kChip:
       return permissions::PermissionPromptDisposition::LOCATION_BAR_LEFT_CHIP;
-    case PermissionPromptStyle::kQuiet: {
-      permissions::PermissionRequestManager* manager =
-          permissions::PermissionRequestManager::FromWebContents(web_contents_);
+    case PermissionPromptStyle::kQuietChip:
+      return permissions::PermissionPromptDisposition::
+          LOCATION_BAR_LEFT_QUIET_CHIP;
+    case PermissionPromptStyle::kLocationBarRightIcon: {
       return permissions::PermissionUiSelector::ShouldSuppressAnimation(
-                 manager->ReasonForUsingQuietUi())
+                 manager_->ReasonForUsingQuietUi())
                  ? permissions::PermissionPromptDisposition::
                        LOCATION_BAR_RIGHT_STATIC_ICON
                  : permissions::PermissionPromptDisposition::
@@ -213,3 +214,109 @@
     }
   }
 }
+
+void PermissionPromptImpl::OnWidgetClosing(views::Widget* widget) {
+  DCHECK_EQ(widget, prompt_bubble_->GetWidget());
+  widget->RemoveObserver(this);
+  prompt_bubble_ = nullptr;
+}
+
+bool PermissionPromptImpl::IsLocationBarDisplayed() {
+  LocationBarView* lbv = GetLocationBarView();
+  return lbv && lbv->IsDrawn();
+}
+
+void PermissionPromptImpl::SelectPwaPrompt() {
+  if (manager_->ShouldCurrentRequestUseQuietUI()) {
+    ShowQuietIcon();
+  } else {
+    ShowBubble();
+  }
+}
+
+void PermissionPromptImpl::SelectNormalPrompt() {
+  DCHECK(!manager_->ShouldCurrentRequestUseQuietUI());
+  if (ShouldCurrentRequestUseChip()) {
+    ShowChip();
+  } else {
+    ShowBubble();
+  }
+}
+
+void PermissionPromptImpl::SelectQuietPrompt() {
+  if (ShouldCurrentRequestUseQuietChip()) {
+    if (IsLocationBarDisplayed()) {
+      ShowChip();
+    } else {
+      // If LocationBar is not displayed (Fullscreen mode), display a default
+      // bubble only for non-abusive origins.
+      DCHECK(!manager_->ShouldDropCurrentRequestIfCannotShowQuietly());
+      ShowBubble();
+    }
+  } else {
+    ShowQuietIcon();
+  }
+}
+
+LocationBarView* PermissionPromptImpl::GetLocationBarView() {
+  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser_);
+  return browser_view ? browser_view->GetLocationBarView() : nullptr;
+}
+
+void PermissionPromptImpl::ShowQuietIcon() {
+  prompt_style_ = PermissionPromptStyle::kLocationBarRightIcon;
+  // Shows the prompt as an indicator in the right side of the omnibox.
+  content_settings::UpdateLocationBarUiForWebContents(web_contents_);
+}
+
+void PermissionPromptImpl::ShowBubble() {
+  prompt_style_ = PermissionPromptStyle::kBubbleOnly;
+  prompt_bubble_ = new PermissionPromptBubbleView(
+      browser_, delegate_, permission_requested_time_, prompt_style_);
+  prompt_bubble_->Show();
+  prompt_bubble_->GetWidget()->AddObserver(this);
+}
+
+void PermissionPromptImpl::ShowChip() {
+  LocationBarView* lbv = GetLocationBarView();
+  DCHECK(lbv);
+
+  if (manager_->ShouldCurrentRequestUseQuietUI()) {
+    chip_ = lbv->DisplayQuietChip(
+        delegate_, !permissions::PermissionUiSelector::ShouldSuppressAnimation(
+                       manager_->ReasonForUsingQuietUi()));
+    prompt_style_ = PermissionPromptStyle::kQuietChip;
+  } else {
+    chip_ = lbv->DisplayChip(delegate_);
+    prompt_style_ = PermissionPromptStyle::kChip;
+  }
+}
+
+bool PermissionPromptImpl::ShouldCurrentRequestUseChip() {
+  if (!base::FeatureList::IsEnabled(permissions::features::kPermissionChip))
+    return false;
+
+  std::vector<permissions::PermissionRequest*> requests = delegate_->Requests();
+  return std::all_of(requests.begin(), requests.end(), [](auto* request) {
+    return request->GetChipText().has_value();
+  });
+}
+
+bool PermissionPromptImpl::ShouldCurrentRequestUseQuietChip() {
+  if (!base::FeatureList::IsEnabled(
+          permissions::features::kPermissionQuietChip)) {
+    return false;
+  }
+
+  std::vector<permissions::PermissionRequest*> requests = delegate_->Requests();
+  return std::all_of(requests.begin(), requests.end(), [](auto* request) {
+    return request->GetRequestType() ==
+               permissions::RequestType::kNotifications ||
+           request->GetRequestType() == permissions::RequestType::kGeolocation;
+  });
+}
+
+void PermissionPromptImpl::FinalizeChip() {
+  GetLocationBarView()->FinalizeChip();
+  chip_ = nullptr;
+}
diff --git a/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.h b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.h
index a7e8586..915288e 100644
--- a/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.h
+++ b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.h
@@ -18,6 +18,10 @@
 class BubbleDialogDelegateView;
 }
 
+namespace permissions {
+class PermissionRequestManager;
+}
+
 namespace content {
 class WebContents;
 }  // namespace content
@@ -49,10 +53,16 @@
   void OnWidgetClosing(views::Widget* widget) override;
 
  private:
+  bool IsLocationBarDisplayed();
+  void SelectPwaPrompt();
+  void SelectNormalPrompt();
+  void SelectQuietPrompt();
   LocationBarView* GetLocationBarView();
+  void ShowQuietIcon();
   void ShowBubble();
-  void ShowChipUI();
-  bool ShouldCurrentRequestUseChipUI();
+  void ShowChip();
+  bool ShouldCurrentRequestUseChip();
+  bool ShouldCurrentRequestUseQuietChip();
   void FinalizeChip();
 
   // The popup bubble. Not owned by this class; it will delete itself when a
@@ -72,6 +82,9 @@
 
   base::TimeTicks permission_requested_time_;
 
+  // PermissionRequestManager owns `this` and outlives `PermissionPromptImpl`.
+  permissions::PermissionRequestManager* manager_ = nullptr;
+
   DISALLOW_COPY_AND_ASSIGN(PermissionPromptImpl);
 };
 
diff --git a/chrome/browser/ui/views/permission_bubble/permission_prompt_style.h b/chrome/browser/ui/views/permission_bubble/permission_prompt_style.h
index 7a02f1c..b6231b1 100644
--- a/chrome/browser/ui/views/permission_bubble/permission_prompt_style.h
+++ b/chrome/browser/ui/views/permission_bubble/permission_prompt_style.h
@@ -12,7 +12,10 @@
   // The permission chip view in the location bar.
   kChip,
   // The prompt as an indicator in the right side of the omnibox.
-  kQuiet
+  kLocationBarRightIcon,
+  // The less prominent (quiet) version of permission chip view in the location
+  // bar.
+  kQuietChip
 };
 
 #endif  // CHROME_BROWSER_UI_VIEWS_PERMISSION_BUBBLE_PERMISSION_PROMPT_STYLE_H_