| // 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_ |