Commit d73a6b5b authored by Olesia Marukhno's avatar Olesia Marukhno Committed by Commit Bot

Add handling of pending requests when switching to fullscreen

When there is a pending request and chip UI is used, after switching to
fullscreen mode bubble UI should be used if pending request is new (chip
haven't been collapsed yet). This prevents case when permission was
requested and shorty after that user switches to fullscreen mode and
cannot see pending request anymore.

When switching from fullscreen mode, if request should be shown with
chip UI, switch back to it with bubble opened. This provides visual
consistency and in regular mode with chip UI bubble is easily dismissable.

Bug: 1148332
Change-Id: I52886d95842db45ec72997127f25010585d97670
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2540527
Commit-Queue: Olesia Marukhno <olesiamarukhno@google.com>
Reviewed-by: default avatarBalazs Engedy <engedy@chromium.org>
Reviewed-by: default avatarBret Sepulveda <bsep@chromium.org>
Cr-Commit-Position: refs/heads/master@{#831042}
parent 35047f4e
...@@ -136,8 +136,11 @@ void PermissionChip::Show(permissions::PermissionPrompt::Delegate* delegate) { ...@@ -136,8 +136,11 @@ void PermissionChip::Show(permissions::PermissionPrompt::Delegate* delegate) {
SetVisible(true); SetVisible(true);
// TODO(olesiamarukhno): Add tests for animation logic. // TODO(olesiamarukhno): Add tests for animation logic.
animation_->Reset(); animation_->Reset();
if (!delegate_->WasCurrentRequestAlreadyDisplayed()) is_collapsed_ = true;
if (!delegate_->WasCurrentRequestAlreadyDisplayed()) {
animation_->Show(); animation_->Show();
is_collapsed_ = false;
}
requested_time_ = base::TimeTicks::Now(); requested_time_ = base::TimeTicks::Now();
PreferredSizeChanged(); PreferredSizeChanged();
} }
...@@ -188,13 +191,10 @@ void PermissionChip::OnWidgetDestroying(views::Widget* widget) { ...@@ -188,13 +191,10 @@ void PermissionChip::OnWidgetDestroying(views::Widget* widget) {
widget->RemoveObserver(this); widget->RemoveObserver(this);
prompt_bubble_ = nullptr; prompt_bubble_ = nullptr;
animation_->Hide(); animation_->Hide();
is_collapsed_ = true;
} }
bool PermissionChip::IsBubbleShowing() const { void PermissionChip::OpenBubble() {
return prompt_bubble_ != nullptr;
}
void PermissionChip::ChipButtonPressed() {
// The prompt bubble is either not opened yet or already closed on // The prompt bubble is either not opened yet or already closed on
// deactivation. // deactivation.
DCHECK(!prompt_bubble_); DCHECK(!prompt_bubble_);
...@@ -203,6 +203,14 @@ void PermissionChip::ChipButtonPressed() { ...@@ -203,6 +203,14 @@ void PermissionChip::ChipButtonPressed() {
browser_, delegate_, requested_time_, PermissionPromptStyle::kChip); browser_, delegate_, requested_time_, PermissionPromptStyle::kChip);
prompt_bubble_->Show(); prompt_bubble_->Show();
prompt_bubble_->GetWidget()->AddObserver(this); prompt_bubble_->GetWidget()->AddObserver(this);
}
bool PermissionChip::IsBubbleShowing() const {
return prompt_bubble_ != nullptr;
}
void PermissionChip::ChipButtonPressed() {
OpenBubble();
// Restart the timer after user clicks on the chip to open the bubble. // Restart the timer after user clicks on the chip to open the bubble.
StartCollapseTimer(); StartCollapseTimer();
if (!already_recorded_interaction_) { if (!already_recorded_interaction_) {
...@@ -217,6 +225,7 @@ void PermissionChip::Collapse() { ...@@ -217,6 +225,7 @@ void PermissionChip::Collapse() {
StartCollapseTimer(); StartCollapseTimer();
} else { } else {
animation_->Hide(); animation_->Hide();
is_collapsed_ = true;
} }
} }
......
...@@ -41,8 +41,10 @@ class PermissionChip : public views::View, ...@@ -41,8 +41,10 @@ class PermissionChip : public views::View,
void Show(permissions::PermissionPrompt::Delegate* delegate); void Show(permissions::PermissionPrompt::Delegate* delegate);
void Hide(); void Hide();
void OpenBubble();
views::Button* button() { return chip_button_; } views::Button* button() { return chip_button_; }
bool is_collapsed() { return is_collapsed_; }
// views::AnimationDelegateViews: // views::AnimationDelegateViews:
void AnimationEnded(const gfx::Animation* animation) override; void AnimationEnded(const gfx::Animation* animation) override;
...@@ -90,6 +92,10 @@ class PermissionChip : public views::View, ...@@ -90,6 +92,10 @@ class PermissionChip : public views::View,
// If uma metric was already recorded on the button click. // If uma metric was already recorded on the button click.
bool already_recorded_interaction_ = false; bool already_recorded_interaction_ = false;
// If chip is collapsed. In the collapsed state, only an icon is visible,
// without text.
bool is_collapsed_ = false;
}; };
#endif // CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_PERMISSION_CHIP_H_ #endif // CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_PERMISSION_CHIP_H_
...@@ -96,16 +96,7 @@ PermissionPromptBubbleView::PermissionPromptBubbleView( ...@@ -96,16 +96,7 @@ PermissionPromptBubbleView::PermissionPromptBubbleView(
SetCancelCallback(base::BindOnce(&PermissionPromptBubbleView::DenyPermission, SetCancelCallback(base::BindOnce(&PermissionPromptBubbleView::DenyPermission,
base::Unretained(this))); base::Unretained(this)));
// If bubble hanging off the padlock icon, with no chip showing, it shouldn't SetPromptStyle(prompt_style);
// close on deactivate and it should stick until user makes a decision.
// Otherwise, the chip is indicating the pending permission request and so the
// bubble can be opened and closed repeatedly.
if (prompt_style == PermissionPromptStyle::kBubbleOnly) {
set_close_on_deactivate(false);
DialogDelegate::SetCloseCallback(
base::BindOnce(&PermissionPromptBubbleView::ClosingPermission,
base::Unretained(this)));
}
SetLayoutManager(std::make_unique<views::BoxLayout>( SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical, gfx::Insets(), views::BoxLayout::Orientation::kVertical, gfx::Insets(),
...@@ -217,6 +208,23 @@ void PermissionPromptBubbleView::UpdateAnchorPosition() { ...@@ -217,6 +208,23 @@ void PermissionPromptBubbleView::UpdateAnchorPosition() {
SetArrow(configuration.bubble_arrow); SetArrow(configuration.bubble_arrow);
} }
void PermissionPromptBubbleView::SetPromptStyle(
PermissionPromptStyle prompt_style) {
// If bubble hanging off the padlock icon, with no chip showing, it shouldn't
// close on deactivate and it should stick until user makes a decision.
// Otherwise, the chip is indicating the pending permission request and so the
// bubble can be opened and closed repeatedly.
if (prompt_style == PermissionPromptStyle::kBubbleOnly) {
set_close_on_deactivate(false);
DialogDelegate::SetCloseCallback(
base::BindOnce(&PermissionPromptBubbleView::ClosingPermission,
base::Unretained(this)));
} else {
set_close_on_deactivate(true);
DialogDelegate::SetCloseCallback(base::OnceClosure());
}
}
void PermissionPromptBubbleView::AddedToWidget() { void PermissionPromptBubbleView::AddedToWidget() {
if (name_or_origin_.is_origin) { if (name_or_origin_.is_origin) {
// There is a risk of URL spoofing from origins that are too wide to fit in // There is a risk of URL spoofing from origins that are too wide to fit in
......
...@@ -29,6 +29,8 @@ class PermissionPromptBubbleView : public views::BubbleDialogDelegateView { ...@@ -29,6 +29,8 @@ class PermissionPromptBubbleView : public views::BubbleDialogDelegateView {
// bubble_anchor_util::GetPageInfoAnchorConfiguration. // bubble_anchor_util::GetPageInfoAnchorConfiguration.
void UpdateAnchorPosition(); void UpdateAnchorPosition();
void SetPromptStyle(PermissionPromptStyle prompt_style);
// views::BubbleDialogDelegateView: // views::BubbleDialogDelegateView:
void AddedToWidget() override; void AddedToWidget() override;
bool ShouldShowCloseButton() const override; bool ShouldShowCloseButton() const override;
......
...@@ -47,16 +47,8 @@ PermissionPromptImpl::PermissionPromptImpl(Browser* browser, ...@@ -47,16 +47,8 @@ PermissionPromptImpl::PermissionPromptImpl(Browser* browser,
content_settings::UpdateLocationBarUiForWebContents(web_contents_); content_settings::UpdateLocationBarUiForWebContents(web_contents_);
} else { } else {
LocationBarView* lbv = GetLocationBarView(); LocationBarView* lbv = GetLocationBarView();
std::vector<permissions::PermissionRequest*> requests = if (lbv && lbv->IsDrawn() && ShouldCurrentRequestUseChipUI()) {
delegate->Requests(); ShowChipUI();
const bool should_use_chip_ui = std::all_of(
requests.begin(), requests.end(),
[](auto* request) { return request->GetChipText().has_value(); });
if (base::FeatureList::IsEnabled(permissions::features::kPermissionChip) &&
lbv && lbv->IsDrawn() && should_use_chip_ui) {
permission_chip_ = lbv->permission_chip();
permission_chip_->Show(delegate);
prompt_style_ = PermissionPromptStyle::kChip;
} else { } else {
ShowBubble(); ShowBubble();
} }
...@@ -70,25 +62,60 @@ void PermissionPromptImpl::OnWidgetClosing(views::Widget* widget) { ...@@ -70,25 +62,60 @@ void PermissionPromptImpl::OnWidgetClosing(views::Widget* widget) {
} }
PermissionPromptImpl::~PermissionPromptImpl() { PermissionPromptImpl::~PermissionPromptImpl() {
if (prompt_bubble_) switch (prompt_style_) {
prompt_bubble_->GetWidget()->Close(); case PermissionPromptStyle::kBubbleOnly:
DCHECK(!permission_chip_);
if (prompt_style_ == PermissionPromptStyle::kQuiet) { if (prompt_bubble_)
// Hides the quiet prompt. prompt_bubble_->GetWidget()->Close();
content_settings::UpdateLocationBarUiForWebContents(web_contents_); break;
case PermissionPromptStyle::kChip:
DCHECK(!prompt_bubble_);
DCHECK(permission_chip_);
permission_chip_->Hide();
permission_chip_ = nullptr;
break;
case PermissionPromptStyle::kQuiet:
DCHECK(!prompt_bubble_);
DCHECK(!permission_chip_);
content_settings::UpdateLocationBarUiForWebContents(web_contents_);
break;
} }
if (prompt_style_ == PermissionPromptStyle::kChip && permission_chip_) {
permission_chip_->Hide();
}
CHECK(!IsInObserverList()); CHECK(!IsInObserverList());
} }
void PermissionPromptImpl::UpdateAnchorPosition() { void PermissionPromptImpl::UpdateAnchorPosition() {
// TODO(olesiamarukhno): Figure out if we need to switch UI styles (chip to LocationBarView* lbv = GetLocationBarView();
// bubble and vice versa) here. const bool is_location_bar_drawn = lbv && lbv->IsDrawn();
if (prompt_bubble_) switch (prompt_style_) {
prompt_bubble_->UpdateAnchorPosition(); case PermissionPromptStyle::kBubbleOnly:
DCHECK(prompt_bubble_);
DCHECK(!permission_chip_);
if (ShouldCurrentRequestUseChipUI() && 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();
permission_chip_->OpenBubble();
} else {
prompt_bubble_->UpdateAnchorPosition();
}
break;
case PermissionPromptStyle::kChip:
DCHECK(!prompt_bubble_);
DCHECK(permission_chip_);
// If there is fresh pending request shown as chip UI and location bar
// isn't visible anymore, show bubble UI instead.
if (!permission_chip_->is_collapsed() && !is_location_bar_drawn) {
permission_chip_->Hide();
permission_chip_ = nullptr;
ShowBubble();
}
break;
case PermissionPromptStyle::kQuiet:
break;
}
} }
LocationBarView* PermissionPromptImpl::GetLocationBarView() { LocationBarView* PermissionPromptImpl::GetLocationBarView() {
...@@ -96,6 +123,15 @@ LocationBarView* PermissionPromptImpl::GetLocationBarView() { ...@@ -96,6 +123,15 @@ LocationBarView* PermissionPromptImpl::GetLocationBarView() {
return browser_view ? browser_view->GetLocationBarView() : nullptr; return browser_view ? browser_view->GetLocationBarView() : nullptr;
} }
void PermissionPromptImpl::ShowChipUI() {
LocationBarView* lbv = GetLocationBarView();
DCHECK(lbv);
permission_chip_ = lbv->permission_chip();
permission_chip_->Show(delegate_);
prompt_style_ = PermissionPromptStyle::kChip;
}
void PermissionPromptImpl::ShowBubble() { void PermissionPromptImpl::ShowBubble() {
prompt_style_ = PermissionPromptStyle::kBubbleOnly; prompt_style_ = PermissionPromptStyle::kBubbleOnly;
prompt_bubble_ = new PermissionPromptBubbleView( prompt_bubble_ = new PermissionPromptBubbleView(
...@@ -104,6 +140,16 @@ void PermissionPromptImpl::ShowBubble() { ...@@ -104,6 +140,16 @@ void PermissionPromptImpl::ShowBubble() {
prompt_bubble_->GetWidget()->AddObserver(this); 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();
});
}
permissions::PermissionPrompt::TabSwitchingBehavior permissions::PermissionPrompt::TabSwitchingBehavior
PermissionPromptImpl::GetTabSwitchingBehavior() { PermissionPromptImpl::GetTabSwitchingBehavior() {
return permissions::PermissionPrompt::TabSwitchingBehavior:: return permissions::PermissionPrompt::TabSwitchingBehavior::
......
...@@ -50,6 +50,10 @@ class PermissionPromptImpl : public permissions::PermissionPrompt, ...@@ -50,6 +50,10 @@ class PermissionPromptImpl : public permissions::PermissionPrompt,
void ShowBubble(); void ShowBubble();
void ShowChipUI();
bool ShouldCurrentRequestUseChipUI();
// The popup bubble. Not owned by this class; it will delete itself when a // The popup bubble. Not owned by this class; it will delete itself when a
// decision is made. // decision is made.
PermissionPromptBubbleView* prompt_bubble_; PermissionPromptBubbleView* prompt_bubble_;
......
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