chromium/ios/chrome/browser/download/ui_bundled/unopened_downloads_tracker.mm

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/download/ui_bundled/unopened_downloads_tracker.h"

#import <Foundation/Foundation.h>

#import "base/metrics/histogram_functions.h"
#import "ios/chrome/browser/download/model/download_manager_metric_names.h"
#import "ios/chrome/browser/download/model/external_app_util.h"
#import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
#import "ios/web/public/download/download_task.h"
#import "net/base/net_errors.h"

UnopenedDownloadsTracker::UnopenedDownloadsTracker() {}

UnopenedDownloadsTracker::~UnopenedDownloadsTracker() {
  for (web::DownloadTask* task : observed_tasks_) {
    task->RemoveObserver(this);
    DownloadAborted(task);
  }
}

void UnopenedDownloadsTracker::Add(web::DownloadTask* task) {
  task->AddObserver(this);
  observed_tasks_.insert(task);
}

void UnopenedDownloadsTracker::Remove(web::DownloadTask* task) {
  task->RemoveObserver(this);
  observed_tasks_.erase(task);
}

void UnopenedDownloadsTracker::OnDownloadUpdated(web::DownloadTask* task) {
  if (task->IsDone()) {
    base::UmaHistogramEnumeration("Download.IOSDownloadFileResult",
                                  task->GetErrorCode()
                                      ? DownloadFileResult::Failure
                                      : DownloadFileResult::Completed,
                                  DownloadFileResult::Count);
    if (task->GetErrorCode()) {
      base::UmaHistogramSparse("Download.IOSDownloadedFileNetError",
                               -task->GetErrorCode());
    } else {
      bool GoogleDriveIsInstalled = IsGoogleDriveAppInstalled();
      if (GoogleDriveIsInstalled) {
        base::UmaHistogramEnumeration(
            "Download.IOSDownloadFileUIGoogleDrive",
            DownloadFileUIGoogleDrive::GoogleDriveAlreadyInstalled,
            DownloadFileUIGoogleDrive::Count);
      } else {
        base::UmaHistogramEnumeration(
            "Download.IOSDownloadFileUIGoogleDrive",
            DownloadFileUIGoogleDrive::GoogleDriveNotInstalled,
            DownloadFileUIGoogleDrive::Count);
      }
    }

    bool backgrounded = task->HasPerformedBackgroundDownload();
    DownloadFileInBackground histogram_value =
        task->GetErrorCode()
            ? (backgrounded
                   ? DownloadFileInBackground::FailedWithBackgrounding
                   : DownloadFileInBackground::FailedWithoutBackgrounding)
            : (backgrounded
                   ? DownloadFileInBackground::SucceededWithBackgrounding
                   : DownloadFileInBackground::SucceededWithoutBackgrounding);
    base::UmaHistogramEnumeration("Download.IOSDownloadFileInBackground",
                                  histogram_value,
                                  DownloadFileInBackground::Count);
  }
}

void UnopenedDownloadsTracker::OnDownloadDestroyed(web::DownloadTask* task) {
  // This download task was never open by the user.
  task->RemoveObserver(this);
  observed_tasks_.erase(task);

  DownloadAborted(task);
}

void UnopenedDownloadsTracker::DownloadAborted(web::DownloadTask* task) {
  if (task->GetState() == web::DownloadTask::State::kInProgress) {
    base::UmaHistogramEnumeration("Download.IOSDownloadFileResult",
                                  DownloadFileResult::Other,
                                  DownloadFileResult::Count);

    if (did_close_web_state_without_user_action) {
      // web state can be closed without user action only during the app
      // shutdown.
      base::UmaHistogramEnumeration(
          "Download.IOSDownloadFileInBackground",
          DownloadFileInBackground::CanceledAfterAppQuit,
          DownloadFileInBackground::Count);
    }
  }

  if (task->IsDone() && task->GetErrorCode() == net::OK) {
    base::UmaHistogramEnumeration(
        "Download.IOSDownloadedFileAction",
        DownloadedFileAction::NoActionOrOpenedViaExtension,
        DownloadedFileAction::Count);
  }
}

void UnopenedDownloadsTracker::WebStateListWillChange(
    WebStateList* web_state_list,
    const WebStateListChangeDetach& detach_change,
    const WebStateListStatus& status) {
  if (!detach_change.is_closing()) {
    return;
  }

  if (!detach_change.is_user_action()) {
    did_close_web_state_without_user_action = true;
  }
}