blob: 6be36b68cec01b046efefd147a95c3be269a6a76 [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_DOWNLOAD_BUBBLE_DOWNLOAD_BUBBLE_UI_CONTROLLER_H_
#define CHROME_BROWSER_DOWNLOAD_BUBBLE_DOWNLOAD_BUBBLE_UI_CONTROLLER_H_
#include <optional>
#include <set>
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "chrome/browser/download/bubble/download_bubble_update_service.h"
#include "chrome/browser/download/bubble/download_display_controller.h"
#include "chrome/browser/download/download_warning_desktop_hats_utils.h"
#include "chrome/browser/download/offline_item_model.h"
#include "chrome/browser/metrics/browser_activity_watcher.h"
#include "components/download/content/public/all_download_item_notifier.h"
#include "components/offline_items_collection/core/offline_content_aggregator.h"
#include "components/offline_items_collection/core/offline_content_provider.h"
class Profile;
namespace offline_items_collection {
struct ContentId;
}
// This handles the window-level logic for controlling the download bubble.
// There is one instance of this class per browser window, and it is owned by
// the download toolbar button.
class DownloadBubbleUIController {
public:
// Get a valid controller for the given `download`. In the case of web apps,
// this will always be the web app window's controller. For regular downloads,
// this could be the controller for the most recently active window associated
// with this profile.
static DownloadBubbleUIController* GetForDownload(
download::DownloadItem* download);
explicit DownloadBubbleUIController(Browser* browser);
// Used to inject a custom DownloadBubbleUpdateService for testing. Prefer
// the constructor above which uses that of the profile.
DownloadBubbleUIController(Browser* browser,
DownloadBubbleUpdateService* update_service);
DownloadBubbleUIController(const DownloadBubbleUIController&) = delete;
DownloadBubbleUIController& operator=(const DownloadBubbleUIController&) =
delete;
virtual ~DownloadBubbleUIController();
// These methods are called to notify the UI of new events.
// |may_show_animation| is whether the window this controller belongs to may
// show the animation. (Whether the animation is actually shown may depend on
// the download and the device's graphics capabilities.) We don't show an
// animation for offline items. Notifications for created/added download items
// generally come from the DownloadUIController(Delegate) (except for crx
// downloads, which come via the DownloadBubbleUpdateService), and the rest
// are called from DownloadBubbleUpdateService.
void OnDownloadItemAdded(download::DownloadItem* item,
bool may_show_animation);
void OnDownloadItemUpdated(download::DownloadItem* item);
void OnDownloadItemRemoved(download::DownloadItem* item);
void OnOfflineItemsAdded(
const OfflineContentProvider::OfflineItemList& items);
void OnOfflineItemUpdated(const OfflineItem& item);
void OnOfflineItemRemoved(const ContentId& id);
// Get the entries for the main view of the Download Bubble. The main view
// contains all the recent downloads (finished within the last 24 hours).
// Virtual for testing.
virtual std::vector<DownloadUIModel::DownloadUIModelPtr> GetMainView();
// Get the entries for the partial view of the Download Bubble. The partial
// view contains in-progress and uninteracted downloads, meant to capture the
// user's recent tasks. This can only be opened by the browser in the event of
// new downloads, and user action only creates a main view.
// Virtual for testing.
virtual std::vector<DownloadUIModel::DownloadUIModelPtr> GetPartialView();
// Process button press on the bubble.
// May launch a HaTS survey if the action applies to a download warning.
// TODO(chlily): `is_main_view` should be named `is_primary_view`. It
// distinguishes the primary page from the (security) subpage, not the main vs
// partial flavors of the primary view.
void ProcessDownloadButtonPress(base::WeakPtr<DownloadUIModel> model,
DownloadCommands::Command command,
bool is_main_view);
// Notify when a download toolbar button (in any window) is pressed.
void HandleButtonPressed();
// Schedules the ephemeral warning download to be hidden from the bubble, and
// subsequently canceled. It will only be canceled if it continues to be an
// ephemeral warning that hasn't been acted on when the scheduled time
// arrives.
void ScheduleCancelForEphemeralWarning(const std::string& guid);
// Force the controller to hide the download UI entirely, including the bubble
// and the toolbar icon. This function should only be called if the event is
// triggered outside of normal download events that are not listened by
// observers.
void HideDownloadUi();
// Records that a dangerous download was shown to the user. This only
// records the fact that an interaction occurred, and should not be
// used quantitatively to count the number of such interactions.
void RecordDangerousDownloadShownToUser(download::DownloadItem* download);
// Returns the DownloadDisplayController. Should always return a valid
// controller.
DownloadDisplayController* GetDownloadDisplayController() {
return display_controller_;
}
void SetDownloadDisplayController(DownloadDisplayController* controller) {
display_controller_ = controller;
}
DownloadBubbleUpdateService* update_service() { return update_service_; }
// See comment on member below. This may not be correct/meaningful, do not
// rely on this for anything important. This is not meaningful if the partial
// view is not enabled.
bool last_primary_view_was_partial() const {
return last_primary_view_was_partial_;
}
base::WeakPtr<DownloadBubbleUIController> GetWeakPtr();
private:
friend class DownloadBubbleUIControllerTest;
friend class DownloadBubbleUIControllerIncognitoTest;
// Common method for getting main and partial views.
std::vector<DownloadUIModel::DownloadUIModelPtr> GetDownloadUIModels(
bool is_main_view);
// Kick off retrying an eligible interrupted download.
void RetryDownload(DownloadUIModel* model, DownloadCommands::Command command);
// Stamps the PSD for HaTS surveys with the extra info specific to the
// download bubble triggers.
void CompleteHatsPsd(DownloadWarningHatsProductSpecificData& psd);
// Callback for `browser_activity_observer_`.
void OnBrowserActivity();
raw_ptr<Browser, DanglingUntriaged> browser_;
raw_ptr<Profile, DanglingUntriaged> profile_;
raw_ptr<DownloadBubbleUpdateService, DanglingUntriaged> update_service_;
raw_ptr<OfflineItemModelManager, DanglingUntriaged> offline_manager_;
// DownloadDisplayController and DownloadBubbleUIController have the same
// lifetime. Both are owned, constructed together, and destructed together by
// DownloadToolbarButtonView. If one is valid, so is the other.
raw_ptr<DownloadDisplayController, AcrossTasksDanglingUntriaged>
display_controller_;
std::optional<base::Time> last_partial_view_shown_time_ = std::nullopt;
// Tracks whether the last time we provided models was for a partial view
// (true) or a main view (false). This is an approximation for whether the
// last incarnation of the download bubble that the user saw or interacted
// with was a partial or main view. (It's only an approximation because there
// are controllers for other browsers that are not accounted for here.) In
// most cases, this should be correct and meaningful if queried immediately
// after the user interacted with / clicked on the bubble. This value might
// be bogus if the download bubble is shown on multiple browsers at the same
// time, or if the primary view is bypassed altogether (e.g. by clicking on
// a desktop notification on ChromeOS to go to the security view directly).
bool last_primary_view_was_partial_ = false;
// Used for showing HaTS surveys when download warnings are delayed.
// Nullptr when the user is not eligible for download bubble warning ignored
// surveys.
std::unique_ptr<DelayedDownloadWarningHatsLauncher> delayed_hats_launcher_;
std::unique_ptr<BrowserActivityWatcher> browser_activity_watcher_;
base::WeakPtrFactory<DownloadBubbleUIController> weak_factory_{this};
};
#endif // CHROME_BROWSER_DOWNLOAD_BUBBLE_DOWNLOAD_BUBBLE_UI_CONTROLLER_H_