blob: b0031dcb63a17ec2d4451f4a19badb4a4b0c886d [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.
#include "chrome/browser/web_applications/commands/fetch_installability_for_chrome_management.h"
#include <memory>
#include <optional>
#include <utility>
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/values.h"
#include "chrome/browser/web_applications/commands/web_app_command.h"
#include "chrome/browser/web_applications/locks/app_lock.h"
#include "chrome/browser/web_applications/locks/noop_lock.h"
#include "chrome/browser/web_applications/locks/web_app_lock_manager.h"
#include "chrome/browser/web_applications/web_app_command_manager.h"
#include "chrome/browser/web_applications/web_app_helpers.h"
#include "chrome/browser/web_applications/web_contents/web_app_data_retriever.h"
#include "components/webapps/browser/installable/installable_logging.h"
#include "components/webapps/browser/web_contents/web_app_url_loader.h"
#include "components/webapps/common/web_app_id.h"
#include "content/public/browser/web_contents.h"
#include "url/gurl.h"
namespace web_app {
FetchInstallabilityForChromeManagement::FetchInstallabilityForChromeManagement(
const GURL& url,
base::WeakPtr<content::WebContents> web_contents,
std::unique_ptr<webapps::WebAppUrlLoader> url_loader,
std::unique_ptr<WebAppDataRetriever> data_retriever,
FetchInstallabilityForChromeManagementCallback callback)
: WebAppCommand<NoopLock,
InstallableCheckResult,
std::optional<webapps::AppId>>(
"FetchInstallabilityForChromeManagement",
NoopLockDescription(),
std::move(callback),
/*args_for_shutdown=*/
std::make_tuple(InstallableCheckResult::kNotInstallable,
std::nullopt)),
url_(url),
web_contents_(web_contents),
url_loader_(std::move(url_loader)),
data_retriever_(std::move(data_retriever)) {
CHECK(url.is_valid());
CHECK(web_contents_);
CHECK(url_loader_);
CHECK(data_retriever_);
GetMutableDebugValue().Set("url", url.spec());
}
FetchInstallabilityForChromeManagement::
~FetchInstallabilityForChromeManagement() = default;
void FetchInstallabilityForChromeManagement::StartWithLock(
std::unique_ptr<NoopLock> lock) {
noop_lock_ = std::move(lock);
if (IsWebContentsDestroyed()) {
GetMutableDebugValue().Set("web_contents_destroyed", true);
CompleteAndSelfDestruct(CommandResult::kSuccess,
InstallableCheckResult::kNotInstallable,
std::nullopt);
return;
}
url_loader_->LoadUrl(
url_, web_contents_.get(),
webapps::WebAppUrlLoader::UrlComparison::kIgnoreQueryParamsAndRef,
base::BindOnce(&FetchInstallabilityForChromeManagement::
OnUrlLoadedCheckInstallability,
weak_factory_.GetWeakPtr()));
}
void FetchInstallabilityForChromeManagement::OnUrlLoadedCheckInstallability(
webapps::WebAppUrlLoaderResult result) {
if (IsWebContentsDestroyed()) {
GetMutableDebugValue().Set("web_contents_destroyed", true);
CompleteAndSelfDestruct(CommandResult::kSuccess,
InstallableCheckResult::kNotInstallable,
std::nullopt);
return;
}
GetMutableDebugValue().Set("WebAppUrlLoader::Result",
ConvertUrlLoaderResultToString(result));
if (result == webapps::WebAppUrlLoaderResult::kRedirectedUrlLoaded) {
CompleteAndSelfDestruct(CommandResult::kSuccess,
InstallableCheckResult::kNotInstallable,
std::nullopt);
return;
}
if (result == webapps::WebAppUrlLoaderResult::kFailedPageTookTooLong) {
CompleteAndSelfDestruct(CommandResult::kSuccess,
InstallableCheckResult::kNotInstallable,
std::nullopt);
return;
}
if (result != webapps::WebAppUrlLoaderResult::kUrlLoaded) {
CompleteAndSelfDestruct(CommandResult::kFailure,
InstallableCheckResult::kNotInstallable,
std::nullopt);
return;
}
data_retriever_->CheckInstallabilityAndRetrieveManifest(
web_contents_.get(),
base::BindOnce(&FetchInstallabilityForChromeManagement::
OnWebAppInstallabilityChecked,
weak_factory_.GetWeakPtr()));
}
void FetchInstallabilityForChromeManagement::OnWebAppInstallabilityChecked(
blink::mojom::ManifestPtr opt_manifest,
const GURL& manifest_url,
bool valid_manifest_for_web_app,
webapps::InstallableStatusCode error_code) {
if (IsWebContentsDestroyed()) {
GetMutableDebugValue().Set("web_contents_destroyed", true);
CompleteAndSelfDestruct(CommandResult::kSuccess,
InstallableCheckResult::kNotInstallable,
std::nullopt);
return;
}
if (error_code != webapps::InstallableStatusCode::NO_ERROR_DETECTED) {
CompleteAndSelfDestruct(CommandResult::kSuccess,
InstallableCheckResult::kNotInstallable,
std::nullopt);
return;
}
DCHECK(opt_manifest);
app_id_ = GenerateAppIdFromManifest(*opt_manifest);
GetMutableDebugValue().Set("app_id", app_id_);
command_manager()->lock_manager().UpgradeAndAcquireLock(
std::move(noop_lock_), {app_id_},
base::BindOnce(&FetchInstallabilityForChromeManagement::OnAppLockGranted,
weak_factory_.GetWeakPtr()));
}
void FetchInstallabilityForChromeManagement::OnAppLockGranted(
std::unique_ptr<AppLock> app_lock) {
app_lock_ = std::move(app_lock);
if (IsWebContentsDestroyed()) {
GetMutableDebugValue().Set("web_contents_destroyed", true);
CompleteAndSelfDestruct(CommandResult::kSuccess,
InstallableCheckResult::kNotInstallable,
std::nullopt);
return;
}
DCHECK(!app_id_.empty());
InstallableCheckResult result;
if (app_lock_->registrar().IsInstalled(app_id_)) {
result = InstallableCheckResult::kAlreadyInstalled;
} else {
result = InstallableCheckResult::kInstallable;
}
CompleteAndSelfDestruct(CommandResult::kSuccess, result, app_id_);
}
bool FetchInstallabilityForChromeManagement::IsWebContentsDestroyed() {
return !web_contents_ || web_contents_->IsBeingDestroyed();
}
} // namespace web_app