blob: 857a0f8d736426d7b922563a133b3a1bb6c9c7e8 [file] [log] [blame]
// 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.
#include "components/webapps/browser/installable/installable_task.h"
#include "base/containers/contains.h"
#include "components/webapps/browser/installable/installable_manager.h"
#include "content/public/browser/web_contents.h"
#include "third_party/blink/public/common/manifest/manifest_util.h"
namespace webapps {
InstallableTask::InstallableTask(
content::WebContents* web_contents,
base::WeakPtr<InstallableManager> installable_manager,
const InstallableParams& params,
InstallableCallback callback,
InstallablePageData& page_data)
: web_contents_(web_contents->GetWeakPtr()),
manager_(installable_manager),
params_(params),
callback_(std::move(callback)),
page_data_(page_data) {
fetcher_ = std::make_unique<InstallableDataFetcher>(web_contents, page_data);
evaluator_ = std::make_unique<InstallableEvaluator>(
web_contents, page_data, params_.installable_criteria);
}
InstallableTask::InstallableTask(const InstallableParams params,
InstallablePageData& page_data)
: params_(params), page_data_(page_data) {}
InstallableTask::~InstallableTask() = default;
void InstallableTask::Start() {
IncrementStateAndWorkOnNextTask();
}
void InstallableTask::RunCallback() {
if (callback_) {
InstallableData data = {
std::move(errors_),
page_data_->manifest_url(),
page_data_->GetManifest(),
page_data_->WebPageMetadata(),
page_data_->primary_icon_url(),
page_data_->primary_icon(),
page_data_->primary_icon_purpose() ==
blink::mojom::ManifestImageResource_Purpose::MASKABLE,
page_data_->screenshots(),
installability_check_passed_,
};
std::move(callback_).Run(data);
}
}
void InstallableTask::ResetWithError(InstallableStatusCode code) {
// Some callbacks might be already invalidated on certain resets, so we must
// check for that.
// Manifest is assumed to be non-null, so we create an empty one here.
if (callback_) {
blink::mojom::Manifest manifest;
mojom::WebPageMetadata metadata;
std::move(callback_).Run(InstallableData({code}, GURL(), manifest, metadata,
GURL(), nullptr, false,
std::vector<Screenshot>(), false));
}
}
void InstallableTask::IncrementStateAndWorkOnNextTask() {
if ((!errors_.empty() && !params_.is_debug_mode) || state_ == kComplete) {
manager_->OnTaskFinished();
RunCallback();
return;
}
state_++;
CHECK(kInactive < state_ && state_ < kMaxState);
switch (state_) {
case kCheckEligibility:
if (params_.check_eligibility) {
CheckEligibility();
return;
}
break;
case kFetchWebPageMetadata:
if (params_.fetch_metadata) {
fetcher_->FetchWebPageMetadata(base::BindOnce(
&InstallableTask::OnFetchedData, base::Unretained(this)));
return;
}
break;
case kFetchManifest:
fetcher_->FetchManifest(base::BindOnce(&InstallableTask::OnFetchedData,
base::Unretained(this)));
return;
case kCheckInstallability:
CheckInstallability();
return;
case kFetchPrimaryIcon:
if (params_.valid_primary_icon) {
fetcher_->CheckAndFetchBestPrimaryIcon(
base::BindOnce(&InstallableTask::OnFetchedData,
base::Unretained(this)),
params_.prefer_maskable_icon, params_.fetch_favicon);
return;
}
break;
case kFetchScreenshots:
if (params_.fetch_screenshots) {
fetcher_->CheckAndFetchScreenshots(base::BindOnce(
&InstallableTask::OnFetchedData, base::Unretained(this)));
return;
}
break;
}
IncrementStateAndWorkOnNextTask();
}
void InstallableTask::OnFetchedData(InstallableStatusCode error) {
if (error != InstallableStatusCode::NO_ERROR_DETECTED) {
errors_.push_back(error);
}
IncrementStateAndWorkOnNextTask();
}
void InstallableTask::CheckEligibility() {
auto errors = evaluator_->CheckEligibility(web_contents_.get());
if (!errors.empty()) {
errors_.insert(errors_.end(), errors.begin(), errors.end());
}
IncrementStateAndWorkOnNextTask();
}
void InstallableTask::CheckInstallability() {
auto installable_errors = evaluator_->CheckInstallability();
if (installable_errors.has_value()) {
for (auto new_error : installable_errors.value()) {
if (base::Contains(errors_, new_error)) {
// Don't add duplicated errors.
continue;
}
errors_.push_back(new_error);
}
}
installability_check_passed_ =
installable_errors.has_value() && installable_errors->empty();
IncrementStateAndWorkOnNextTask();
}
} // namespace webapps