Skip to content

Commit

Permalink
iwa: Add InstallabilityChecker to IWA installer UI
Browse files Browse the repository at this point in the history
InstallabilityChecker is a helper class that encapsulates
IsolatedWebAppUrlInfo and SignedWebBundleMetadata creation, and the
CheckIsolatedWebAppBundleInstallability call, and is called by the UI's
ViewController when it is started.

This has several other changes to the UI to make testing easier. In
particular the ViewController can now be Start()ed without being
Show()n to simulate running through the UI without creating the real
View.

Bug: 1479140
Change-Id: I90493212de48f794f907e5c8a60ac30655eb82af
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4977278
Reviewed-by: Zelin Liu <zelin@chromium.org>
Commit-Queue: Robbie McElrath <rmcelrath@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1217254}
  • Loading branch information
robbiemc authored and Chromium LUCI CQ committed Oct 30, 2023
1 parent e3ce112 commit aa54e00
Show file tree
Hide file tree
Showing 12 changed files with 524 additions and 28 deletions.
2 changes: 2 additions & 0 deletions chrome/browser/ui/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -5895,6 +5895,8 @@ static_library("ui") {
"views/web_apps/frame_toolbar/web_app_toolbar_button_container.h",
"views/web_apps/frame_toolbar/window_controls_overlay_toggle_button.cc",
"views/web_apps/frame_toolbar/window_controls_overlay_toggle_button.h",
"views/web_apps/isolated_web_apps/installability_checker.cc",
"views/web_apps/isolated_web_apps/installability_checker.h",
"views/web_apps/isolated_web_apps/isolated_web_app_installer_coordinator.cc",
"views/web_apps/isolated_web_apps/isolated_web_app_installer_coordinator.h",
"views/web_apps/isolated_web_apps/isolated_web_app_installer_model.cc",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// 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 "chrome/browser/ui/views/web_apps/isolated_web_apps/installability_checker.h"

#include <memory>
#include <string>

#include "base/functional/callback.h"
#include "base/memory/ptr_util.h"
#include "base/types/expected.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/web_applications/isolated_web_apps/check_isolated_web_app_bundle_installability_command.h"
#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_location.h"
#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
#include "chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_metadata.h"
#include "chrome/browser/web_applications/web_app_command_scheduler.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "third_party/abseil-cpp/absl/types/optional.h"

namespace web_app {

namespace {
using InstallabilityCheckResult =
CheckIsolatedWebAppBundleInstallabilityCommand::InstallabilityCheckResult;
} // namespace

// static
std::unique_ptr<InstallabilityChecker> InstallabilityChecker::CreateAndStart(
Profile* profile,
WebAppProvider* web_app_provider,
const base::FilePath& bundle_path,
Delegate* delegate) {
std::unique_ptr<InstallabilityChecker> checker = base::WrapUnique(
new InstallabilityChecker(profile, web_app_provider, delegate));
checker->Start(bundle_path);
return checker;
}

InstallabilityChecker::~InstallabilityChecker() = default;

InstallabilityChecker::InstallabilityChecker(Profile* profile,
WebAppProvider* web_app_provider,
Delegate* delegate)
: profile_(profile),
web_app_provider_(web_app_provider),
delegate_(delegate) {
CHECK(profile_);
CHECK(web_app_provider_);
CHECK(delegate_);
}

void InstallabilityChecker::Start(const base::FilePath& bundle_path) {
IsolatedWebAppLocation location = DevModeBundle{bundle_path};
IsolatedWebAppUrlInfo::CreateFromIsolatedWebAppLocation(
location, base::BindOnce(&InstallabilityChecker::OnLoadedUrlInfo,
weak_ptr_factory_.GetWeakPtr(), location));
}

void InstallabilityChecker::OnLoadedUrlInfo(
IsolatedWebAppLocation location,
base::expected<IsolatedWebAppUrlInfo, std::string> url_info) {
if (!url_info.has_value()) {
delegate_->OnBundleInvalid(url_info.error());
return;
}
SignedWebBundleMetadata::Create(
profile_, web_app_provider_, url_info.value(), location,
base::BindOnce(&InstallabilityChecker::OnLoadedMetadata,
weak_ptr_factory_.GetWeakPtr()));
}

void InstallabilityChecker::OnLoadedMetadata(
base::expected<SignedWebBundleMetadata, std::string> metadata) {
if (!metadata.has_value()) {
delegate_->OnBundleInvalid(metadata.error());
return;
}
web_app_provider_->scheduler().CheckIsolatedWebAppBundleInstallability(
metadata.value(),
base::BindOnce(&InstallabilityChecker::OnInstallabilityChecked,
weak_ptr_factory_.GetWeakPtr(), metadata.value()));
}

void InstallabilityChecker::OnInstallabilityChecked(
SignedWebBundleMetadata metadata,
InstallabilityCheckResult installability_check_result,
absl::optional<base::Version> installed_version) {
switch (installability_check_result) {
case InstallabilityCheckResult::kInstallable:
delegate_->OnBundleInstallable(metadata);
return;
case InstallabilityCheckResult::kUpdatable:
CHECK(installed_version.has_value());
delegate_->OnBundleUpdatable(metadata, installed_version.value());
return;
case InstallabilityCheckResult::kOutdated:
CHECK(installed_version.has_value());
delegate_->OnBundleOutdated(metadata, installed_version.value());
return;
case InstallabilityCheckResult::kShutdown:
delegate_->OnProfileShutdown();
return;
}
}

} // namespace web_app
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// 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.

#ifndef CHROME_BROWSER_UI_VIEWS_WEB_APPS_ISOLATED_WEB_APPS_INSTALLABILITY_CHECKER_H_
#define CHROME_BROWSER_UI_VIEWS_WEB_APPS_ISOLATED_WEB_APPS_INSTALLABILITY_CHECKER_H_

#include <memory>
#include <string>

#include "base/memory/weak_ptr.h"
#include "base/types/expected.h"
#include "chrome/browser/web_applications/isolated_web_apps/check_isolated_web_app_bundle_installability_command.h"
#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_location.h"
#include "third_party/abseil-cpp/absl/types/optional.h"

class Profile;

namespace base {
class FilePath;
class Version;
} // namespace base

namespace web_app {

class IsolatedWebAppUrlInfo;
class SignedWebBundleMetadata;
class WebAppProvider;

class InstallabilityChecker {
public:
class Delegate {
public:
virtual void OnProfileShutdown() = 0;
virtual void OnBundleInvalid(const std::string& error) = 0;
virtual void OnBundleInstallable(
const SignedWebBundleMetadata& metadata) = 0;
virtual void OnBundleUpdatable(const SignedWebBundleMetadata& metadata,
const base::Version& installed_version) = 0;
virtual void OnBundleOutdated(const SignedWebBundleMetadata& metadata,
const base::Version& installed_version) = 0;
};

static std::unique_ptr<InstallabilityChecker> CreateAndStart(
Profile* profile,
WebAppProvider* web_app_provider,
const base::FilePath& bundle_path,
Delegate* delegate);

~InstallabilityChecker();

private:
InstallabilityChecker(Profile* profile,
WebAppProvider* web_app_provider,
Delegate* delegate);

void Start(const base::FilePath& bundle_path);
void OnLoadedUrlInfo(
IsolatedWebAppLocation location,
base::expected<IsolatedWebAppUrlInfo, std::string> url_info);
void OnLoadedMetadata(
base::expected<SignedWebBundleMetadata, std::string> metadata);
void OnInstallabilityChecked(
SignedWebBundleMetadata metadata,
CheckIsolatedWebAppBundleInstallabilityCommand::InstallabilityCheckResult
installability_check_result,
absl::optional<base::Version> installed_version);

raw_ptr<Profile> profile_;
raw_ptr<WebAppProvider> web_app_provider_;
raw_ptr<Delegate> delegate_;
base::WeakPtrFactory<InstallabilityChecker> weak_ptr_factory_{this};
};

} // namespace web_app

#endif // CHROME_BROWSER_UI_VIEWS_WEB_APPS_ISOLATED_WEB_APPS_INSTALLABILITY_CHECKER_H_
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ IsolatedWebAppInstallerCoordinator::IsolatedWebAppInstallerCoordinator(
const base::FilePath& bundle_path)
: model_(std::make_unique<IsolatedWebAppInstallerModel>(bundle_path)),
controller_(std::make_unique<IsolatedWebAppInstallerViewController>(
profile,
WebAppProvider::GetForWebApps(profile),
model_.get())) {}

Expand All @@ -44,6 +45,7 @@ IsolatedWebAppInstallerCoordinator::~IsolatedWebAppInstallerCoordinator() =

void IsolatedWebAppInstallerCoordinator::Show(
base::OnceCallback<void(absl::optional<webapps::AppId>)> callback) {
controller_->Start();
controller_->Show(
base::BindOnce(&IsolatedWebAppInstallerCoordinator::OnDialogClosed,
base::Unretained(this), std::move(callback)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,7 @@ BEGIN_METADATA(DisabledScreen, InstallerScreenView)
END_METADATA

IsolatedWebAppInstallerView::IsolatedWebAppInstallerView(Delegate* delegate)
: delegate_(delegate), screen_(nullptr) {
views::LayoutProvider* provider = views::LayoutProvider::Get();
SetInsideBorderInsets(
provider->GetInsetsMetric(views::InsetsMetric::INSETS_DIALOG));
}
: delegate_(delegate), screen_(nullptr), initialized_(false) {}

IsolatedWebAppInstallerView::~IsolatedWebAppInstallerView() = default;

Expand Down Expand Up @@ -229,6 +225,13 @@ void IsolatedWebAppInstallerView::ShowInstallSuccessScreen(

void IsolatedWebAppInstallerView::ShowScreen(
std::unique_ptr<InstallerScreenView> screen) {
if (!initialized_) {
initialized_ = true;
views::LayoutProvider* provider = views::LayoutProvider::Get();
SetInsideBorderInsets(
provider->GetInsetsMetric(views::InsetsMetric::INSETS_DIALOG));
}

if (screen_) {
RemoveChildView(screen_);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,23 +40,27 @@ class IsolatedWebAppInstallerView : public views::BoxLayoutView {
explicit IsolatedWebAppInstallerView(Delegate* delegate);
~IsolatedWebAppInstallerView() override;

void ShowDisabledScreen();
virtual void ShowDisabledScreen();

void ShowGetMetadataScreen();
void UpdateGetMetadataProgress(double percent, int minutes_remaining);
virtual void ShowGetMetadataScreen();
virtual void UpdateGetMetadataProgress(double percent, int minutes_remaining);

void ShowMetadataScreen(const SignedWebBundleMetadata& bundle_metadata);
virtual void ShowMetadataScreen(
const SignedWebBundleMetadata& bundle_metadata);

void ShowInstallScreen(const SignedWebBundleMetadata& bundle_metadata);
void UpdateInstallProgress(double percent, int minutes_remaining);
virtual void ShowInstallScreen(
const SignedWebBundleMetadata& bundle_metadata);
virtual void UpdateInstallProgress(double percent, int minutes_remaining);

void ShowInstallSuccessScreen(const SignedWebBundleMetadata& bundle_metadata);
virtual void ShowInstallSuccessScreen(
const SignedWebBundleMetadata& bundle_metadata);

private:
void ShowScreen(std::unique_ptr<InstallerScreenView> screen);

raw_ptr<Delegate> delegate_;
raw_ptr<InstallerScreenView> screen_;
bool initialized_;
};

} // namespace web_app
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "base/files/file_path.h"
#include "base/functional/callback_helpers.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/test/pixel_test_configuration_mixin.h"
#include "chrome/browser/ui/test/test_browser_dialog.h"
Expand Down Expand Up @@ -59,8 +60,9 @@ class IsolatedWebAppInstallerViewUiPixelTest
IsolatedWebAppInstallerModel model{base::FilePath()};
model.SetStep(GetParam().step);

Profile* profile = browser()->profile();
IsolatedWebAppInstallerViewController controller{
WebAppProvider::GetForWebApps(browser()->profile()), &model};
profile, WebAppProvider::GetForWebApps(profile), &model};
controller.Show(base::DoNothing());
}

Expand Down

0 comments on commit aa54e00

Please sign in to comment.