chromium/chrome/browser/download/android/download_manager_service.h

// Copyright 2015 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_ANDROID_DOWNLOAD_MANAGER_SERVICE_H_
#define CHROME_BROWSER_DOWNLOAD_ANDROID_DOWNLOAD_MANAGER_SERVICE_H_

#include <map>
#include <memory>
#include <string>
#include <vector>

#include "base/android/scoped_java_ref.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/singleton.h"
#include "base/scoped_multi_source_observation.h"
#include "chrome/browser/download/android/download_open_source.h"
#include "chrome/browser/download/download_manager_utils.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_observer.h"
#include "components/download/public/common/all_download_event_notifier.h"
#include "components/download/public/common/in_progress_download_manager.h"
#include "content/public/browser/download_manager.h"

using base::android::JavaParamRef;

class Profile;
class ProfileKey;

namespace download {
class DownloadItem;
class SimpleDownloadManagerCoordinator;
}  // namespace download

// Native side of DownloadManagerService.java. The native object is owned by its
// Java object.
class DownloadManagerService
    : public download::AllDownloadEventNotifier::Observer,
      public ProfileObserver {
 public:
  static void CreateAutoResumptionHandler();

  static void OnDownloadCanceled(download::DownloadItem* download,
                                 bool has_no_external_storage);

  static DownloadManagerService* GetInstance();

  static base::android::ScopedJavaLocalRef<jobject> CreateJavaDownloadInfo(
      JNIEnv* env,
      download::DownloadItem* item);

  DownloadManagerService();

  DownloadManagerService(const DownloadManagerService&) = delete;
  DownloadManagerService& operator=(const DownloadManagerService&) = delete;

  ~DownloadManagerService() override;

  // Called to Initialize this object. If |is_profile_added| is false,
  // it means only a minimal browser is launched. OnProfileAdded() will
  // be called later when the profile is added.
  void Init(JNIEnv* env, jobject obj, bool is_profile_added);

  // Called when the profile is added to the ProfileManager and fully
  // initialized.
  void OnProfileAdded(JNIEnv* env, jobject obj, Profile* profile);

  void OnProfileAdded(Profile* profile);

  // Called to handle subsequent steps, after a download was determined as a OMA
  // download type.
  void HandleOMADownload(download::DownloadItem* download,
                         int64_t system_download_id);

  // Called to open a given download item.
  void OpenDownload(download::DownloadItem* download, int source);

  // Called to open a download item whose GUID is equal to |jdownload_guid|.
  void OpenDownload(JNIEnv* env,
                    jobject obj,
                    std::string& download_guid,
                    const JavaParamRef<jobject>& j_profile_key,
                    jint source);

  // Called to resume downloading the item that has GUID equal to
  // |jdownload_guid|..
  void ResumeDownload(JNIEnv* env,
                      jobject obj,
                      std::string& download_guid,
                      const JavaParamRef<jobject>& j_profile_key);

  // Called to cancel a download item that has GUID equal to |jdownload_guid|.
  // If the DownloadItem is not yet created, retry after a while.
  void CancelDownload(JNIEnv* env,
                      jobject obj,
                      std::string& download_guid,
                      const JavaParamRef<jobject>& j_profile_key);

  // Called to pause a download item that has GUID equal to |jdownload_guid|.
  // If the DownloadItem is not yet created, do nothing as it is already paused.
  void PauseDownload(JNIEnv* env,
                     jobject obj,
                     std::string& download_guid,
                     const JavaParamRef<jobject>& j_profile_key);

  // Called to remove a download item that has GUID equal to |jdownload_guid|.
  void RemoveDownload(JNIEnv* env,
                      jobject obj,
                      std::string& download_guid,
                      const JavaParamRef<jobject>& j_profile_key);

  // Called to rename a download item that has GUID equal to |id|.
  void RenameDownload(JNIEnv* env,
                      const JavaParamRef<jobject>& obj,
                      std::string& id,
                      std::string& name,
                      const JavaParamRef<jobject>& callback,
                      const JavaParamRef<jobject>& j_profile_key);

  // Returns whether or not the given download can be opened by the browser.
  bool IsDownloadOpenableInBrowser(JNIEnv* env,
                                   jobject obj,
                                   const JavaParamRef<jstring>& jdownload_guid,
                                   const JavaParamRef<jobject>& j_profile_key);

  // Called to request that the DownloadManagerService return data about all
  // downloads in the user's history.
  void GetAllDownloads(JNIEnv* env,
                       const JavaParamRef<jobject>& obj,
                       const JavaParamRef<jobject>& j_profile_key);

  // Called to check if the files associated with any downloads have been
  // removed by an external action.
  void CheckForExternallyRemovedDownloads(
      JNIEnv* env,
      const JavaParamRef<jobject>& obj,
      const JavaParamRef<jobject>& j_profile_key);

  // Called to update the last access time associated with a download.
  void UpdateLastAccessTime(JNIEnv* env,
                            const JavaParamRef<jobject>& obj,
                            std::string& download_guid,
                            const JavaParamRef<jobject>& j_profile_key);

  // AllDownloadEventNotifier::Observer methods.
  void OnDownloadsInitialized(
      download::SimpleDownloadManagerCoordinator* coordinator,
      bool active_downloads_only) override;
  void OnManagerGoingDown(
      download::SimpleDownloadManagerCoordinator* coordinator) override;
  void OnDownloadCreated(
      download::SimpleDownloadManagerCoordinator* coordinator,
      download::DownloadItem* item) override;
  void OnDownloadUpdated(
      download::SimpleDownloadManagerCoordinator* coordinator,
      download::DownloadItem* item) override;
  void OnDownloadRemoved(
      download::SimpleDownloadManagerCoordinator* coordinator,
      download::DownloadItem* item) override;

  // ProfileObserver:
  void OnOffTheRecordProfileCreated(Profile* off_the_record) override;

  // Called by the java code to create and insert an interrupted download to
  // |in_progress_manager_| for testing purpose.
  void CreateInterruptedDownloadForTest(JNIEnv* env,
                                        jobject obj,
                                        std::string& url,
                                        std::string& download_guid,
                                        std::string& target_path);

  // Retrives the in-progress manager and give up the ownership.
  std::unique_ptr<download::InProgressDownloadManager>
  RetrieveInProgressDownloadManager(content::BrowserContext* context);

  // Gets a download item from DownloadManager or InProgressManager.
  download::DownloadItem* GetDownload(const std::string& download_guid,
                                      ProfileKey* profile_key);

  // Helper method to record the interrupt reason UMA for the first background
  // download.
  void RecordFirstBackgroundInterruptReason(JNIEnv* env,
                                            const JavaParamRef<jobject>& obj,
                                            std::string& download_guid,
                                            jboolean download_started);

  // Open the download page the given profile, and the source of the opening
  // action is |download_open_source|.
  void OpenDownloadsPage(Profile* profile,
                         DownloadOpenSource download_open_source);

 private:
  // For testing.
  friend class DownloadManagerServiceTest;
  friend struct base::DefaultSingletonTraits<DownloadManagerService>;

  enum DownloadAction { RESUME, PAUSE, CANCEL, REMOVE, UNKNOWN };

  using PendingDownloadActions = std::map<std::string, DownloadAction>;
  using Coordinators =
      std::map<ProfileKey*, download::SimpleDownloadManagerCoordinator*>;

  // Helper function to start the download resumption.
  void ResumeDownloadInternal(const std::string& download_guid,
                              ProfileKey* profile_key);

  // Helper function to cancel a download.
  void CancelDownloadInternal(const std::string& download_guid,
                              ProfileKey* profile_key);

  // Helper function to pause a download.
  void PauseDownloadInternal(const std::string& download_guid,
                             ProfileKey* profile_key);

  // Helper function to remove a download.
  void RemoveDownloadInternal(const std::string& download_guid,
                              ProfileKey* profile_key);

  // Helper function to send info about all downloads to the Java-side.
  void GetAllDownloadsInternal(ProfileKey* profile_key);

  // Called to notify the java side that download resumption failed.
  void OnResumptionFailed(const std::string& download_guid);

  void OnResumptionFailedInternal(const std::string& download_guid);

  // Called when all pending downloads are loaded.
  void OnPendingDownloadsLoaded();

  using ResumeCallback = base::OnceCallback<void(bool)>;
  void set_resume_callback_for_testing(ResumeCallback resume_cb) {
    resume_callback_for_testing_ = std::move(resume_cb);
  }

  // Helper method to reset the SimpleDownloadManagerCoordinator if needed.
  void ResetCoordinatorIfNeeded(ProfileKey* profile_key);

  // Helper method to reset the SimpleDownloadManagerCoordinator for a given
  // profile type.
  void UpdateCoordinator(
      download::SimpleDownloadManagerCoordinator* coordinator,
      ProfileKey* profile_key);

  // Called to get the content::DownloadManager instance.
  content::DownloadManager* GetDownloadManager(ProfileKey* profile_key);

  // Retrieves the SimpleDownloadManagerCoordinator this object is listening to.
  download::SimpleDownloadManagerCoordinator* GetCoordinator(
      ProfileKey* profile_key);

  void InitializeForProfile(ProfileKey* profile_key);

  // Reference to the Java object.
  base::android::ScopedJavaGlobalRef<jobject> java_ref_;

  bool is_manager_initialized_;
  bool is_pending_downloads_loaded_;

  std::vector<raw_ptr<ProfileKey, VectorExperimental>>
      profiles_with_pending_get_downloads_actions_;

  PendingDownloadActions pending_actions_;

  void EnqueueDownloadAction(const std::string& download_guid,
                             DownloadAction download_action);

  ResumeCallback resume_callback_for_testing_;

  base::ScopedMultiSourceObservation<Profile, ProfileObserver>
      observed_profiles_{this};

  Coordinators coordinators_;
};

#endif  // CHROME_BROWSER_DOWNLOAD_ANDROID_DOWNLOAD_MANAGER_SERVICE_H_