text: // Copyright 2018 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "chrome/browser/web_applications/externally_managed_app_registration_task.h"
  
  #include "base/callback_helpers.h"
  #include "chrome/browser/profiles/profile.h"
  #include "chrome/browser/web_applications/components/externally_managed_app_manager.h"
  #include "chrome/browser/web_applications/components/web_app_url_loader.h"
  #include "content/public/browser/browser_context.h"
  #include "content/public/browser/service_worker_context.h"
  #include "content/public/browser/storage_partition.h"
  #include "content/public/browser/web_contents.h"
  #include "url/url_constants.h"
  
  namespace web_app {
  
  ExternallyManagedAppRegistrationTaskBase::
      ExternallyManagedAppRegistrationTaskBase(const GURL& install_url)
      : install_url_(install_url) {}
  
  ExternallyManagedAppRegistrationTaskBase::
      ~ExternallyManagedAppRegistrationTaskBase() = default;
  
  int ExternallyManagedAppRegistrationTask::registration_timeout_in_seconds_ = 40;
  
  ExternallyManagedAppRegistrationTask::ExternallyManagedAppRegistrationTask(
      const GURL& install_url,
      WebAppUrlLoader* url_loader,
      content::WebContents* web_contents,
      RegistrationCallback callback)
      : ExternallyManagedAppRegistrationTaskBase(install_url),
        url_loader_(url_loader),
        web_contents_(web_contents),
        callback_(std::move(callback)) {
    content::StoragePartition* storage_partition =
        web_contents_->GetBrowserContext()->GetStoragePartition(
            web_contents_->GetSiteInstance());
    DCHECK(storage_partition);
  
    service_worker_context_ = storage_partition->GetServiceWorkerContext();
    service_worker_context_->AddObserver(this);
  
    registration_timer_.Start(
        FROM_HERE, base::TimeDelta::FromSeconds(registration_timeout_in_seconds_),
        base::BindOnce(
            &ExternallyManagedAppRegistrationTask::OnRegistrationTimeout,
            weak_ptr_factory_.GetWeakPtr()));
  
    // Check to see if there is already a service worker for the install url.
    service_worker_context_->CheckHasServiceWorker(
        install_url,
        base::BindOnce(
            &ExternallyManagedAppRegistrationTask::OnDidCheckHasServiceWorker,
            weak_ptr_factory_.GetWeakPtr()));
  }
  
  ExternallyManagedAppRegistrationTask::~ExternallyManagedAppRegistrationTask() {
    if (service_worker_context_)
      service_worker_context_->RemoveObserver(this);
  }
  
  void ExternallyManagedAppRegistrationTask::OnRegistrationCompleted(
      const GURL& scope) {
    if (!content::ServiceWorkerContext::ScopeMatches(scope, install_url()))
      return;
  
    registration_timer_.Stop();
    std::move(callback_).Run(RegistrationResultCode::kSuccess);
  }
  
  void ExternallyManagedAppRegistrationTask::OnDestruct(
      content::ServiceWorkerContext* context) {
    service_worker_context_->RemoveObserver(this);
    service_worker_context_ = nullptr;
  }
  
  void ExternallyManagedAppRegistrationTask::SetTimeoutForTesting(
      int registration_timeout_in_seconds) {
    registration_timeout_in_seconds_ = registration_timeout_in_seconds;
  }
  
  void ExternallyManagedAppRegistrationTask::OnDidCheckHasServiceWorker(
      content::ServiceWorkerCapability capability) {
    if (capability != content::ServiceWorkerCapability::NO_SERVICE_WORKER) {
      registration_timer_.Stop();
      std::move(callback_).Run(RegistrationResultCode::kAlreadyRegistered);
      return;
    }
  
    url_loader_->PrepareForLoad(
        web_contents_,
        base::BindOnce(&ExternallyManagedAppRegistrationTask::OnWebContentsReady,
                       weak_ptr_factory_.GetWeakPtr()));
  }
  
  void ExternallyManagedAppRegistrationTask::OnWebContentsReady(
      WebAppUrlLoader::Result result) {
    // TODO(crbug.com/1098139): Handle the scenario where WebAppUrlLoader fails to
    // load about:blank and flush WebContents states.
  
    // No action is needed when the URL loads.
    // We wait for OnRegistrationCompleted (or registration timeout).
    url_loader_->LoadUrl(install_url(), web_contents_,
                         WebAppUrlLoader::UrlComparison::kExact,
                         base::DoNothing());
  }
  
  void ExternallyManagedAppRegistrationTask::OnRegistrationTimeout() {
    std::move(callback_).Run(RegistrationResultCode::kTimeout);
  }
  
  }  // namespace web_app
  