1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/permissions/permission_request_manager.h"
9 #include "base/auto_reset.h"
10 #include "base/command_line.h"
11 #include "base/containers/contains.h"
12 #include "base/functional/bind.h"
13 #include "base/metrics/histogram_functions.h"
14 #include "base/metrics/user_metrics.h"
15 #include "base/metrics/user_metrics_action.h"
16 #include "base/observer_list.h"
17 #include "base/rand_util.h"
18 #include "base/ranges/algorithm.h"
19 #include "base/task/sequenced_task_runner.h"
20 #include "base/time/clock.h"
21 #include "base/time/time.h"
22 #include "components/back_forward_cache/back_forward_cache_disable.h"
23 #include "components/permissions/constants.h"
24 #include "components/permissions/features.h"
25 #include "components/permissions/origin_keyed_permission_action_service.h"
26 #include "components/permissions/permission_decision_auto_blocker.h"
27 #include "components/permissions/permission_prompt.h"
28 #include "components/permissions/permission_request.h"
29 #include "components/permissions/permission_uma_util.h"
30 #include "components/permissions/permission_util.h"
31 #include "components/permissions/permissions_client.h"
32 #include "components/permissions/request_type.h"
33 #include "components/permissions/switches.h"
34 #include "content/public/browser/back_forward_cache.h"
35 #include "content/public/browser/browser_context.h"
36 #include "content/public/browser/browser_task_traits.h"
37 #include "content/public/browser/browser_thread.h"
38 #include "content/public/browser/disallow_activation_reason.h"
39 #include "content/public/browser/navigation_handle.h"
40 #include "content/public/browser/render_frame_host.h"
41 #include "content/public/browser/render_process_host.h"
42 #include "content/public/browser/web_contents.h"
43 #include "ui/base/window_open_disposition_utils.h"
44 #include "ui/events/event.h"
46 #include "url/origin.h"
48 #if BUILDFLAG(IS_ANDROID)
49 #include "components/permissions/android/android_permission_util.h"
52 namespace permissions {
54 const char kAbusiveNotificationRequestsEnforcementMessage[] =
55 "Chrome is blocking notification permission requests on this site because "
56 "the site tends to show permission requests that mislead, trick, or force "
57 "users into allowing notifications. You should fix the issues as soon as "
58 "possible and submit your site for another review. Learn more at "
59 "https://support.google.com/webtools/answer/9799048.";
61 const char kAbusiveNotificationRequestsWarningMessage[] =
62 "Chrome might start blocking notification permission requests on this site "
63 "in the future because the site tends to show permission requests that "
64 "mislead, trick, or force users into allowing notifications. You should "
65 "fix the issues as soon as possible and submit your site for another "
66 "review. Learn more at https://support.google.com/webtools/answer/9799048.";
68 constexpr char kAbusiveNotificationContentEnforcementMessage[] =
69 "Chrome is blocking notification permission requests on this site because "
70 "the site tends to show notifications with content that mislead or trick "
71 "users. You should fix the issues as soon as possible and submit your site "
72 "for another review. Learn more at "
73 "https://support.google.com/webtools/answer/9799048";
75 constexpr char kAbusiveNotificationContentWarningMessage[] =
76 "Chrome might start blocking notification permission requests on this site "
77 "in the future because the site tends to show notifications with content "
78 "that mislead or trick users. You should fix the issues as soon as "
79 "possible and submit your site for another review. Learn more at "
80 "https://support.google.com/webtools/answer/9799048";
82 constexpr char kDisruptiveNotificationBehaviorEnforcementMessage[] =
83 "Chrome is blocking notification permission requests on this site because "
84 "the site exhibits behaviors that may be disruptive to users.";
88 // In case of multiple permission requests that use chip UI, a newly added
89 // request will preempt the currently showing request, which is put back to the
90 // queue, and will be shown later. To reduce user annoyance, if a quiet chip
91 // permission prompt was displayed longer than `kQuietChipIgnoreTimeout`, we
92 // consider it as shown long enough and it will not be shown again after it is
94 // TODO(crbug.com/1221083): If a user switched tabs, do not include that time as
96 bool ShouldShowQuietRequestAgainIfPreempted(
97 absl::optional<base::Time> request_display_start_time) {
98 if (request_display_start_time->is_null()) {
102 static constexpr base::TimeDelta kQuietChipIgnoreTimeout = base::Seconds(8.5);
103 return base::Time::Now() - request_display_start_time.value() <
104 kQuietChipIgnoreTimeout;
107 bool IsMediaRequest(RequestType type) {
108 #if !BUILDFLAG(IS_ANDROID)
109 if (type == RequestType::kCameraPanTiltZoom)
112 return type == RequestType::kMicStream || type == RequestType::kCameraStream;
115 bool ShouldGroupRequests(PermissionRequest* a, PermissionRequest* b) {
116 if (a->requesting_origin() != b->requesting_origin())
119 // Group if both requests are media requests.
120 if (IsMediaRequest(a->request_type()) && IsMediaRequest(b->request_type())) {
129 // PermissionRequestManager ----------------------------------------------------
131 bool PermissionRequestManager::PermissionRequestSource::
132 IsSourceFrameInactiveAndDisallowActivation() const {
133 content::RenderFrameHost* rfh =
134 content::RenderFrameHost::FromID(requesting_frame_id);
136 rfh->IsInactiveAndDisallowActivation(
137 content::DisallowActivationReasonId::kPermissionRequestSource);
140 PermissionRequestManager::~PermissionRequestManager() {
141 DCHECK(!IsRequestInProgress());
142 DCHECK(duplicate_requests_.empty());
143 DCHECK(pending_permission_requests_.IsEmpty());
145 for (Observer& observer : observer_list_)
146 observer.OnPermissionRequestManagerDestructed();
149 void PermissionRequestManager::AddRequest(
150 content::RenderFrameHost* source_frame,
151 PermissionRequest* request) {
152 DCHECK(source_frame);
153 DCHECK_EQ(content::WebContents::FromRenderFrameHost(source_frame),
156 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
157 switches::kDenyPermissionPrompts)) {
158 request->PermissionDenied();
159 request->RequestFinished();
163 if (source_frame->IsInactiveAndDisallowActivation(
164 content::DisallowActivationReasonId::kPermissionAddRequest)) {
165 request->Cancelled();
166 request->RequestFinished();
170 if (source_frame->IsNestedWithinFencedFrame()) {
171 request->Cancelled();
172 request->RequestFinished();
176 #if BUILDFLAG(IS_ANDROID)
177 if (request->GetContentSettingsType() == ContentSettingsType::NOTIFICATIONS) {
178 bool app_level_settings_allow_site_notifications =
179 enabled_app_level_notification_permission_for_testing_.has_value()
180 ? enabled_app_level_notification_permission_for_testing_.value()
181 : DoesAppLevelSettingsAllowSiteNotifications();
182 base::UmaHistogramBoolean(
183 "Permissions.Prompt.Notifications.EnabledAppLevel",
184 app_level_settings_allow_site_notifications);
186 if (!app_level_settings_allow_site_notifications &&
187 base::FeatureList::IsEnabled(
188 features::kBlockNotificationPromptsIfDisabledOnAppLevel)) {
189 // Automatically cancel site Notification requests when Chrome is not able
190 // to send notifications in an app level.
191 request->Cancelled();
192 request->RequestFinished();
196 #endif // BUILDFLAG(IS_ANDROID)
198 if (is_notification_prompt_cooldown_active_ &&
199 request->GetContentSettingsType() == ContentSettingsType::NOTIFICATIONS) {
200 // Short-circuit by canceling rather than denying to avoid creating a large
201 // number of content setting exceptions on Desktop / disabled notification
202 // channels on Android.
203 request->Cancelled();
204 request->RequestFinished();
208 if (!web_contents_supports_permission_requests_) {
209 request->Cancelled();
210 request->RequestFinished();
214 // TODO(tsergeant): change the UMA to no longer mention bubble.
215 base::RecordAction(base::UserMetricsAction("PermissionBubbleRequest"));
217 // TODO(gbillock): is there a race between an early request on a
218 // newly-navigated page and the to-be-cleaned-up requests on the previous
219 // page? We should maybe listen to DidStartNavigationToPendingEntry (and
220 // any other renderer-side nav initiations?). Double-check this for
221 // correct behavior on interstitials -- we probably want to basically queue
222 // any request for which GetVisibleURL != GetLastCommittedURL.
223 CHECK(source_frame->GetMainFrame()->IsInPrimaryMainFrame());
224 const GURL main_frame_origin =
225 PermissionUtil::GetLastCommittedOriginAsURL(source_frame->GetMainFrame());
227 url::IsSameOriginWith(main_frame_origin, request->requesting_origin());
229 absl::optional<url::Origin> auto_approval_origin =
230 PermissionsClient::Get()->GetAutoApprovalOrigin();
231 if (auto_approval_origin) {
232 if (url::Origin::Create(request->requesting_origin()) ==
233 auto_approval_origin.value()) {
234 request->PermissionGranted(/*is_one_time=*/false);
236 request->RequestFinished();
240 // Don't re-add an existing request or one with a duplicate text request.
241 if (auto* existing_request = GetExistingRequest(request)) {
242 if (request == existing_request) {
246 // |request| is a duplicate. Add it to |duplicate_requests_| unless it's the
247 // same object as |existing_request| or an existing duplicate.
248 auto iter = FindDuplicateRequestList(existing_request);
249 if (iter == duplicate_requests_.end()) {
250 duplicate_requests_.push_back({request->GetWeakPtr()});
254 for (const auto& weak_request : (*iter)) {
255 if (weak_request && request == weak_request.get()) {
259 iter->push_back(request->GetWeakPtr());
264 if (IsRequestInProgress()) {
266 base::UserMetricsAction("PermissionBubbleRequestQueued"));
270 base::UserMetricsAction("PermissionBubbleIFrameRequestQueued"));
273 request->set_requesting_frame_id(source_frame->GetGlobalId());
275 QueueRequest(source_frame, request);
277 if (!IsRequestInProgress()) {
278 ScheduleDequeueRequestIfNeeded();
282 ReprioritizeCurrentRequestIfNeeded();
285 bool PermissionRequestManager::ReprioritizeCurrentRequestIfNeeded() {
286 if (!IsRequestInProgress() ||
287 IsCurrentRequestEmbeddedPermissionElementInitiated()) {
291 // Pop out all invalid requests in front of the queue.
292 while (!pending_permission_requests_.IsEmpty() &&
293 !ValidateRequest(pending_permission_requests_.Peek())) {
294 pending_permission_requests_.Pop();
297 if (pending_permission_requests_.IsEmpty()) {
301 auto current_request_fate = CurrentRequestFate::kKeepCurrent;
303 if (PermissionUtil::DoesPlatformSupportChip()) {
304 if (ShouldCurrentRequestUseQuietUI() &&
305 !ShouldShowQuietRequestAgainIfPreempted(
306 current_request_first_display_time_)) {
307 current_request_fate = CurrentRequestFate::kFinalize;
309 // Preempt current request if it is a quiet UI request.
310 if (ShouldCurrentRequestUseQuietUI()) {
311 current_request_fate = CurrentRequestFate::kPreempt;
313 // Here we also try to prioritise the requests. If there's a valid high
314 // priority request (high acceptance rate request) in the pending queue,
315 // preempt the current request. The valid high priority request, if
316 // there's any, is always the front of the queue.
317 if (!pending_permission_requests_.IsEmpty() &&
318 !PermissionUtil::IsLowPriorityPermissionRequest(
319 pending_permission_requests_.Peek())) {
320 current_request_fate = CurrentRequestFate::kPreempt;
324 } else if (ShouldCurrentRequestUseQuietUI()) {
325 // If we're displaying a quiet permission request, ignore it in favor of a
326 // new permission request.
327 current_request_fate = CurrentRequestFate::kFinalize;
330 if (current_request_fate == CurrentRequestFate::kKeepCurrent &&
331 !pending_permission_requests_.IsEmpty() &&
332 pending_permission_requests_.Peek()
333 ->IsEmbeddedPermissionElementInitiated()) {
334 current_request_fate = CurrentRequestFate::kPreempt;
337 switch (current_request_fate) {
338 case CurrentRequestFate::kKeepCurrent:
340 case CurrentRequestFate::kPreempt: {
341 CHECK(!pending_permission_requests_.IsEmpty());
342 auto* next_candidate = pending_permission_requests_.Peek();
344 // Consider a case of infinite loop here (eg: 2 low priority requests can
345 // preempt each other, causing a loop). We only preempt the current
346 // request if the next candidate has just been added to pending queue but
347 // not validated yet.
348 if (validated_requests_set_.find(next_candidate) !=
349 validated_requests_set_.end()) {
353 pending_permission_requests_.Pop();
354 PreemptAndRequeueCurrentRequest();
355 pending_permission_requests_.PushFront(next_candidate);
356 ScheduleDequeueRequestIfNeeded();
359 case CurrentRequestFate::kFinalize:
360 // FinalizeCurrentRequests() will call ScheduleDequeueRequestIfNeeded on
362 CurrentRequestsDecided(PermissionAction::IGNORED);
369 bool PermissionRequestManager::ValidateRequest(PermissionRequest* request,
370 bool should_finalize) {
371 const auto iter = request_sources_map_.find(request);
372 if (iter == request_sources_map_.end()) {
376 if (!iter->second.IsSourceFrameInactiveAndDisallowActivation()) {
380 if (should_finalize) {
381 request->Cancelled();
382 request->RequestFinished();
383 validated_requests_set_.erase(request);
384 request_sources_map_.erase(request);
390 void PermissionRequestManager::QueueRequest(
391 content::RenderFrameHost* source_frame,
392 PermissionRequest* request) {
393 pending_permission_requests_.Push(request);
394 request_sources_map_.emplace(
395 request, PermissionRequestSource({source_frame->GetGlobalId()}));
398 void PermissionRequestManager::PreemptAndRequeueCurrentRequest() {
399 ResetViewStateForCurrentRequest();
400 for (auto* current_request : requests_) {
401 pending_permission_requests_.PushFront(current_request);
404 // Because the order of the requests is changed, we should not preignore it.
405 preignore_timer_.AbandonAndStop();
410 void PermissionRequestManager::UpdateAnchor() {
412 // When the prompt's anchor is being updated, the prompt view can be
413 // recreated for the new browser. Because of that, ignore prompt callbacks
415 base::AutoReset<bool> ignore(&ignore_callbacks_from_prompt_, true);
416 if (!view_->UpdateAnchor())
421 void PermissionRequestManager::DidStartNavigation(
422 content::NavigationHandle* navigation_handle) {
423 for (Observer& observer : observer_list_)
424 observer.OnNavigation(navigation_handle);
426 if (!navigation_handle->IsInPrimaryMainFrame() ||
427 navigation_handle->IsSameDocument()) {
431 // Cooldown lasts until the next user-initiated navigation, which is defined
432 // as either a renderer-initiated navigation with a user gesture, or a
433 // browser-initiated navigation.
435 // TODO(crbug.com/952347): This check has to be done at DidStartNavigation
436 // time, the HasUserGesture state is lost by the time the navigation
438 if (!navigation_handle->IsRendererInitiated() ||
439 navigation_handle->HasUserGesture()) {
440 is_notification_prompt_cooldown_active_ = false;
444 void PermissionRequestManager::DidFinishNavigation(
445 content::NavigationHandle* navigation_handle) {
446 if (!navigation_handle->IsInPrimaryMainFrame() ||
447 !navigation_handle->HasCommitted() ||
448 navigation_handle->IsSameDocument()) {
452 if (!navigation_handle->IsErrorPage()) {
453 permissions::PermissionUmaUtil::
454 RecordTopLevelPermissionsHeaderPolicyOnNavigation(
455 navigation_handle->GetRenderFrameHost());
458 if (!base::FeatureList::IsEnabled(
459 features::kBackForwardCacheUnblockPermissionRequest)) {
460 if (!pending_permission_requests_.IsEmpty() || IsRequestInProgress()) {
461 // |pending_permission_requests_| and |requests_| will be deleted below,
462 // which might be a problem for back-forward cache — the page might be
463 // restored later, but the requests won't be. Disable bfcache here if we
464 // have any requests here to prevent this from happening.
465 content::BackForwardCache::DisableForRenderFrameHost(
466 navigation_handle->GetPreviousRenderFrameHostId(),
467 back_forward_cache::DisabledReason(
468 back_forward_cache::DisabledReasonId::kPermissionRequestManager));
474 void PermissionRequestManager::DocumentOnLoadCompletedInPrimaryMainFrame() {
475 // This is scheduled because while all calls to the browser have been
476 // issued at DOMContentLoaded, they may be bouncing around in scheduled
477 // callbacks finding the UI thread still. This makes sure we allow those
478 // scheduled calls to AddRequest to complete before we show the page-load
479 // permissions prompt.
480 ScheduleDequeueRequestIfNeeded();
483 void PermissionRequestManager::DOMContentLoaded(
484 content::RenderFrameHost* render_frame_host) {
485 ScheduleDequeueRequestIfNeeded();
488 void PermissionRequestManager::WebContentsDestroyed() {
489 // If the web contents has been destroyed, treat the prompt as cancelled.
492 // The WebContents is going away; be aggressively paranoid and delete
493 // ourselves lest other parts of the system attempt to add permission
494 // prompts or use us otherwise during the destruction.
495 web_contents()->RemoveUserData(UserDataKey());
496 // That was the equivalent of "delete this". This object is now destroyed;
497 // returning from this function is the only safe thing to do.
500 void PermissionRequestManager::OnVisibilityChanged(
501 content::Visibility visibility) {
502 bool tab_was_hidden = tab_is_hidden_;
503 tab_is_hidden_ = visibility == content::Visibility::HIDDEN;
504 if (tab_was_hidden == tab_is_hidden_)
506 NotifyTabVisibilityChanged(visibility);
507 if (tab_is_hidden_) {
509 switch (view_->GetTabSwitchingBehavior()) {
510 case PermissionPrompt::TabSwitchingBehavior::
511 kDestroyPromptButKeepRequestPending:
514 case PermissionPrompt::TabSwitchingBehavior::
515 kDestroyPromptAndIgnoreRequest:
516 CurrentRequestsDecided(PermissionAction::IGNORED);
518 case PermissionPrompt::TabSwitchingBehavior::kKeepPromptAlive:
526 if (!web_contents()->IsDocumentOnLoadCompletedInPrimaryMainFrame())
529 if (!IsRequestInProgress()) {
530 ScheduleDequeueRequestIfNeeded();
535 // We switched tabs away and back while a prompt was active.
536 DCHECK_EQ(view_->GetTabSwitchingBehavior(),
537 PermissionPrompt::TabSwitchingBehavior::kKeepPromptAlive);
538 } else if (current_request_ui_to_use_.has_value()) {
543 const std::vector<PermissionRequest*>& PermissionRequestManager::Requests() {
547 GURL PermissionRequestManager::GetRequestingOrigin() const {
548 CHECK(!requests_.empty());
549 GURL origin = requests_.front()->requesting_origin();
550 if (DCHECK_IS_ON()) {
551 for (auto* request : requests_)
552 DCHECK_EQ(origin, request->requesting_origin());
557 GURL PermissionRequestManager::GetEmbeddingOrigin() const {
558 if (embedding_origin_for_testing_.has_value()) {
559 return embedding_origin_for_testing_.value();
562 return PermissionUtil::GetLastCommittedOriginAsURL(
563 web_contents()->GetPrimaryMainFrame());
566 void PermissionRequestManager::Accept() {
567 if (ignore_callbacks_from_prompt_)
570 std::vector<PermissionRequest*>::iterator requests_iter;
571 for (requests_iter = requests_.begin(); requests_iter != requests_.end();
573 StorePermissionActionForUMA((*requests_iter)->requesting_origin(),
574 (*requests_iter)->request_type(),
575 PermissionAction::GRANTED);
576 PermissionGrantedIncludingDuplicates(*requests_iter,
577 /*is_one_time=*/false);
579 #if !BUILDFLAG(IS_ANDROID)
580 absl::optional<ContentSettingsType> content_settings_type =
581 RequestTypeToContentSettingsType((*requests_iter)->request_type());
582 if (content_settings_type.has_value()) {
583 PermissionUmaUtil::RecordPermissionRegrantForUnusedSites(
584 (*requests_iter)->requesting_origin(), content_settings_type.value(),
585 PermissionSourceUI::PROMPT, web_contents()->GetBrowserContext(),
591 NotifyRequestDecided(PermissionAction::GRANTED);
592 CurrentRequestsDecided(PermissionAction::GRANTED);
595 void PermissionRequestManager::AcceptThisTime() {
596 if (ignore_callbacks_from_prompt_)
599 std::vector<PermissionRequest*>::iterator requests_iter;
600 for (requests_iter = requests_.begin(); requests_iter != requests_.end();
602 StorePermissionActionForUMA((*requests_iter)->requesting_origin(),
603 (*requests_iter)->request_type(),
604 PermissionAction::GRANTED_ONCE);
605 PermissionGrantedIncludingDuplicates(*requests_iter,
606 /*is_one_time=*/true);
609 NotifyRequestDecided(PermissionAction::GRANTED_ONCE);
610 CurrentRequestsDecided(PermissionAction::GRANTED_ONCE);
613 void PermissionRequestManager::Deny() {
614 if (ignore_callbacks_from_prompt_)
618 // Suppress any further prompts in this WebContents, from any origin, until
619 // there is a user-initiated navigation. This stops users from getting
620 // trapped in request loops where the website automatically navigates
621 // cross-origin (e.g. to another subdomain) to be able to prompt again after
623 if (base::FeatureList::IsEnabled(
624 features::kBlockRepeatedNotificationPermissionPrompts) &&
625 base::Contains(requests_, ContentSettingsType::NOTIFICATIONS,
626 &PermissionRequest::GetContentSettingsType)) {
627 is_notification_prompt_cooldown_active_ = true;
630 std::vector<PermissionRequest*>::iterator requests_iter;
631 for (requests_iter = requests_.begin(); requests_iter != requests_.end();
633 StorePermissionActionForUMA((*requests_iter)->requesting_origin(),
634 (*requests_iter)->request_type(),
635 PermissionAction::DENIED);
636 PermissionDeniedIncludingDuplicates(*requests_iter);
639 NotifyRequestDecided(PermissionAction::DENIED);
640 CurrentRequestsDecided(PermissionAction::DENIED);
643 void PermissionRequestManager::Dismiss() {
644 if (ignore_callbacks_from_prompt_)
647 std::vector<PermissionRequest*>::iterator requests_iter;
648 for (requests_iter = requests_.begin(); requests_iter != requests_.end();
650 StorePermissionActionForUMA((*requests_iter)->requesting_origin(),
651 (*requests_iter)->request_type(),
652 PermissionAction::DISMISSED);
653 CancelledIncludingDuplicates(*requests_iter);
656 NotifyRequestDecided(PermissionAction::DISMISSED);
657 CurrentRequestsDecided(PermissionAction::DISMISSED);
660 void PermissionRequestManager::Ignore() {
661 if (ignore_callbacks_from_prompt_)
664 std::vector<PermissionRequest*>::iterator requests_iter;
665 for (requests_iter = requests_.begin(); requests_iter != requests_.end();
667 StorePermissionActionForUMA((*requests_iter)->requesting_origin(),
668 (*requests_iter)->request_type(),
669 PermissionAction::IGNORED);
670 CancelledIncludingDuplicates(*requests_iter);
673 NotifyRequestDecided(PermissionAction::IGNORED);
674 CurrentRequestsDecided(PermissionAction::IGNORED);
677 void PermissionRequestManager::FinalizeCurrentRequests() {
678 ResetViewStateForCurrentRequest();
679 std::vector<PermissionRequest*>::iterator requests_iter;
680 for (requests_iter = requests_.begin(); requests_iter != requests_.end();
682 RequestFinishedIncludingDuplicates(*requests_iter);
683 validated_requests_set_.erase(*requests_iter);
684 request_sources_map_.erase(*requests_iter);
687 // No need to execute the preignore logic as we canceling currently active
689 preignore_timer_.AbandonAndStop();
693 for (Observer& observer : observer_list_) {
694 observer.OnRequestsFinalized();
697 ScheduleDequeueRequestIfNeeded();
700 void PermissionRequestManager::OpenHelpCenterLink(const ui::Event& event) {
701 CHECK_GT(requests_.size(), 0u);
702 switch (requests_[0]->request_type()) {
703 case permissions::RequestType::kStorageAccess:
704 GetAssociatedWebContents()->OpenURL(content::OpenURLParams(
705 GURL(permissions::kEmbeddedContentHelpCenterURL), content::Referrer(),
706 ui::DispositionFromEventFlags(
707 event.flags(), WindowOpenDisposition::NEW_FOREGROUND_TAB),
708 ui::PAGE_TRANSITION_LINK, /*is_renderer_initiated=*/false));
711 NOTREACHED_NORETURN();
715 void PermissionRequestManager::PreIgnoreQuietPrompt() {
716 // Random number of seconds in the range [1.0, 2.0).
717 double delay_seconds = 1.0 + 1.0 * base::RandDouble();
718 preignore_timer_.Start(
719 FROM_HERE, base::Seconds(delay_seconds), this,
720 &PermissionRequestManager::PreIgnoreQuietPromptInternal);
723 void PermissionRequestManager::PreIgnoreQuietPromptInternal() {
724 DCHECK(!requests_.empty());
726 if (requests_.empty()) {
727 // If `requests_` was cleared then there is nothing preignore.
731 std::vector<PermissionRequest*>::iterator requests_iter;
732 for (requests_iter = requests_.begin(); requests_iter != requests_.end();
734 CancelledIncludingDuplicates(*requests_iter, /*is_final_decision=*/false);
737 blink::PermissionType permission;
738 bool success = PermissionUtil::GetPermissionType(
739 requests_[0]->GetContentSettingsType(), &permission);
742 PermissionUmaUtil::PermissionRequestPreignored(permission);
745 bool PermissionRequestManager::WasCurrentRequestAlreadyDisplayed() {
746 return current_request_already_displayed_;
749 void PermissionRequestManager::SetDismissOnTabClose() {
750 should_dismiss_current_request_ = true;
753 void PermissionRequestManager::SetPromptShown() {
754 did_show_prompt_ = true;
757 void PermissionRequestManager::SetDecisionTime() {
758 current_request_decision_time_ = base::Time::Now();
761 void PermissionRequestManager::SetManageClicked() {
762 set_manage_clicked();
765 void PermissionRequestManager::SetLearnMoreClicked() {
766 set_learn_more_clicked();
769 base::WeakPtr<PermissionPrompt::Delegate>
770 PermissionRequestManager::GetWeakPtr() {
771 return weak_factory_.GetWeakPtr();
774 content::WebContents* PermissionRequestManager::GetAssociatedWebContents() {
775 content::WebContents& web_contents = GetWebContents();
776 return &web_contents;
779 bool PermissionRequestManager::RecreateView() {
780 view_ = view_factory_.Run(web_contents(), this);
782 current_request_prompt_disposition_ =
783 PermissionPromptDisposition::NONE_VISIBLE;
784 if (ShouldDropCurrentRequestIfCannotShowQuietly()) {
785 CurrentRequestsDecided(PermissionAction::IGNORED);
787 NotifyPromptRecreateFailed();
791 current_request_prompt_disposition_ = view_->GetPromptDisposition();
795 absl::optional<gfx::Rect>
796 PermissionRequestManager::GetPromptBubbleViewBoundsInScreen() const {
797 return view_ ? view_->GetViewBoundsInScreen() : absl::nullopt;
800 PermissionRequestManager::PermissionRequestManager(
801 content::WebContents* web_contents)
802 : content::WebContentsObserver(web_contents),
803 content::WebContentsUserData<PermissionRequestManager>(*web_contents),
804 view_factory_(base::BindRepeating(&PermissionPrompt::Create)),
805 tab_is_hidden_(web_contents->GetVisibility() ==
806 content::Visibility::HIDDEN),
807 auto_response_for_test_(NONE),
808 permission_ui_selectors_(
809 PermissionsClient::Get()->CreatePermissionUiSelectors(
810 web_contents->GetBrowserContext())) {}
812 void PermissionRequestManager::DequeueRequestIfNeeded() {
813 // TODO(olesiamarukhno): Media requests block other media requests from
814 // pre-empting them. For example, when a camera request is pending and mic
815 // is requested, the camera request remains pending and mic request appears
816 // only after the camera request is resolved. This is caused by code in
817 // PermissionBubbleMediaAccessHandler and UserMediaClient. We probably don't
818 // need two permission queues, so resolve the duplication.
820 if (!web_contents()->IsDocumentOnLoadCompletedInPrimaryMainFrame() || view_ ||
821 IsRequestInProgress()) {
825 // Find first valid request.
826 while (!pending_permission_requests_.IsEmpty()) {
827 auto* next = pending_permission_requests_.Pop();
828 if (ValidateRequest(next)) {
829 validated_requests_set_.insert(next);
830 requests_.push_back(next);
835 if (requests_.empty()) {
839 // Find additional requests that can be grouped with the first one.
840 for (; !pending_permission_requests_.IsEmpty();
841 pending_permission_requests_.Pop()) {
842 auto* front = pending_permission_requests_.Peek();
843 if (!ValidateRequest(front))
846 validated_requests_set_.insert(front);
847 if (!ShouldGroupRequests(requests_.front(), front))
850 requests_.push_back(front);
853 // Mark the remaining pending requests as validated, so only the "new and has
854 // not been validated" requests added to the queue could have effect to
856 for (const auto& request_list : pending_permission_requests_) {
857 for (auto* request : request_list) {
858 if (ValidateRequest(request, /* should_finalize */ false)) {
859 validated_requests_set_.insert(request);
864 if (permission_ui_selectors_.empty()) {
865 current_request_ui_to_use_ =
866 UiDecision(UiDecision::UseNormalUi(), UiDecision::ShowNoWarning());
871 DCHECK(!current_request_ui_to_use_.has_value());
872 // Initialize the selector decisions vector.
873 DCHECK(selector_decisions_.empty());
874 selector_decisions_.resize(permission_ui_selectors_.size());
876 for (size_t selector_index = 0;
877 selector_index < permission_ui_selectors_.size(); ++selector_index) {
878 // Skip if we have already made a decision due to a higher priority
880 if (current_request_ui_to_use_.has_value() || !IsRequestInProgress()) {
884 if (permission_ui_selectors_[selector_index]->IsPermissionRequestSupported(
885 requests_.front()->request_type())) {
886 permission_ui_selectors_[selector_index]->SelectUiToUse(
888 base::BindOnce(&PermissionRequestManager::OnPermissionUiSelectorDone,
889 weak_factory_.GetWeakPtr(), selector_index));
893 OnPermissionUiSelectorDone(
895 PermissionUiSelector::Decision::UseNormalUiAndShowNoWarning());
899 void PermissionRequestManager::ScheduleDequeueRequestIfNeeded() {
900 base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
902 base::BindOnce(&PermissionRequestManager::DequeueRequestIfNeeded,
903 weak_factory_.GetWeakPtr()));
906 void PermissionRequestManager::ShowPrompt() {
907 // There is a race condition where the request might have been removed
908 // already so double-checking that there is a request in progress.
910 // There is no need to show a new prompt if the previous one still exists.
911 if (!IsRequestInProgress() || view_)
914 DCHECK(web_contents()->IsDocumentOnLoadCompletedInPrimaryMainFrame());
915 DCHECK(current_request_ui_to_use_);
917 if (tab_is_hidden_) {
918 NotifyPromptCreationFailedHiddenTab();
922 if (!ReprioritizeCurrentRequestIfNeeded())
928 if (!current_request_already_displayed_) {
929 PermissionUmaUtil::PermissionPromptShown(requests_);
931 auto quiet_ui_reason = ReasonForUsingQuietUi();
932 if (quiet_ui_reason) {
933 switch (*quiet_ui_reason) {
934 case QuietUiReason::kEnabledInPrefs:
935 case QuietUiReason::kTriggeredByCrowdDeny:
936 case QuietUiReason::kServicePredictedVeryUnlikelyGrant:
937 case QuietUiReason::kOnDevicePredictedVeryUnlikelyGrant:
939 case QuietUiReason::kTriggeredDueToAbusiveRequests:
940 LogWarningToConsole(kAbusiveNotificationRequestsEnforcementMessage);
942 case QuietUiReason::kTriggeredDueToAbusiveContent:
943 LogWarningToConsole(kAbusiveNotificationContentEnforcementMessage);
945 case QuietUiReason::kTriggeredDueToDisruptiveBehavior:
947 kDisruptiveNotificationBehaviorEnforcementMessage);
950 base::RecordAction(base::UserMetricsAction(
951 "Notifications.Quiet.PermissionRequestShown"));
954 #if !BUILDFLAG(IS_ANDROID)
955 PermissionsClient::Get()->TriggerPromptHatsSurveyIfEnabled(
956 web_contents()->GetBrowserContext(), requests_[0]->request_type(),
957 absl::nullopt, DetermineCurrentRequestUIDisposition(),
958 DetermineCurrentRequestUIDispositionReasonForUMA(),
959 requests_[0]->GetGestureType(), absl::nullopt, false,
960 web_contents()->GetLastCommittedURL(),
961 hats_shown_callback_.has_value()
962 ? std::move(hats_shown_callback_.value())
963 : base::DoNothing());
965 hats_shown_callback_.reset();
968 current_request_already_displayed_ = true;
969 current_request_first_display_time_ = base::Time::Now();
973 // If in testing mode, automatically respond to the bubble that was shown.
974 if (auto_response_for_test_ != NONE) {
975 DoAutoResponseForTesting();
979 void PermissionRequestManager::SetHatsShownCallback(
980 base::OnceCallback<void()> callback) {
981 hats_shown_callback_ = std::move(callback);
984 void PermissionRequestManager::DeletePrompt() {
987 base::AutoReset<bool> deleting(&ignore_callbacks_from_prompt_, true);
990 NotifyPromptRemoved();
993 void PermissionRequestManager::ResetViewStateForCurrentRequest() {
994 for (const auto& selector : permission_ui_selectors_)
997 current_request_already_displayed_ = false;
998 current_request_first_display_time_ = base::Time();
999 current_request_decision_time_ = base::Time();
1000 current_request_prompt_disposition_.reset();
1001 prediction_grant_likelihood_.reset();
1002 current_request_ui_to_use_.reset();
1003 was_decision_held_back_.reset();
1004 selector_decisions_.clear();
1005 should_dismiss_current_request_ = false;
1006 did_show_prompt_ = false;
1007 did_click_manage_ = false;
1008 did_click_learn_more_ = false;
1009 hats_shown_callback_.reset();
1014 void PermissionRequestManager::CurrentRequestsDecided(
1015 PermissionAction permission_action) {
1016 DCHECK(IsRequestInProgress());
1017 base::TimeDelta time_to_decision;
1018 if (!current_request_first_display_time_.is_null() &&
1019 permission_action != PermissionAction::IGNORED) {
1020 if (current_request_decision_time_.is_null()) {
1021 current_request_decision_time_ = base::Time::Now();
1024 current_request_decision_time_ - current_request_first_display_time_;
1027 if (time_to_decision_for_test_.has_value()) {
1028 time_to_decision = time_to_decision_for_test_.value();
1029 time_to_decision_for_test_.reset();
1032 content::BrowserContext* browser_context =
1033 web_contents()->GetBrowserContext();
1034 PermissionUmaUtil::PermissionPromptResolved(
1035 requests_, web_contents(), permission_action, time_to_decision,
1036 DetermineCurrentRequestUIDisposition(),
1037 DetermineCurrentRequestUIDispositionReasonForUMA(),
1038 prediction_grant_likelihood_, was_decision_held_back_,
1039 permission_action == PermissionAction::IGNORED
1040 ? absl::make_optional(
1041 PermissionsClient::Get()->DetermineIgnoreReason(web_contents()))
1043 did_show_prompt_, did_click_manage_, did_click_learn_more_);
1045 PermissionDecisionAutoBlocker* autoblocker =
1046 PermissionsClient::Get()->GetPermissionDecisionAutoBlocker(
1049 absl::optional<QuietUiReason> quiet_ui_reason;
1050 if (ShouldCurrentRequestUseQuietUI())
1051 quiet_ui_reason = ReasonForUsingQuietUi();
1053 for (PermissionRequest* request : requests_) {
1054 // TODO(timloh): We only support dismiss and ignore embargo for
1055 // permissions which use PermissionRequestImpl as the other subclasses
1056 // don't support GetContentSettingsType.
1057 if (request->GetContentSettingsType() == ContentSettingsType::DEFAULT)
1060 auto time_since_shown =
1061 current_request_first_display_time_.is_null()
1062 ? base::TimeDelta::Max()
1063 : base::Time::Now() - current_request_first_display_time_;
1064 PermissionsClient::Get()->OnPromptResolved(
1065 request->request_type(), permission_action,
1066 request->requesting_origin(), DetermineCurrentRequestUIDisposition(),
1067 DetermineCurrentRequestUIDispositionReasonForUMA(),
1068 request->GetGestureType(), quiet_ui_reason, time_since_shown,
1071 PermissionEmbargoStatus embargo_status =
1072 PermissionEmbargoStatus::NOT_EMBARGOED;
1073 if (permission_action == PermissionAction::DISMISSED) {
1074 if (autoblocker->RecordDismissAndEmbargo(
1075 request->requesting_origin(), request->GetContentSettingsType(),
1076 ShouldCurrentRequestUseQuietUI())) {
1077 embargo_status = PermissionEmbargoStatus::REPEATED_DISMISSALS;
1079 } else if (permission_action == PermissionAction::IGNORED) {
1080 if (autoblocker->RecordIgnoreAndEmbargo(
1081 request->requesting_origin(), request->GetContentSettingsType(),
1082 ShouldCurrentRequestUseQuietUI())) {
1083 embargo_status = PermissionEmbargoStatus::REPEATED_IGNORES;
1085 } else if (permission_action == PermissionAction::GRANTED_ONCE) {
1086 autoblocker->RemoveEmbargoAndResetCounts(
1087 request->requesting_origin(), request->GetContentSettingsType());
1089 PermissionUmaUtil::RecordEmbargoStatus(embargo_status);
1092 // IGNORED is not a decision on the prompt and it occurs because of external
1093 // factors (e.g. tab switching). Therefore |ShouldFinalizeRequestAfterDecided|
1094 // does not take effect when the action is IGNORED.
1095 if (ShouldFinalizeRequestAfterDecided(permission_action)) {
1096 FinalizeCurrentRequests();
1100 void PermissionRequestManager::CleanUpRequests() {
1101 // No need to execute the preignore logic as we canceling currently active
1103 preignore_timer_.AbandonAndStop();
1105 for (; !pending_permission_requests_.IsEmpty();
1106 pending_permission_requests_.Pop()) {
1107 auto* pending_request = pending_permission_requests_.Peek();
1108 CancelledIncludingDuplicates(pending_request);
1109 RequestFinishedIncludingDuplicates(pending_request);
1110 validated_requests_set_.erase(pending_request);
1111 request_sources_map_.erase(pending_request);
1114 if (IsRequestInProgress()) {
1115 std::vector<PermissionRequest*>::iterator requests_iter;
1116 for (requests_iter = requests_.begin(); requests_iter != requests_.end();
1118 CancelledIncludingDuplicates(*requests_iter);
1121 CurrentRequestsDecided(should_dismiss_current_request_
1122 ? PermissionAction::DISMISSED
1123 : PermissionAction::IGNORED);
1124 should_dismiss_current_request_ = false;
1128 PermissionRequest* PermissionRequestManager::GetExistingRequest(
1129 PermissionRequest* request) const {
1130 for (PermissionRequest* existing_request : requests_) {
1131 if (request->IsDuplicateOf(existing_request)) {
1132 return existing_request;
1135 return pending_permission_requests_.FindDuplicate(request);
1138 PermissionRequestManager::WeakPermissionRequestList::iterator
1139 PermissionRequestManager::FindDuplicateRequestList(PermissionRequest* request) {
1140 for (auto request_list = duplicate_requests_.begin();
1141 request_list != duplicate_requests_.end(); ++request_list) {
1142 for (auto iter = request_list->begin(); iter != request_list->end();) {
1143 // Remove any requests that have been destroyed.
1144 const auto& weak_request = (*iter);
1145 if (!weak_request) {
1146 iter = request_list->erase(iter);
1150 // The first valid request in the list will indicate whether all other
1151 // members are duplicate or not.
1152 if (weak_request->IsDuplicateOf(request)) {
1153 return request_list;
1160 return duplicate_requests_.end();
1163 PermissionRequestManager::WeakPermissionRequestList::iterator
1164 PermissionRequestManager::VisitDuplicateRequests(
1165 DuplicateRequestVisitor visitor,
1166 PermissionRequest* request) {
1167 auto request_list = FindDuplicateRequestList(request);
1168 if (request_list == duplicate_requests_.end()) {
1169 return request_list;
1172 for (auto iter = request_list->begin(); iter != request_list->end();) {
1173 if (auto& weak_request = (*iter)) {
1174 visitor.Run(weak_request);
1177 // Remove any requests that have been destroyed.
1178 iter = request_list->erase(iter);
1182 return request_list;
1185 void PermissionRequestManager::PermissionGrantedIncludingDuplicates(
1186 PermissionRequest* request,
1188 DCHECK_EQ(1ul, base::ranges::count(requests_, request) +
1189 pending_permission_requests_.Count(request))
1190 << "Only requests in [pending_permission_]requests_ can have duplicates";
1191 request->PermissionGranted(is_one_time);
1192 VisitDuplicateRequests(
1193 base::BindRepeating(
1194 [](bool is_one_time,
1195 const base::WeakPtr<PermissionRequest>& weak_request) {
1196 weak_request->PermissionGranted(is_one_time);
1202 void PermissionRequestManager::PermissionDeniedIncludingDuplicates(
1203 PermissionRequest* request) {
1204 DCHECK_EQ(1ul, base::ranges::count(requests_, request) +
1205 pending_permission_requests_.Count(request))
1206 << "Only requests in [pending_permission_]requests_ can have duplicates";
1207 request->PermissionDenied();
1208 VisitDuplicateRequests(
1209 base::BindRepeating(
1210 [](const base::WeakPtr<PermissionRequest>& weak_request) {
1211 weak_request->PermissionDenied();
1216 void PermissionRequestManager::CancelledIncludingDuplicates(
1217 PermissionRequest* request,
1218 bool is_final_decision) {
1219 DCHECK_EQ(1ul, base::ranges::count(requests_, request) +
1220 pending_permission_requests_.Count(request))
1221 << "Only requests in [pending_permission_]requests_ can have duplicates";
1222 request->Cancelled(is_final_decision);
1223 VisitDuplicateRequests(
1224 base::BindRepeating(
1226 const base::WeakPtr<PermissionRequest>& weak_request) {
1227 weak_request->Cancelled(is_final);
1233 void PermissionRequestManager::RequestFinishedIncludingDuplicates(
1234 PermissionRequest* request) {
1235 DCHECK_EQ(1ul, base::ranges::count(requests_, request) +
1236 pending_permission_requests_.Count(request))
1237 << "Only requests in [pending_permission_]requests_ can have duplicates";
1238 auto duplicate_list = VisitDuplicateRequests(
1239 base::BindRepeating(
1240 [](const base::WeakPtr<PermissionRequest>& weak_request) {
1241 weak_request->RequestFinished();
1245 // Note: beyond this point, |request| has probably been deleted, any
1246 // dereference of |request| must be done prior this point.
1247 request->RequestFinished();
1249 // Additionally, we can now remove the duplicates.
1250 if (duplicate_list != duplicate_requests_.end()) {
1251 duplicate_requests_.erase(duplicate_list);
1255 void PermissionRequestManager::AddObserver(Observer* observer) {
1256 observer_list_.AddObserver(observer);
1259 void PermissionRequestManager::RemoveObserver(Observer* observer) {
1260 observer_list_.RemoveObserver(observer);
1263 bool PermissionRequestManager::ShouldCurrentRequestUseQuietUI() const {
1264 // ContentSettingImageModel might call into this method if the user switches
1265 // between tabs while the |notification_permission_ui_selectors_| are
1267 return ReasonForUsingQuietUi() != absl::nullopt;
1270 absl::optional<PermissionRequestManager::QuietUiReason>
1271 PermissionRequestManager::ReasonForUsingQuietUi() const {
1272 if (!IsRequestInProgress() || !current_request_ui_to_use_ ||
1273 !current_request_ui_to_use_->quiet_ui_reason)
1274 return absl::nullopt;
1276 return *(current_request_ui_to_use_->quiet_ui_reason);
1279 bool PermissionRequestManager::IsRequestInProgress() const {
1280 return !requests_.empty();
1283 bool PermissionRequestManager::CanRestorePrompt() {
1284 #if BUILDFLAG(IS_ANDROID)
1287 return IsRequestInProgress() &&
1288 current_request_prompt_disposition_.has_value() && !view_;
1292 void PermissionRequestManager::RestorePrompt() {
1293 if (CanRestorePrompt())
1297 bool PermissionRequestManager::ShouldDropCurrentRequestIfCannotShowQuietly()
1299 absl::optional<QuietUiReason> quiet_ui_reason = ReasonForUsingQuietUi();
1300 if (quiet_ui_reason.has_value()) {
1301 switch (quiet_ui_reason.value()) {
1302 case QuietUiReason::kEnabledInPrefs:
1303 case QuietUiReason::kServicePredictedVeryUnlikelyGrant:
1304 case QuietUiReason::kOnDevicePredictedVeryUnlikelyGrant:
1305 case QuietUiReason::kTriggeredByCrowdDeny:
1307 case QuietUiReason::kTriggeredDueToAbusiveRequests:
1308 case QuietUiReason::kTriggeredDueToAbusiveContent:
1309 case QuietUiReason::kTriggeredDueToDisruptiveBehavior:
1317 void PermissionRequestManager::NotifyTabVisibilityChanged(
1318 content::Visibility visibility) {
1319 for (Observer& observer : observer_list_) {
1320 observer.OnTabVisibilityChanged(visibility);
1324 void PermissionRequestManager::NotifyPromptAdded() {
1325 for (Observer& observer : observer_list_)
1326 observer.OnPromptAdded();
1329 void PermissionRequestManager::NotifyPromptRemoved() {
1330 for (Observer& observer : observer_list_) {
1331 observer.OnPromptRemoved();
1335 void PermissionRequestManager::NotifyPromptRecreateFailed() {
1336 for (Observer& observer : observer_list_)
1337 observer.OnPromptRecreateViewFailed();
1340 void PermissionRequestManager::NotifyPromptCreationFailedHiddenTab() {
1341 for (Observer& observer : observer_list_)
1342 observer.OnPromptCreationFailedHiddenTab();
1345 void PermissionRequestManager::NotifyRequestDecided(
1346 permissions::PermissionAction permission_action) {
1347 for (Observer& observer : observer_list_)
1348 observer.OnRequestDecided(permission_action);
1351 void PermissionRequestManager::StorePermissionActionForUMA(
1353 RequestType request_type,
1354 PermissionAction permission_action) {
1355 absl::optional<ContentSettingsType> content_settings_type =
1356 RequestTypeToContentSettingsType(request_type);
1357 if (content_settings_type.has_value()) {
1358 PermissionsClient::Get()
1359 ->GetOriginKeyedPermissionActionService(
1360 web_contents()->GetBrowserContext())
1361 ->RecordAction(PermissionUtil::GetLastCommittedOriginAsURL(
1362 web_contents()->GetPrimaryMainFrame()),
1363 content_settings_type.value(), permission_action);
1367 void PermissionRequestManager::OnPermissionUiSelectorDone(
1368 size_t selector_index,
1369 const UiDecision& decision) {
1370 if (decision.warning_reason) {
1371 switch (*(decision.warning_reason)) {
1372 case WarningReason::kAbusiveRequests:
1373 LogWarningToConsole(kAbusiveNotificationRequestsWarningMessage);
1375 case WarningReason::kAbusiveContent:
1376 LogWarningToConsole(kAbusiveNotificationContentWarningMessage);
1378 case WarningReason::kDisruptiveBehavior:
1383 // We have already made a decision because of a higher priority selector
1384 // therefore this selector's decision can be discarded.
1385 if (current_request_ui_to_use_.has_value())
1388 CHECK_LT(selector_index, selector_decisions_.size());
1389 selector_decisions_[selector_index] = decision;
1391 size_t decision_index = 0;
1392 while (decision_index < selector_decisions_.size() &&
1393 selector_decisions_[decision_index].has_value()) {
1394 const UiDecision& current_decision =
1395 selector_decisions_[decision_index].value();
1397 if (!prediction_grant_likelihood_.has_value()) {
1398 prediction_grant_likelihood_ = permission_ui_selectors_[decision_index]
1399 ->PredictedGrantLikelihoodForUKM();
1402 if (!was_decision_held_back_.has_value()) {
1403 was_decision_held_back_ = permission_ui_selectors_[decision_index]
1404 ->WasSelectorDecisionHeldback();
1407 if (current_decision.quiet_ui_reason.has_value()) {
1408 current_request_ui_to_use_ = current_decision;
1415 // All decisions have been considered and none was conclusive.
1416 if (decision_index == selector_decisions_.size() &&
1417 !current_request_ui_to_use_.has_value()) {
1418 current_request_ui_to_use_ = UiDecision::UseNormalUiAndShowNoWarning();
1421 if (current_request_ui_to_use_.has_value()) {
1426 PermissionPromptDisposition
1427 PermissionRequestManager::DetermineCurrentRequestUIDisposition() {
1428 if (current_request_prompt_disposition_.has_value())
1429 return current_request_prompt_disposition_.value();
1430 return PermissionPromptDisposition::NONE_VISIBLE;
1433 PermissionPromptDispositionReason
1434 PermissionRequestManager::DetermineCurrentRequestUIDispositionReasonForUMA() {
1435 auto quiet_ui_reason = ReasonForUsingQuietUi();
1436 if (!quiet_ui_reason)
1437 return PermissionPromptDispositionReason::DEFAULT_FALLBACK;
1438 switch (*quiet_ui_reason) {
1439 case QuietUiReason::kEnabledInPrefs:
1440 return PermissionPromptDispositionReason::USER_PREFERENCE_IN_SETTINGS;
1441 case QuietUiReason::kTriggeredByCrowdDeny:
1442 case QuietUiReason::kTriggeredDueToAbusiveRequests:
1443 case QuietUiReason::kTriggeredDueToAbusiveContent:
1444 case QuietUiReason::kTriggeredDueToDisruptiveBehavior:
1445 return PermissionPromptDispositionReason::SAFE_BROWSING_VERDICT;
1446 case QuietUiReason::kServicePredictedVeryUnlikelyGrant:
1447 return PermissionPromptDispositionReason::PREDICTION_SERVICE;
1448 case QuietUiReason::kOnDevicePredictedVeryUnlikelyGrant:
1449 return PermissionPromptDispositionReason::ON_DEVICE_PREDICTION_MODEL;
1453 void PermissionRequestManager::LogWarningToConsole(const char* message) {
1454 web_contents()->GetPrimaryMainFrame()->AddMessageToConsole(
1455 blink::mojom::ConsoleMessageLevel::kWarning, message);
1458 void PermissionRequestManager::DoAutoResponseForTesting() {
1459 switch (auto_response_for_test_) {
1477 bool PermissionRequestManager::
1478 IsCurrentRequestEmbeddedPermissionElementInitiated() const {
1479 return IsRequestInProgress() &&
1480 requests_[0]->IsEmbeddedPermissionElementInitiated();
1483 bool PermissionRequestManager::ShouldFinalizeRequestAfterDecided(
1484 PermissionAction action) const {
1485 // If the action is IGNORED, it is not coming from the prompt itself but
1486 // rather from external circumstance (like tab switching) and therefore
1487 // |view_->ShouldFinalizeRequestAfterDecided| is not queried.
1489 // If there is an autoresponse set, or there is no |view_|, finalize the
1490 // request since there won't be a separate |FinalizeCurrentRequests()| call.
1491 if (action == PermissionAction::IGNORED || auto_response_for_test_ != NONE ||
1496 return view_->ShouldFinalizeRequestAfterDecided();
1499 WEB_CONTENTS_USER_DATA_KEY_IMPL(PermissionRequestManager);
1501 } // namespace permissions