1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
|
// Copyright 2019 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_ENTERPRISE_CONNECTORS_ANALYSIS_CONTENT_ANALYSIS_DIALOG_CONTROLLER_H_
#define CHROME_BROWSER_ENTERPRISE_CONNECTORS_ANALYSIS_CONTENT_ANALYSIS_DIALOG_CONTROLLER_H_
#include <cstddef>
#include <memory>
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "chrome/browser/enterprise/connectors/analysis/content_analysis_delegate_base.h"
#include "chrome/browser/enterprise/connectors/analysis/content_analysis_dialog_delegate.h"
#include "chrome/browser/enterprise/connectors/common.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h"
#include "components/download/public/common/download_item.h"
#include "content/public/browser/web_contents_observer.h"
#include "ui/base/mojom/ui_base_types.mojom-shared.h"
#include "ui/views/animation/bounds_animator.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/styled_label.h"
#include "ui/views/controls/textfield/textfield_controller.h"
#include "ui/views/window/dialog_delegate.h"
namespace content {
class WebContents;
} // namespace content
namespace views {
class ImageView;
class Label;
class Link;
class Textarea;
class Throbber;
} // namespace views
namespace enterprise_connectors {
// Dialog shown for Deep Scanning to offer the possibility of cancelling the
// upload to the user.
class ContentAnalysisDialogController
: public ContentAnalysisDialogDelegate,
public content::WebContentsObserver,
public download::DownloadItem::Observer {
public:
// TestObserver should be implemented by tests that need to track when certain
// ContentAnalysisDialogController functions are called. The test can add
// itself as an observer by using SetObserverForTesting.
class TestObserver {
public:
virtual ~TestObserver() = default;
// Called at the start of ContentAnalysisDialogController's constructor.
// `dialog` is a pointer to the newly constructed
// ContentAnalysisDialogController and should be kept in memory by the test
// in order to validate its state.
virtual void ConstructorCalled(ContentAnalysisDialogController* dialog,
base::TimeTicks timestamp) {}
// Called at the end of ContentAnalysisDialogController::Show. `timestamp`
// is the time used by ContentAnalysisDialogController to decide whether the
// pending state has been shown for long enough. The test can keep this time
// in memory and validate the pending time was sufficient in DialogUpdated.
virtual void ViewsFirstShown(ContentAnalysisDialogController* dialog,
base::TimeTicks timestamp) {}
// Called at the end of ContentAnalysisDialogController::UpdateDialog.
// `result` is the value that UpdatedDialog used to transition from the
// pending state to the success/failure/warning state.
virtual void DialogUpdated(ContentAnalysisDialogController* dialog,
FinalContentAnalysisResult result) {}
// Called at the start of CancelDialogAndDelete(). `dialog` is a pointer
// that will soon be destructed. Along with `result`, it is used by the test
// to validate the dialog should be canceled or deleted.
virtual void CancelDialogAndDeleteCalled(
ContentAnalysisDialogController* dialog,
FinalContentAnalysisResult result) {}
// Called at the end of ContentAnalysisDialogController's destructor.
// `dialog` is a pointer to the ContentAnalysisDialogController being
// destructed. It can be used to compare it to the pointer obtained from
// ConstructorCalled to ensure which view is being destroyed.
virtual void DestructorCalled(ContentAnalysisDialogController* dialog) {}
};
static void SetObserverForTesting(TestObserver* observer);
static void SetMinimumPendingDialogTimeForTesting(base::TimeDelta delta);
static void SetSuccessDialogTimeoutForTesting(base::TimeDelta delta);
static void SetShowDialogDelayForTesting(base::TimeDelta delta);
static base::TimeDelta GetMinimumPendingDialogTime();
static base::TimeDelta GetSuccessDialogTimeout();
static base::TimeDelta ShowDialogDelay();
ContentAnalysisDialogController(
std::unique_ptr<ContentAnalysisDelegateBase> delegate,
bool is_cloud,
content::WebContents* web_contents,
safe_browsing::DeepScanAccessPoint access_point,
int files_count,
FinalContentAnalysisResult final_result =
FinalContentAnalysisResult::SUCCESS,
download::DownloadItem* download_item = nullptr);
// content::WebContentsObserver:
void WebContentsDestroyed() override;
void PrimaryPageChanged(content::Page& page) override;
// Updates the dialog with the result, and simply delete it from memory if
// nothing should be shown.
void ShowResult(FinalContentAnalysisResult result);
inline bool is_cloud() const { return is_cloud_; }
// Cancels the dialog an schedules it for deletion if visible, otherwise
// simply deletes it soon.
void CancelDialogAndDelete();
// Accessors used to validate the views in tests.
views::ImageView* GetTopImageForTesting() const;
views::Throbber* GetSideIconSpinnerForTesting() const;
views::StyledLabel* GetMessageForTesting() const;
views::Link* GetLearnMoreLinkForTesting() const;
views::Label* GetBypassJustificationLabelForTesting() const;
views::Textarea* GetBypassJustificationTextareaForTesting() const;
views::Label* GetJustificationTextLengthForTesting() const;
private:
// Friend the unit test class for this so it can call the private dtor.
friend class ContentAnalysisDialogPlainTest;
// Friend to allow use of TaskRunner::DeleteSoon().
friend class base::DeleteHelper<ContentAnalysisDialogController>;
~ContentAnalysisDialogController() override;
// Callback function of delayed timer to make the dialog visible.
void ShowDialogNow();
// Update the UI depending on `dialog_state_`. This also triggers resizes and
// fires some events. It's meant to be called to update the entire dialog when
// it's already showing.
// This function can only be called after the dialog widget is initialized.
void UpdateDialog();
// Helper function to determine whether dialog should be shown immediately.
bool ShouldShowDialogNow();
void AcceptButtonCallback();
void CancelButtonCallback();
// This callback used by DialogDelegate::SetCancelCallback and is used to
// ensure the auto-closing success dialog handles focus correctly.
void SuccessCallback();
// download::DownloadItem::Observer:
void OnDownloadUpdated(download::DownloadItem* download) override;
void OnDownloadOpened(download::DownloadItem* download) override;
void OnDownloadDestroyed(download::DownloadItem* download) override;
// Several conditions can lead to the dialog being no longer useful, so this
// method is shared for those different conditions to close the dialog.
void CancelDialogWithoutCallback();
content::WebContents::Getter CreateWebContentsGetter();
std::unique_ptr<ContentAnalysisDelegateBase> delegate_base_;
base::TimeTicks first_shown_timestamp_;
// `DownloadItem` for dialogs corresponding to a download with a reviewable
// verdict. nullptr otherwise.
raw_ptr<download::DownloadItem> download_item_ = nullptr;
// Set to true once the dialog is either accepted or cancelled by the user.
// This is used to decide whether the dialog should go away without user input
// or not.
bool accepted_or_cancelled_ = false;
// Set to true once `DeleteSoon()` is called in `CancelDialogAndDelete()`.
// This is used by other pending tasks, such as `ShowDialogNow()` to do
// nothing if the dialog has been scheduled for deletion.
bool will_be_deleted_soon_ = false;
// If input events for our `WebContents` have been ignored, then this is the
// closure to re-enable them.
std::optional<content::WebContents::ScopedIgnoreInputEvents>
scoped_ignore_input_events_;
// A reference to the top level web contents of the tab whose content is
// being analyzed. Input events of this contents are ignored for the life
// time of the dialog.
base::WeakPtr<content::WebContents> top_level_contents_;
base::WeakPtrFactory<ContentAnalysisDialogController> weak_ptr_factory_{this};
};
} // namespace enterprise_connectors
#endif // CHROME_BROWSER_ENTERPRISE_CONNECTORS_ANALYSIS_CONTENT_ANALYSIS_DIALOG_CONTROLLER_H_
|