Commit e9934acb authored by Balazs Engedy's avatar Balazs Engedy Committed by Commit Bot

Introduce interface NotificationPermissionUiSelector.

Rename PermissionRequestAutoBlocker to NotificationPermissionUiSelector
to better reflect its current responsibility, and to disambiguate from
PermissionDecisionAutoBlocker.

Factor out all logic from ShouldCurrentRequestUseQuietUI() into an
NotificationPermissionUiSelector implementation, in preparation for the
drop-in replacement ContextualNotifictionPermissionUiSelector from a
follow-up CL.

Also update calls sites on Android to call the PermissionRequestManager
instead of the QuietNotificationPermissionUiState, so that these call
sites will be able to tolerate showing only a fraction of requests
using the quiet UI once Safe Browsing based triggering is enabled.

Bug: 1030633
Change-Id: I355072e0f40cae665536c66b0631d8e609be9b8f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1951105Reviewed-by: default avatarAndy Paicu <andypaicu@chromium.org>
Commit-Queue: Balazs Engedy <engedy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#721690}
parent a5b0d9bb
...@@ -1179,6 +1179,7 @@ jumbo_static_library("browser") { ...@@ -1179,6 +1179,7 @@ jumbo_static_library("browser") {
"permissions/crowd_deny_preload_data.h", "permissions/crowd_deny_preload_data.h",
"permissions/crowd_deny_safe_browsing_request.cc", "permissions/crowd_deny_safe_browsing_request.cc",
"permissions/crowd_deny_safe_browsing_request.h", "permissions/crowd_deny_safe_browsing_request.h",
"permissions/notification_permission_ui_selector.h",
"permissions/permission_context_base.cc", "permissions/permission_context_base.cc",
"permissions/permission_context_base.h", "permissions/permission_context_base.h",
"permissions/permission_decision_auto_blocker.cc", "permissions/permission_decision_auto_blocker.cc",
...@@ -1189,7 +1190,6 @@ jumbo_static_library("browser") { ...@@ -1189,7 +1190,6 @@ jumbo_static_library("browser") {
"permissions/permission_manager_factory.h", "permissions/permission_manager_factory.h",
"permissions/permission_request.cc", "permissions/permission_request.cc",
"permissions/permission_request.h", "permissions/permission_request.h",
"permissions/permission_request_auto_blocker.h",
"permissions/permission_request_id.cc", "permissions/permission_request_id.cc",
"permissions/permission_request_id.h", "permissions/permission_request_id.h",
"permissions/permission_request_impl.cc", "permissions/permission_request_impl.cc",
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/infobars/infobar_service.h"
#include "chrome/browser/permissions/permission_prompt_android.h" #include "chrome/browser/permissions/permission_prompt_android.h"
#include "chrome/browser/permissions/permission_request.h" #include "chrome/browser/permissions/permission_request.h"
#include "chrome/browser/permissions/permission_request_manager.h"
#include "chrome/browser/permissions/permission_uma_util.h" #include "chrome/browser/permissions/permission_uma_util.h"
#include "chrome/browser/permissions/permission_util.h" #include "chrome/browser/permissions/permission_util.h"
#include "chrome/browser/permissions/quiet_notification_permission_ui_config.h" #include "chrome/browser/permissions/quiet_notification_permission_ui_config.h"
...@@ -17,6 +18,7 @@ ...@@ -17,6 +18,7 @@
#include "chrome/grit/generated_resources.h" #include "chrome/grit/generated_resources.h"
#include "components/infobars/core/infobar.h" #include "components/infobars/core/infobar.h"
#include "components/url_formatter/elide_url.h" #include "components/url_formatter/elide_url.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
#include "ui/strings/grit/ui_strings.h" #include "ui/strings/grit/ui_strings.h"
...@@ -91,11 +93,11 @@ bool GroupedPermissionInfoBarDelegate::LinkClicked( ...@@ -91,11 +93,11 @@ bool GroupedPermissionInfoBarDelegate::LinkClicked(
// static // static
bool GroupedPermissionInfoBarDelegate::ShouldShowMiniInfobar( bool GroupedPermissionInfoBarDelegate::ShouldShowMiniInfobar(
Profile* profile, content::WebContents* web_contents,
ContentSettingsType type) { ContentSettingsType type) {
auto* manager = PermissionRequestManager::FromWebContents(web_contents);
return type == ContentSettingsType::NOTIFICATIONS && return type == ContentSettingsType::NOTIFICATIONS &&
// TODO(crbug.com/1030633): Consult PermissionRequestManager here. manager->ShouldCurrentRequestUseQuietUI() &&
QuietNotificationPermissionUiState::IsQuietUiEnabledInPrefs(profile) &&
QuietNotificationPermissionUiConfig::UiFlavorToUse() == QuietNotificationPermissionUiConfig::UiFlavorToUse() ==
QuietNotificationPermissionUiConfig::UiFlavor::MINI_INFOBAR; QuietNotificationPermissionUiConfig::UiFlavor::MINI_INFOBAR;
} }
......
...@@ -13,7 +13,10 @@ ...@@ -13,7 +13,10 @@
class InfoBarService; class InfoBarService;
class PermissionPromptAndroid; class PermissionPromptAndroid;
class Profile;
namespace content {
class WebContents;
}
// An InfoBar that displays a permission request. // An InfoBar that displays a permission request.
// //
...@@ -52,7 +55,8 @@ class GroupedPermissionInfoBarDelegate : public ConfirmInfoBarDelegate { ...@@ -52,7 +55,8 @@ class GroupedPermissionInfoBarDelegate : public ConfirmInfoBarDelegate {
bool LinkClicked(WindowOpenDisposition disposition) override; bool LinkClicked(WindowOpenDisposition disposition) override;
// Returns true if we should show the permission request as a mini-infobar. // Returns true if we should show the permission request as a mini-infobar.
static bool ShouldShowMiniInfobar(Profile* profile, ContentSettingsType type); static bool ShouldShowMiniInfobar(content::WebContents* web_contents,
ContentSettingsType type);
private: private:
GroupedPermissionInfoBarDelegate( GroupedPermissionInfoBarDelegate(
......
// Copyright 2019 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_PERMISSIONS_NOTIFICATION_PERMISSION_UI_SELECTOR_H_
#define CHROME_BROWSER_PERMISSIONS_NOTIFICATION_PERMISSION_UI_SELECTOR_H_
#include "chrome/browser/permissions/permission_request.h"
// The interface for implementations that decide if the quiet prompt UI should
// be used to display a notification permission |request|.
//
// Implementations of interface are expected to have long-lived instances that
// can support multiple requests, but only one at a time.
class NotificationPermissionUiSelector {
public:
enum class UiToUse {
kNormalUi,
kQuietUi,
};
enum class QuietUiReason {
kEnabledInPrefs,
kTriggeredByCrowdDeny,
};
using DecisionMadeCallback =
base::OnceCallback<void(UiToUse, base::Optional<QuietUiReason>)>;
virtual ~NotificationPermissionUiSelector() {}
// Determines the UI to use for the given |request|, and invokes |callback|
// when done, either synchronously or asynchrously. The |callback| is
// guaranteed never to be invoked after |this| goes out of scope. Only one
// request is supported at a time.
virtual void SelectUiToUse(PermissionRequest* request,
DecisionMadeCallback callback) = 0;
// Cancel the pending request, if any. After this, the |callback| is
// guaranteed not to be invoked anymore, and another call to SelectUiToUse()
// can be issued.
virtual void Cancel() {}
};
#endif // CHROME_BROWSER_PERMISSIONS_NOTIFICATION_PERMISSION_UI_SELECTOR_H_
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include "chrome/browser/permissions/grouped_permission_infobar_delegate_android.h" #include "chrome/browser/permissions/grouped_permission_infobar_delegate_android.h"
#include "chrome/browser/permissions/permission_dialog_delegate.h" #include "chrome/browser/permissions/permission_dialog_delegate.h"
#include "chrome/browser/permissions/permission_request.h" #include "chrome/browser/permissions/permission_request.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/url_constants.h" #include "chrome/common/url_constants.h"
#include "chrome/grit/generated_resources.h" #include "chrome/grit/generated_resources.h"
#include "components/infobars/core/infobar.h" #include "components/infobars/core/infobar.h"
...@@ -29,13 +28,11 @@ PermissionPromptAndroid::PermissionPromptAndroid( ...@@ -29,13 +28,11 @@ PermissionPromptAndroid::PermissionPromptAndroid(
weak_factory_(this) { weak_factory_(this) {
DCHECK(web_contents); DCHECK(web_contents);
Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
InfoBarService* infobar_service = InfoBarService* infobar_service =
InfoBarService::FromWebContents(web_contents_); InfoBarService::FromWebContents(web_contents_);
if (infobar_service && if (infobar_service &&
GroupedPermissionInfoBarDelegate::ShouldShowMiniInfobar( GroupedPermissionInfoBarDelegate::ShouldShowMiniInfobar(
profile, GetContentSettingType(0u /* position */))) { web_contents, GetContentSettingType(0u /* position */))) {
permission_infobar_ = GroupedPermissionInfoBarDelegate::Create( permission_infobar_ = GroupedPermissionInfoBarDelegate::Create(
weak_factory_.GetWeakPtr(), infobar_service); weak_factory_.GetWeakPtr(), infobar_service);
infobar_service->AddObserver(this); infobar_service->AddObserver(this);
...@@ -43,7 +40,7 @@ PermissionPromptAndroid::PermissionPromptAndroid( ...@@ -43,7 +40,7 @@ PermissionPromptAndroid::PermissionPromptAndroid(
} }
if (PermissionRequestNotificationAndroid::ShouldShowAsNotification( if (PermissionRequestNotificationAndroid::ShouldShowAsNotification(
profile, GetContentSettingType(0u /* position */))) { web_contents, GetContentSettingType(0u /* position */))) {
permission_request_notification_ = permission_request_notification_ =
PermissionRequestNotificationAndroid::Create(web_contents_, delegate_); PermissionRequestNotificationAndroid::Create(web_contents_, delegate_);
return; return;
......
// Copyright 2019 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_PERMISSIONS_PERMISSION_REQUEST_AUTO_BLOCKER_H_
#define CHROME_BROWSER_PERMISSIONS_PERMISSION_REQUEST_AUTO_BLOCKER_H_
#include "chrome/browser/permissions/permission_request.h"
// Describes the interface that needs to be implemented by a permission request
// automatic decision maker.
class PermissionRequestAutoBlocker {
public:
enum Response {
USE_NORMAL_UI,
USE_QUIET_UI,
TIMEOUT,
};
using DecisionMadeCallback = base::OnceCallback<void(Response)>;
virtual ~PermissionRequestAutoBlocker() = default;
// Callback needs to be always be invoked, even when a decision could not be
// made for some reason or another.
virtual void MakeDecision(PermissionRequest* request,
DecisionMadeCallback callback) = 0;
};
#endif // CHROME_BROWSER_PERMISSIONS_PERMISSION_REQUEST_AUTO_BLOCKER_H_
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "base/task/post_task.h" #include "base/task/post_task.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "chrome/browser/permissions/adaptive_quiet_notification_permission_ui_enabler.h" #include "chrome/browser/permissions/adaptive_quiet_notification_permission_ui_enabler.h"
#include "chrome/browser/permissions/notification_permission_ui_selector.h"
#include "chrome/browser/permissions/permission_decision_auto_blocker.h" #include "chrome/browser/permissions/permission_decision_auto_blocker.h"
#include "chrome/browser/permissions/permission_request.h" #include "chrome/browser/permissions/permission_request.h"
#include "chrome/browser/permissions/permission_uma_util.h" #include "chrome/browser/permissions/permission_uma_util.h"
...@@ -40,6 +41,35 @@ ...@@ -40,6 +41,35 @@
namespace { namespace {
class NotificationPermissionUiSelectorBasedOnPrefs
: public NotificationPermissionUiSelector {
public:
explicit NotificationPermissionUiSelectorBasedOnPrefs(Profile* profile)
: profile_(profile) {}
~NotificationPermissionUiSelectorBasedOnPrefs() override = default;
// NotificationPermissionUiSelector:
void SelectUiToUse(PermissionRequest* request,
DecisionMadeCallback callback) override {
if (QuietNotificationPermissionUiConfig::UiFlavorToUse() !=
QuietNotificationPermissionUiConfig::NONE &&
QuietNotificationPermissionUiState::IsQuietUiEnabledInPrefs(profile_)) {
std::move(callback).Run(UiToUse::kQuietUi,
QuietUiReason::kEnabledInPrefs);
} else {
std::move(callback).Run(UiToUse::kNormalUi, base::nullopt);
}
}
private:
NotificationPermissionUiSelectorBasedOnPrefs(
const NotificationPermissionUiSelectorBasedOnPrefs&) = delete;
const NotificationPermissionUiSelectorBasedOnPrefs& operator=(
NotificationPermissionUiSelectorBasedOnPrefs&) = delete;
Profile* profile_;
};
bool IsMessageTextEqual(PermissionRequest* a, bool IsMessageTextEqual(PermissionRequest* a,
PermissionRequest* b) { PermissionRequest* b) {
if (a == b) if (a == b)
...@@ -270,7 +300,7 @@ void PermissionRequestManager::OnVisibilityChanged( ...@@ -270,7 +300,7 @@ void PermissionRequestManager::OnVisibilityChanged(
// We switched tabs away and back while a prompt was active. // We switched tabs away and back while a prompt was active.
DCHECK_EQ(view_->GetTabSwitchingBehavior(), DCHECK_EQ(view_->GetTabSwitchingBehavior(),
PermissionPrompt::TabSwitchingBehavior::kKeepPromptAlive); PermissionPrompt::TabSwitchingBehavior::kKeepPromptAlive);
} else if (current_request_autoblocker_response_.has_value()) { } else if (current_request_ui_to_use_.has_value()) {
ShowBubble(); ShowBubble();
} }
} }
...@@ -353,9 +383,11 @@ PermissionRequestManager::PermissionRequestManager( ...@@ -353,9 +383,11 @@ PermissionRequestManager::PermissionRequestManager(
view_(nullptr), view_(nullptr),
tab_is_hidden_(web_contents->GetVisibility() == tab_is_hidden_(web_contents->GetVisibility() ==
content::Visibility::HIDDEN), content::Visibility::HIDDEN),
auto_response_for_test_(NONE), auto_response_for_test_(NONE) {
blocker_(nullptr), notification_permission_ui_selector_ =
current_request_autoblocker_response_(base::nullopt) {} std::make_unique<NotificationPermissionUiSelectorBasedOnPrefs>(
Profile::FromBrowserContext(web_contents->GetBrowserContext()));
}
void PermissionRequestManager::ScheduleShowBubble() { void PermissionRequestManager::ScheduleShowBubble() {
base::RecordAction(base::UserMetricsAction("PermissionBubbleRequest")); base::RecordAction(base::UserMetricsAction("PermissionBubbleRequest"));
...@@ -379,7 +411,17 @@ void PermissionRequestManager::DequeueRequestIfNeeded() { ...@@ -379,7 +411,17 @@ void PermissionRequestManager::DequeueRequestIfNeeded() {
queued_requests_.pop_front(); queued_requests_.pop_front();
} }
QueryAutoBlockerAndShowOrReject(); if (requests_.front()->GetPermissionRequestType() ==
PermissionRequestType::PERMISSION_NOTIFICATIONS) {
notification_permission_ui_selector_->SelectUiToUse(
requests_.front(),
base::BindOnce(
&PermissionRequestManager::OnSelectedUiToUseForNotifications,
weak_factory_.GetWeakPtr()));
} else {
current_request_ui_to_use_ = UiToUse::kNormalUi;
ScheduleShowBubble();
}
} }
void PermissionRequestManager::ScheduleDequeueRequestIfNeeded() { void PermissionRequestManager::ScheduleDequeueRequestIfNeeded() {
...@@ -393,6 +435,7 @@ void PermissionRequestManager::ShowBubble() { ...@@ -393,6 +435,7 @@ void PermissionRequestManager::ShowBubble() {
DCHECK(!view_); DCHECK(!view_);
DCHECK(IsRequestInProgress()); DCHECK(IsRequestInProgress());
DCHECK(web_contents()->IsDocumentOnLoadCompletedInMainFrame()); DCHECK(web_contents()->IsDocumentOnLoadCompletedInMainFrame());
DCHECK(current_request_ui_to_use_);
if (tab_is_hidden_) if (tab_is_hidden_)
return; return;
...@@ -470,6 +513,12 @@ void PermissionRequestManager::FinalizeBubble( ...@@ -470,6 +513,12 @@ void PermissionRequestManager::FinalizeBubble(
} }
requests_.clear(); requests_.clear();
notification_permission_ui_selector_->Cancel();
current_request_view_shown_to_user_ = false;
current_request_ui_to_use_.reset();
current_request_quiet_ui_reason_.reset();
if (view_) if (view_)
DeleteBubble(); DeleteBubble();
...@@ -557,35 +606,15 @@ bool PermissionRequestManager::ShouldCurrentRequestUseQuietUI() { ...@@ -557,35 +606,15 @@ bool PermissionRequestManager::ShouldCurrentRequestUseQuietUI() {
if (!IsRequestInProgress()) if (!IsRequestInProgress())
return false; return false;
// The autoblocker has enforced a quiet UI on this request. // ContentSettingImageModel might call into this method if the user switches
if (current_request_autoblocker_response_.has_value() && // between tabs while the |notification_permission_ui_selector_| is pending.
current_request_autoblocker_response_ == return current_request_ui_to_use_ &&
PermissionRequestAutoBlocker::USE_QUIET_UI) *current_request_ui_to_use_ == UiToUse::kQuietUi;
return true; }
Profile* profile =
Profile::FromBrowserContext(web_contents()->GetBrowserContext());
bool not_a_notifications_request =
requests_.front()->GetPermissionRequestType() !=
PermissionRequestType::PERMISSION_NOTIFICATIONS;
bool should_show_loud_ui =
!QuietNotificationPermissionUiState::IsQuietUiEnabledInPrefs(profile);
if (not_a_notifications_request || should_show_loud_ui)
return false;
const auto ui_flavor = QuietNotificationPermissionUiConfig::UiFlavorToUse();
#if !defined(OS_ANDROID) PermissionRequestManager::QuietUiReason
return (ui_flavor == QuietNotificationPermissionUiConfig::STATIC_ICON || PermissionRequestManager::ReasonForUsingQuietUi() {
ui_flavor == QuietNotificationPermissionUiConfig::ANIMATED_ICON); return *current_request_quiet_ui_reason_;
#else // OS_ANDROID
return (
ui_flavor == QuietNotificationPermissionUiConfig::QUIET_NOTIFICATION ||
ui_flavor == QuietNotificationPermissionUiConfig::HEADS_UP_NOTIFICATION ||
ui_flavor == QuietNotificationPermissionUiConfig::MINI_INFOBAR);
#endif // OS_ANDROID
} }
bool PermissionRequestManager::IsRequestInProgress() { bool PermissionRequestManager::IsRequestInProgress() {
...@@ -602,25 +631,11 @@ void PermissionRequestManager::NotifyBubbleRemoved() { ...@@ -602,25 +631,11 @@ void PermissionRequestManager::NotifyBubbleRemoved() {
observer.OnBubbleRemoved(); observer.OnBubbleRemoved();
} }
void PermissionRequestManager::QueryAutoBlockerAndShowOrReject() { void PermissionRequestManager::OnSelectedUiToUseForNotifications(
current_request_view_shown_to_user_ = false; UiToUse ui_to_use,
current_request_autoblocker_response_.reset(); base::Optional<QuietUiReason> quiet_ui_reason) {
current_request_ui_to_use_ = ui_to_use;
if (blocker_) { current_request_quiet_ui_reason_ = quiet_ui_reason;
blocker_->MakeDecision(
requests_.front(),
base::BindOnce(&PermissionRequestManager::AutoBlockerDecisionMade,
weak_factory_.GetWeakPtr()));
} else {
// This simply simulates an auto-blocker decision of "allow".
AutoBlockerDecisionMade(
PermissionRequestAutoBlocker::Response::USE_NORMAL_UI);
}
}
void PermissionRequestManager::AutoBlockerDecisionMade(
PermissionRequestAutoBlocker::Response response) {
current_request_autoblocker_response_ = response;
ScheduleShowBubble(); ScheduleShowBubble();
} }
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#include "base/gtest_prod_util.h" #include "base/gtest_prod_util.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/observer_list.h" #include "base/observer_list.h"
#include "chrome/browser/permissions/permission_request_auto_blocker.h" #include "chrome/browser/permissions/notification_permission_ui_selector.h"
#include "chrome/browser/ui/permission_bubble/permission_prompt.h" #include "chrome/browser/ui/permission_bubble/permission_prompt.h"
#include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h" #include "content/public/browser/web_contents_user_data.h"
...@@ -57,6 +57,9 @@ class PermissionRequestManager ...@@ -57,6 +57,9 @@ class PermissionRequestManager
DISMISS DISMISS
}; };
using UiToUse = NotificationPermissionUiSelector::UiToUse;
using QuietUiReason = NotificationPermissionUiSelector::QuietUiReason;
~PermissionRequestManager() override; ~PermissionRequestManager() override;
// Adds a new request to the permission bubble. Ownership of the request // Adds a new request to the permission bubble. Ownership of the request
...@@ -80,6 +83,7 @@ class PermissionRequestManager ...@@ -80,6 +83,7 @@ class PermissionRequestManager
void RemoveObserver(Observer* observer); void RemoveObserver(Observer* observer);
bool ShouldCurrentRequestUseQuietUI(); bool ShouldCurrentRequestUseQuietUI();
QuietUiReason ReasonForUsingQuietUi();
bool IsRequestInProgress(); bool IsRequestInProgress();
...@@ -108,15 +112,10 @@ class PermissionRequestManager ...@@ -108,15 +112,10 @@ class PermissionRequestManager
void Deny() override; void Deny() override;
void Closing() override; void Closing() override;
// For testing only, used to override the default autoblocker. // For testing only, used to override the default UI selector.
void set_autoblocker_for_testing( void set_notification_permission_ui_selector_for_testing(
std::unique_ptr<PermissionRequestAutoBlocker> blocker) { std::unique_ptr<NotificationPermissionUiSelector> selector) {
blocker_ = std::move(blocker); notification_permission_ui_selector_ = std::move(selector);
}
PermissionRequestAutoBlocker::Response
current_request_autoblocker_response_for_testing() {
return current_request_autoblocker_response_.value();
} }
private: private:
...@@ -182,12 +181,9 @@ class PermissionRequestManager ...@@ -182,12 +181,9 @@ class PermissionRequestManager
void NotifyBubbleAdded(); void NotifyBubbleAdded();
void NotifyBubbleRemoved(); void NotifyBubbleRemoved();
// Will query crowd deny data and make a decision on whether to show or reject void OnSelectedUiToUseForNotifications(
// a request. UiToUse ui_to_use,
void QueryAutoBlockerAndShowOrReject(); base::Optional<QuietUiReason> quiet_ui_reason);
// Autoblocker callback.
void AutoBlockerDecisionMade(PermissionRequestAutoBlocker::Response response);
PermissionPromptDisposition DetermineCurrentRequestUIDispositionForUMA(); PermissionPromptDisposition DetermineCurrentRequestUIDispositionForUMA();
...@@ -221,18 +217,24 @@ class PermissionRequestManager ...@@ -221,18 +217,24 @@ class PermissionRequestManager
// origin requesting the permission. // origin requesting the permission.
bool is_notification_prompt_cooldown_active_ = false; bool is_notification_prompt_cooldown_active_ = false;
// The permission request auto blocker to be used for deciding whether to // Decides if the quiet prompt UI should be used to display notification
// block the request or not. // permission requests.
std::unique_ptr<PermissionRequestAutoBlocker> blocker_; std::unique_ptr<NotificationPermissionUiSelector>
notification_permission_ui_selector_;
// Whether the view for the current |requests_| has been shown to the user at // Whether the view for the current |requests_| has been shown to the user at
// least once. // least once.
bool current_request_view_shown_to_user_ = false; bool current_request_view_shown_to_user_ = false;
// The autoblocker response for the current |requests_|, or nullopt if we are // Whether to use the normal or quiet UI to display the current permission
// still waiting for the response. // |requests_|, or nullopt if we are still waiting on the result from the
base::Optional<PermissionRequestAutoBlocker::Response> // |notification_permission_ui_selector_|.
current_request_autoblocker_response_; base::Optional<UiToUse> current_request_ui_to_use_;
// The reason for using the quiet UI to display the current permission
// |requests_|, or nullopt if we are still waiting for the response from the
// |notification_permission_ui_selector_| or we are using the normal UI.
base::Optional<QuietUiReason> current_request_quiet_ui_reason_;
base::WeakPtrFactory<PermissionRequestManager> weak_factory_{this}; base::WeakPtrFactory<PermissionRequestManager> weak_factory_{this};
WEB_CONTENTS_USER_DATA_KEY_DECL(); WEB_CONTENTS_USER_DATA_KEY_DECL();
......
...@@ -17,8 +17,8 @@ ...@@ -17,8 +17,8 @@
#include "chrome/browser/engagement/site_engagement_service.h" #include "chrome/browser/engagement/site_engagement_service.h"
#include "chrome/browser/permissions/adaptive_quiet_notification_permission_ui_enabler.h" #include "chrome/browser/permissions/adaptive_quiet_notification_permission_ui_enabler.h"
#include "chrome/browser/permissions/mock_permission_request.h" #include "chrome/browser/permissions/mock_permission_request.h"
#include "chrome/browser/permissions/notification_permission_ui_selector.h"
#include "chrome/browser/permissions/permission_request.h" #include "chrome/browser/permissions/permission_request.h"
#include "chrome/browser/permissions/permission_request_auto_blocker.h"
#include "chrome/browser/permissions/permission_request_manager.h" #include "chrome/browser/permissions/permission_request_manager.h"
#include "chrome/browser/permissions/permission_uma_util.h" #include "chrome/browser/permissions/permission_uma_util.h"
#include "chrome/browser/permissions/quiet_notification_permission_ui_config.h" #include "chrome/browser/permissions/quiet_notification_permission_ui_config.h"
...@@ -720,13 +720,12 @@ TEST_F(PermissionRequestManagerTest, ...@@ -720,13 +720,12 @@ TEST_F(PermissionRequestManagerTest,
WaitForBubbleToBeShown(); WaitForBubbleToBeShown();
EXPECT_TRUE(manager_->ShouldCurrentRequestUseQuietUI()); EXPECT_TRUE(manager_->ShouldCurrentRequestUseQuietUI());
// Clearing interaction history does not change the state for the enabled // Clearing interaction history, or turning off quiet mode in preferences does
// quiet UI. // not change the state of the currently showing quiet UI.
permission_ui_enabler->ClearInteractionHistory(base::Time(), permission_ui_enabler->ClearInteractionHistory(base::Time(),
base::Time::Max()); base::Time::Max());
EXPECT_TRUE(manager_->ShouldCurrentRequestUseQuietUI());
QuietNotificationPermissionUiState::DisableQuietUiInPrefs(profile()); QuietNotificationPermissionUiState::DisableQuietUiInPrefs(profile());
EXPECT_FALSE(manager_->ShouldCurrentRequestUseQuietUI()); EXPECT_TRUE(manager_->ShouldCurrentRequestUseQuietUI());
Deny(); Deny();
base::Time recorded_time = clock_.Now(); base::Time recorded_time = clock_.Now();
...@@ -740,6 +739,7 @@ TEST_F(PermissionRequestManagerTest, ...@@ -740,6 +739,7 @@ TEST_F(PermissionRequestManagerTest,
notification9); notification9);
manager_->AddRequest(&notification9_request); manager_->AddRequest(&notification9_request);
WaitForBubbleToBeShown(); WaitForBubbleToBeShown();
EXPECT_FALSE(manager_->ShouldCurrentRequestUseQuietUI());
Deny(); Deny();
clock_.Advance(base::TimeDelta::FromDays(1)); clock_.Advance(base::TimeDelta::FromDays(1));
...@@ -778,86 +778,114 @@ TEST_F(PermissionRequestManagerTest, ...@@ -778,86 +778,114 @@ TEST_F(PermissionRequestManagerTest,
recorded_time); recorded_time);
} }
// Will simulate an autoblocker that simply returns a predefined response every // Simulate a NotificationPermissionUiSelector that simply returns a
// time. // predefined |ui_to_use| every time.
class MockPermissionRequestAutoBlocker : public PermissionRequestAutoBlocker { class MockNotificationPermissionUiSelector
: public NotificationPermissionUiSelector {
public: public:
explicit MockPermissionRequestAutoBlocker(Response response, bool async) { explicit MockNotificationPermissionUiSelector(UiToUse ui_to_use, bool async) {
response_ = response; ui_to_use_ = ui_to_use;
async_ = async; async_ = async;
} }
void MakeDecision(PermissionRequest* request, void SelectUiToUse(PermissionRequest* request,
DecisionMadeCallback callback) override { DecisionMadeCallback callback) override {
if (async_) { if (async_) {
base::PostTask(FROM_HERE, {base::CurrentThread()}, base::PostTask(
base::BindOnce(std::move(callback), response_)); FROM_HERE, {base::CurrentThread()},
base::BindOnce(std::move(callback), ui_to_use_, base::nullopt));
} else { } else {
std::move(callback).Run(response_); std::move(callback).Run(ui_to_use_, base::nullopt);
} }
} }
static void CreateForManager(PermissionRequestManager* manager, static void CreateForManager(PermissionRequestManager* manager,
Response response, UiToUse ui_to_use,
bool async) { bool async) {
manager->set_autoblocker_for_testing( manager->set_notification_permission_ui_selector_for_testing(
std::make_unique<MockPermissionRequestAutoBlocker>(response, async)); std::make_unique<MockNotificationPermissionUiSelector>(ui_to_use,
async));
} }
private: private:
Response response_; UiToUse ui_to_use_;
bool async_; bool async_;
}; };
TEST_F(PermissionRequestManagerTest, AutoBlocker) { TEST_F(PermissionRequestManagerTest,
struct { UiSelectorNotUsedForPermissionsOtherThanNotification) {
MockPermissionRequest* request; for (auto* request : {&request_mic_, &request_camera_}) {
PermissionRequestAutoBlocker::Response auto_blocker_set_response; MockNotificationPermissionUiSelector::CreateForManager(
manager_, NotificationPermissionUiSelector::UiToUse::kQuietUi,
false /* async */);
manager_->AddRequest(request);
WaitForBubbleToBeShown();
ASSERT_TRUE(prompt_factory_->is_visible());
ASSERT_TRUE(
prompt_factory_->RequestTypeSeen(request->GetPermissionRequestType()));
EXPECT_FALSE(manager_->ShouldCurrentRequestUseQuietUI());
Accept();
EXPECT_TRUE(request->granted());
}
}
TEST_F(PermissionRequestManagerTest, UiSelectorUsedForNotifications) {
using UiToUse = NotificationPermissionUiSelector::UiToUse;
const struct {
NotificationPermissionUiSelector::UiToUse ui_to_use;
bool async; bool async;
} tests[] = { } kTests[] = {
{&request1_, PermissionRequestAutoBlocker::Response::USE_NORMAL_UI, true}, {UiToUse::kQuietUi, true},
{&request2_, PermissionRequestAutoBlocker::Response::TIMEOUT, true}, {UiToUse::kNormalUi, true},
{&request_mic_, PermissionRequestAutoBlocker::Response::USE_QUIET_UI, {UiToUse::kQuietUi, false},
true}, {UiToUse::kNormalUi, false},
{&request_camera_, PermissionRequestAutoBlocker::Response::USE_QUIET_UI,
false},
}; };
for (const auto& test : tests) { for (const auto& test : kTests) {
MockPermissionRequestAutoBlocker::CreateForManager( MockNotificationPermissionUiSelector::CreateForManager(
manager_, test.auto_blocker_set_response, test.async); manager_, test.ui_to_use, test.async);
MockPermissionRequest request(
"foo", PermissionRequestType::PERMISSION_NOTIFICATIONS,
PermissionRequestGestureType::GESTURE);
manager_->AddRequest(test.request); manager_->AddRequest(&request);
WaitForBubbleToBeShown(); WaitForBubbleToBeShown();
EXPECT_TRUE(prompt_factory_->is_visible()); EXPECT_TRUE(prompt_factory_->is_visible());
EXPECT_TRUE(prompt_factory_->RequestTypeSeen( EXPECT_TRUE(
test.request->GetPermissionRequestType())); prompt_factory_->RequestTypeSeen(request.GetPermissionRequestType()));
EXPECT_EQ(test.ui_to_use == UiToUse::kQuietUi,
manager_->ShouldCurrentRequestUseQuietUI());
Accept(); Accept();
EXPECT_TRUE(test.request->granted()); EXPECT_TRUE(request.granted());
EXPECT_EQ(manager_->current_request_autoblocker_response_for_testing(),
test.auto_blocker_set_response);
} }
} }
TEST_F(PermissionRequestManagerTest, TEST_F(PermissionRequestManagerTest,
ShouldCurrentRequestUseQuietUIAffectedByAutoblocker) { UiSelectionHappensSeparatelyForEachRequest) {
using UiToUse = NotificationPermissionUiSelector::UiToUse;
MockNotificationPermissionUiSelector::CreateForManager(
manager_, UiToUse::kQuietUi, true);
MockPermissionRequest request1( MockPermissionRequest request1(
"request1", PermissionRequestType::PERMISSION_NOTIFICATIONS, "request1", PermissionRequestType::PERMISSION_NOTIFICATIONS,
PermissionRequestGestureType::GESTURE); PermissionRequestGestureType::GESTURE);
manager_->AddRequest(&request1); manager_->AddRequest(&request1);
WaitForBubbleToBeShown(); WaitForBubbleToBeShown();
EXPECT_FALSE(manager_->ShouldCurrentRequestUseQuietUI()); EXPECT_TRUE(manager_->ShouldCurrentRequestUseQuietUI());
Accept(); Accept();
MockPermissionRequest request2( MockPermissionRequest request2(
"request2", PermissionRequestType::PERMISSION_NOTIFICATIONS, "request2", PermissionRequestType::PERMISSION_NOTIFICATIONS,
PermissionRequestGestureType::GESTURE); PermissionRequestGestureType::GESTURE);
MockPermissionRequestAutoBlocker::CreateForManager( MockNotificationPermissionUiSelector::CreateForManager(
manager_, PermissionRequestAutoBlocker::Response::USE_QUIET_UI, true); manager_, UiToUse::kNormalUi, true);
manager_->AddRequest(&request2); manager_->AddRequest(&request2);
WaitForBubbleToBeShown(); WaitForBubbleToBeShown();
EXPECT_TRUE(manager_->ShouldCurrentRequestUseQuietUI()); EXPECT_FALSE(manager_->ShouldCurrentRequestUseQuietUI());
Accept(); Accept();
} }
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "chrome/browser/notifications/notification_display_service_impl.h" #include "chrome/browser/notifications/notification_display_service_impl.h"
#include "chrome/browser/notifications/notification_handler.h" #include "chrome/browser/notifications/notification_handler.h"
#include "chrome/browser/permissions/permission_request.h" #include "chrome/browser/permissions/permission_request.h"
#include "chrome/browser/permissions/permission_request_manager.h"
#include "chrome/browser/permissions/permission_request_notification_handler.h" #include "chrome/browser/permissions/permission_request_notification_handler.h"
#include "chrome/browser/permissions/quiet_notification_permission_ui_config.h" #include "chrome/browser/permissions/quiet_notification_permission_ui_config.h"
#include "chrome/browser/permissions/quiet_notification_permission_ui_state.h" #include "chrome/browser/permissions/quiet_notification_permission_ui_state.h"
...@@ -56,11 +57,11 @@ PermissionRequestNotificationAndroid::Create( ...@@ -56,11 +57,11 @@ PermissionRequestNotificationAndroid::Create(
// static // static
bool PermissionRequestNotificationAndroid::ShouldShowAsNotification( bool PermissionRequestNotificationAndroid::ShouldShowAsNotification(
Profile* profile, content::WebContents* web_contents,
ContentSettingsType type) { ContentSettingsType type) {
auto* manager = PermissionRequestManager::FromWebContents(web_contents);
return type == ContentSettingsType::NOTIFICATIONS && return type == ContentSettingsType::NOTIFICATIONS &&
// TODO(crbug.com/1030633): Consult PermissionRequestManager here. manager->ShouldCurrentRequestUseQuietUI() &&
QuietNotificationPermissionUiState::IsQuietUiEnabledInPrefs(profile) &&
(QuietNotificationPermissionUiConfig::UiFlavorToUse() == (QuietNotificationPermissionUiConfig::UiFlavorToUse() ==
QuietNotificationPermissionUiConfig::UiFlavor:: QuietNotificationPermissionUiConfig::UiFlavor::
HEADS_UP_NOTIFICATION || HEADS_UP_NOTIFICATION ||
......
...@@ -21,7 +21,6 @@ class Notification; ...@@ -21,7 +21,6 @@ class Notification;
} // namespace message_center } // namespace message_center
class NotificationDisplayServiceImpl; class NotificationDisplayServiceImpl;
class Profile;
// Class for displaying a permission prompt as a notification. Uses // Class for displaying a permission prompt as a notification. Uses
// the notification display service to show the notification. // the notification display service to show the notification.
...@@ -36,7 +35,7 @@ class PermissionRequestNotificationAndroid final ...@@ -36,7 +35,7 @@ class PermissionRequestNotificationAndroid final
PermissionPrompt::Delegate* delegate); PermissionPrompt::Delegate* delegate);
// Returns true if we should show the permission request as a notification. // Returns true if we should show the permission request as a notification.
static bool ShouldShowAsNotification(Profile* profile, static bool ShouldShowAsNotification(content::WebContents* web_contents,
ContentSettingsType type); ContentSettingsType type);
// Converts an origin string into a notification id. // Converts an origin string into a notification id.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment