blob: b917291787c3a166513de713c0ea17d464a821cf [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_VIEWS_PERMISSIONS_CHIP_CONTROLLER_H_
#define CHROME_BROWSER_UI_VIEWS_PERMISSIONS_CHIP_CONTROLLER_H_
#include <cstddef>
#include <memory>
#include "base/check_is_test.h"
#include "base/functional/callback_helpers.h"
#include "base/timer/timer.h"
#include "chrome/browser/ui/views/location_bar/omnibox_chip_button.h"
#include "components/permissions/permission_prompt.h"
#include "components/permissions/permission_request_manager.h"
#include "components/permissions/permission_util.h"
#include "ui/views/widget/widget_observer.h"
class PermissionPromptChipModel;
class LocationBarView;
// ButtonController that NotifyClick from being called when the
// BubbleOwnerDelegate's bubble is showing. Otherwise the bubble will show again
// immediately after being closed via losing focus.
class BubbleOwnerDelegate {
public:
virtual bool IsBubbleShowing() = 0;
virtual bool IsAnimating() const = 0;
virtual void RestartTimersOnMouseHover() = 0;
};
// This class controls a chip UI view to surface permission related information
// and prompts. For its creation, the controller expects an object of type
// OmniboxChipButton which should be a child view of another view. No ownership
// is transferred through the creation, and the controller will never destruct
// the OmniboxChipButton object. The controller and it's view are intended to
// be long-lived.
class ChipController : public permissions::PermissionRequestManager::Observer,
public views::WidgetObserver,
public BubbleOwnerDelegate,
public OmniboxChipButton::Observer {
public:
ChipController(Browser* browser_, OmniboxChipButton* chip_view);
~ChipController() override;
ChipController(const ChipController&) = delete;
ChipController& operator=(const ChipController&) = delete;
// PermissionRequestManager::Observer:
void OnPermissionRequestManagerDestructed() override;
void OnTabVisibilityChanged(content::Visibility visibility) override;
void OnRequestsFinalized() override;
// OnBubbleRemoved only triggers when a request chip (bubble) is removed, when
// the user navigates while a confirmation chip is showing, the request is
// already finished and hence OnBubbleRemoved is not triggered. Thus we need
// to handle chip cleanup on navigation events separately.
void OnNavigation(content::NavigationHandle* navigation_handle) override;
void OnRequestDecided(permissions::PermissionAction permissions) override;
// BubbleOwnerDelegate:
bool IsBubbleShowing() override;
bool IsAnimating() const override;
void RestartTimersOnMouseHover() override;
// WidgetObserver:
void OnWidgetDestroying(views::Widget* widget) override;
void OnWidgetActivationChanged(views::Widget* widget, bool active) override;
// OmniboxChipButton::Observer
void OnChipVisibilityChanged(bool is_visible) override;
void OnExpandAnimationEnded() override;
void OnCollapseAnimationEnded() override;
// Initializes the permission prompt model as well as the permission request
// manager and observes the prompt bubble.
void InitializePermissionPrompt(
content::WebContents* web_contents,
base::WeakPtr<permissions::PermissionPrompt::Delegate> delegate,
base::OnceCallback<void()>);
// Displays a permission prompt using the chip UI.
void ShowPermissionPrompt(
content::WebContents* web_contents,
base::WeakPtr<permissions::PermissionPrompt::Delegate> delegate);
// Chip View.
OmniboxChipButton* chip() { return chip_; }
// Hide and clean up permission parts of the chip.
void ResetPermissionPromptChip();
bool IsPermissionPromptChipVisible() {
return chip_ && chip_->GetVisible() && permission_prompt_model_;
}
views::Widget* GetBubbleWidget();
PermissionPromptBubbleBaseView* GetPromptBubbleView();
bool should_expand_for_testing();
bool is_collapse_timer_running_for_testing() {
CHECK_IS_TEST();
return collapse_timer_.IsRunning();
}
void fire_collapse_timer_for_testing() {
CHECK_IS_TEST();
collapse_timer_.FireNow();
}
bool is_dismiss_timer_running_for_testing() {
CHECK_IS_TEST();
return dismiss_timer_.IsRunning();
}
void stop_animation_for_test() {
CHECK_IS_TEST();
chip_->animation_for_testing()->Stop();
OnExpandAnimationEnded();
}
views::View* get_prompt_bubble_view_for_testing() {
CHECK_IS_TEST();
return bubble_tracker_.view();
}
absl::optional<permissions::PermissionRequestManager*>
active_permission_request_manager_for_testing() {
CHECK_IS_TEST();
return active_chip_permission_request_manager_;
}
private:
bool ShouldWaitForConfirmationToComplete();
void AnimateExpand();
// Confirmation chip.
void HandleConfirmation(permissions::PermissionAction permission_action);
void CollapseConfirmation();
// Permission prompt chip functionality.
void AnnouncePermissionRequestForAccessibility(const std::u16string& text);
void CollapsePrompt(bool allow_restart);
// Hides the chip and invalidates the layout.
void HideChip();
// Permission prompt bubble functiontionality.
void OpenPermissionPromptBubble();
void ClosePermissionPromptBubbleWithReason(
views::Widget::ClosedReason reason);
void RecordRequestChipButtonPressed(const char* recordKey);
// Event handling.
void ObservePromptBubble();
void OnPromptBubbleDismissed();
void OnPromptExpired();
void OnRequestChipButtonPressed();
// Updates chip icon, text and theme with model.
void SyncChipWithModel();
// Opens the Page Info Dialog.
void ShowPageInfoDialog();
// Actions executed when the user closes the page info dialog.
void OnPageInfoBubbleClosed(views::Widget::ClosedReason closed_reason,
bool reload_prompt);
// Clean up utility.
void RemoveBubbleObserverAndResetTimersAndChipCallbacks();
// Timer functionality.
void StartCollapseTimer();
void StartDismissTimer();
void ResetTimers();
// The location bar view to which the chip is attached.
LocationBarView* GetLocationBarView();
bool is_confirmation_showing_ = false;
bool is_waiting_for_confirmation_collapse = false;
// The chip view this controller modifies.
raw_ptr<OmniboxChipButton> chip_;
raw_ptr<Browser> browser_;
// The time when the request chip was displayed.
base::TimeTicks request_chip_shown_time_;
// A timer used to dismiss the permission request after it's been collapsed
// for a while.
base::OneShotTimer dismiss_timer_;
// A timer used to collapse the chip after a delay.
base::OneShotTimer collapse_timer_;
// A timer used to delay showing a prompt if a confirmation chip is being
// displayed.
base::OneShotTimer delay_prompt_timer_;
bool parent_was_visible_when_activation_changed_ = false;
// The model of a permission prompt if one is present.
std::unique_ptr<PermissionPromptChipModel> permission_prompt_model_;
absl::optional<permissions::PermissionRequestManager*>
active_chip_permission_request_manager_;
views::ViewTracker bubble_tracker_;
base::ScopedClosureRunner disallowed_custom_cursors_scope_;
base::ScopedObservation<OmniboxChipButton, OmniboxChipButton::Observer>
observation_{this};
base::WeakPtrFactory<ChipController> weak_factory_{this};
};
#endif // CHROME_BROWSER_UI_VIEWS_PERMISSIONS_CHIP_CONTROLLER_H_