[go: nahoru, domu]

blob: 77145e6f229b43999b6dc8e37b236cb5a3538666 [file] [log] [blame]
Robbie McElrath6abd1392023-10-10 17:02:301// Copyright 2023 The Chromium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Robbie McElratha9fa38ad2023-10-18 17:46:585#include "chrome/browser/ui/views/web_apps/isolated_web_apps/isolated_web_app_installer_view_controller.h"
Robbie McElrath6abd1392023-10-10 17:02:306
7#include <memory>
Mohamed Mansour2778c1b2023-12-05 18:48:098#include <optional>
Zelin Liu882a2392024-01-10 02:45:389#include <string>
Robbie McElrath6abd1392023-10-10 17:02:3010
Zelin Liuafae5a22023-12-18 22:16:0711#include "base/functional/bind.h"
Robbie McElrath6abd1392023-10-10 17:02:3012#include "base/functional/callback.h"
Zelin Liu882a2392024-01-10 02:45:3813#include "base/logging.h"
Robbie McElrathc213c5a22023-12-08 20:10:1314#include "base/time/time.h"
Zelin Liu882a2392024-01-10 02:45:3815#include "base/uuid.h"
Robbie McElrathaa54e002023-10-30 23:07:1516#include "chrome/browser/profiles/profile.h"
Robbie McElrathc213c5a22023-12-08 20:10:1317#include "chrome/browser/ui/views/web_apps/isolated_web_apps/callback_delayer.h"
Robbie McElratha9fa38ad2023-10-18 17:46:5818#include "chrome/browser/ui/views/web_apps/isolated_web_apps/isolated_web_app_installer_model.h"
19#include "chrome/browser/ui/views/web_apps/isolated_web_apps/isolated_web_app_installer_view.h"
Zelin Liuafae5a22023-12-18 22:16:0720#include "chrome/browser/ui/views/web_apps/isolated_web_apps/pref_observer.h"
Robbie McElrath1923a7b2023-11-10 21:53:2221#include "chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command.h"
Robbie McElrathaa54e002023-10-30 23:07:1522#include "chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_metadata.h"
Robbie McElrath1923a7b2023-11-10 21:53:2223#include "chrome/browser/web_applications/web_app_command_scheduler.h"
Zelin Liu882a2392024-01-10 02:45:3824#include "chrome/browser/web_applications/web_app_install_info.h"
Robbie McElrath6abd1392023-10-10 17:02:3025#include "chrome/browser/web_applications/web_app_provider.h"
26#include "chrome/grit/generated_resources.h"
Robbie McElrath07d866a82023-11-07 23:35:3227#include "components/strings/grit/components_strings.h"
Robbie McElrath6abd1392023-10-10 17:02:3028#include "components/webapps/common/web_app_id.h"
Robbie McElratha001ca92023-11-16 00:32:3929#include "third_party/abseil-cpp/absl/types/variant.h"
Robbie McElrath3afcd962023-10-20 19:18:3630#include "ui/base/l10n/l10n_util.h"
Robbie McElrath6abd1392023-10-10 17:02:3031#include "ui/base/ui_base_types.h"
Robbie McElrath9cffd912024-01-09 02:09:5232#include "ui/gfx/geometry/size.h"
Zelin Liu882a2392024-01-10 02:45:3833#include "ui/gfx/image/image_skia.h"
34#include "ui/gfx/native_widget_types.h"
Robbie McElrath3afcd962023-10-20 19:18:3635#include "ui/strings/grit/ui_strings.h"
Robbie McElrath6abd1392023-10-10 17:02:3036#include "ui/views/view.h"
Zelin Liu882a2392024-01-10 02:45:3837#include "ui/views/widget/widget.h"
Robbie McElrath6abd1392023-10-10 17:02:3038#include "ui/views/window/dialog_delegate.h"
39
Robbie McElrath286cebf2023-11-15 18:10:2640#if BUILDFLAG(IS_CHROMEOS)
41#include "chrome/browser/apps/app_service/app_service_proxy.h"
42#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
43#include "components/services/app_service/public/cpp/app_launch_util.h"
44#include "ui/events/event_constants.h"
45#else
46#include "base/command_line.h"
47#endif // BUILDFLAG(IS_CHROMEOS)
48
Zelin Liu0228b4c2023-11-06 20:47:3149#if BUILDFLAG(IS_CHROMEOS_ASH)
50#include "ash/webui/settings/public/constants/routes.mojom.h"
51#include "chrome/browser/ui/settings_window_manager_chromeos.h"
52#endif // BUILDFLAG(IS_CHROMEOS_ASH)
53
54#if BUILDFLAG(IS_CHROMEOS_LACROS)
55#include "ash/webui/settings/public/constants/routes.mojom.h"
Zelin Liu882a2392024-01-10 02:45:3856#include "chrome/browser/ui/lacros/window_utility.h"
Zelin Liu0228b4c2023-11-06 20:47:3157#include "chrome/common/webui_url_constants.h"
Zelin Liu882a2392024-01-10 02:45:3858#include "chromeos/crosapi/mojom/lacros_shelf_item_tracker.mojom.h"
Zelin Liu0228b4c2023-11-06 20:47:3159#include "chromeos/crosapi/mojom/url_handler.mojom.h"
60#include "chromeos/lacros/lacros_service.h"
61#include "url/gurl.h"
62#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
63
Robbie McElrath6abd1392023-10-10 17:02:3064namespace web_app {
65
66namespace {
67
Robbie McElrathc213c5a22023-12-08 20:10:1368constexpr base::TimeDelta kGetMetadataMinimumDelay = base::Seconds(2);
69constexpr base::TimeDelta kInstallationMinimumDelay = base::Seconds(2);
70constexpr double kProgressBarPausePercentage = 0.8;
71
Robbie McElrath6abd1392023-10-10 17:02:3072// A DialogDelegate that notifies callers when it closes.
73// Accept/Cancel/Close callbacks could be used together to figure out when a
74// dialog closes, but this provides a simpler single callback.
75class OnCompleteDialogDelegate : public views::DialogDelegate {
76 public:
77 ~OnCompleteDialogDelegate() override {
78 if (callback_) {
79 std::move(callback_).Run();
80 }
81 }
82
83 void SetCompleteCallback(base::OnceClosure callback) {
84 callback_ = std::move(callback);
85 }
86
87 private:
88 base::OnceClosure callback_;
89};
90
Zelin Liu882a2392024-01-10 02:45:3891std::string CreateRandomInstanceId() {
92 base::Uuid uuid = base::Uuid::GenerateRandomV4();
93 return uuid.AsLowercaseString();
94}
95
Robbie McElrath6abd1392023-10-10 17:02:3096} // namespace
97
Robbie McElratha001ca92023-11-16 00:32:3998struct IsolatedWebAppInstallerViewController::InstallabilityCheckedVisitor {
99 explicit InstallabilityCheckedVisitor(
100 IsolatedWebAppInstallerModel& model,
101 IsolatedWebAppInstallerViewController& controller)
102 : model_(model), controller_(controller) {}
103
Robbie McElrath19cbe072024-01-13 04:00:19104 void operator()(const InstallabilityChecker::BundleInvalid& invalid) {
Zelin Liu882a2392024-01-10 02:45:38105 LOG(ERROR) << "Isolated Web App bundle installability check failed: "
106 << invalid.error;
Robbie McElrath2851c1c2024-01-13 03:56:04107 model_->SetDialog(IsolatedWebAppInstallerModel::BundleInvalidDialog{});
Robbie McElratha001ca92023-11-16 00:32:39108 controller_->OnModelChanged();
109 }
110
Robbie McElrath19cbe072024-01-13 04:00:19111 void operator()(const InstallabilityChecker::BundleInstallable& installable) {
Zelin Liu882a2392024-01-10 02:45:38112 if (!installable.metadata.icons().empty()) {
113 // Get the last icon from |any|, size doesn't matter since Shelf will
114 // rescale the icon anyway.
115 controller_->SetIcon(gfx::ImageSkia::CreateFrom1xBitmap(
116 installable.metadata.icons()
117 .GetBitmapsForPurpose(IconPurpose::ANY)
118 .rbegin()
119 ->second));
120 controller_->AddOrUpdateWindowToShelf();
121 }
Robbie McElratha001ca92023-11-16 00:32:39122 model_->SetSignedWebBundleMetadata(installable.metadata);
Robbie McElrath7cd5cb62023-11-17 19:00:51123 model_->SetStep(IsolatedWebAppInstallerModel::Step::kShowMetadata);
Robbie McElratha001ca92023-11-16 00:32:39124 controller_->OnModelChanged();
125 }
126
Robbie McElrath19cbe072024-01-13 04:00:19127 void operator()(const InstallabilityChecker::BundleUpdatable& updatable) {
Robbie McElratha001ca92023-11-16 00:32:39128 // TODO(crbug.com/1479140): Handle updates
129 controller_->Close();
130 }
131
Robbie McElrath19cbe072024-01-13 04:00:19132 void operator()(const InstallabilityChecker::BundleOutdated& outdated) {
133 if (outdated.metadata.version() == outdated.installed_version) {
134 model_->SetDialog(
135 IsolatedWebAppInstallerModel::BundleAlreadyInstalledDialog{
136 outdated.metadata.app_name(), outdated.installed_version});
137 } else {
138 model_->SetDialog(IsolatedWebAppInstallerModel::BundleOutdatedDialog{
139 outdated.metadata.app_name(), outdated.metadata.version(),
140 outdated.installed_version});
141 }
142 controller_->OnModelChanged();
Robbie McElratha001ca92023-11-16 00:32:39143 }
144
Robbie McElrath19cbe072024-01-13 04:00:19145 void operator()(const InstallabilityChecker::ProfileShutdown&) {
Robbie McElratha001ca92023-11-16 00:32:39146 controller_->Close();
147 }
148
149 private:
150 raw_ref<IsolatedWebAppInstallerModel> model_;
151 raw_ref<IsolatedWebAppInstallerViewController> controller_;
152};
153
Robbie McElrath6abd1392023-10-10 17:02:30154IsolatedWebAppInstallerViewController::IsolatedWebAppInstallerViewController(
Robbie McElrathaa54e002023-10-30 23:07:15155 Profile* profile,
Robbie McElrath6abd1392023-10-10 17:02:30156 WebAppProvider* web_app_provider,
Zelin Liud3ac79b2024-01-05 03:08:02157 IsolatedWebAppInstallerModel* model,
158 std::unique_ptr<IsolatedWebAppsEnabledPrefObserver> pref_observer)
Zelin Liu882a2392024-01-10 02:45:38159 : instance_id_(CreateRandomInstanceId()),
160 profile_(profile),
Robbie McElrathaa54e002023-10-30 23:07:15161 web_app_provider_(web_app_provider),
Robbie McElrath6abd1392023-10-10 17:02:30162 model_(model),
163 view_(nullptr),
Zelin Liud3ac79b2024-01-05 03:08:02164 dialog_delegate_(nullptr),
165 pref_observer_(std::move(pref_observer)) {
Zelin Liuafae5a22023-12-18 22:16:07166 CHECK(profile_);
167 CHECK(model_);
168 CHECK(web_app_provider_);
Zelin Liud3ac79b2024-01-05 03:08:02169 CHECK(pref_observer_);
Zelin Liuafae5a22023-12-18 22:16:07170}
Robbie McElrath6abd1392023-10-10 17:02:30171
172IsolatedWebAppInstallerViewController::
173 ~IsolatedWebAppInstallerViewController() = default;
174
Zelin Liuafae5a22023-12-18 22:16:07175void IsolatedWebAppInstallerViewController::Start(
176 base::OnceClosure initialized_callback,
177 base::OnceClosure completion_callback) {
178 CHECK(initialized_callback);
179 initialized_callback_ = std::move(initialized_callback);
180
181 CHECK(completion_callback);
182 completion_callback_ = std::move(completion_callback);
183
Zelin Liud3ac79b2024-01-05 03:08:02184 // This callback will be posted asynchronously by the |pref_observer_|:
185 // - Once on `Start()` of `pref_observer_`.
186 // - Every time the pref value is changed.
187 IsolatedWebAppsEnabledPrefObserver::PrefChangedCallback
188 pref_changed_callback = base::BindRepeating(
189 &IsolatedWebAppInstallerViewController::OnPrefChanged,
190 weak_ptr_factory_.GetWeakPtr());
191
192 pref_observer_->Start(pref_changed_callback);
Robbie McElrathaa54e002023-10-30 23:07:15193}
194
Zelin Liu882a2392024-01-10 02:45:38195void IsolatedWebAppInstallerViewController::AddOrUpdateWindowToShelf() {
196 if (!window_) {
197 return;
198 }
199// Currently only supports Lacros.
200// TODO(crbug.com/1515466): Ash Implementation.
201#if BUILDFLAG(IS_CHROMEOS_LACROS)
202 chromeos::LacrosService* lacros_service = chromeos::LacrosService::Get();
203 if (lacros_service->IsAvailable<crosapi::mojom::LacrosShelfItemTracker>()) {
204 std::string window_id =
205 lacros_window_utility::GetRootWindowUniqueId(window_);
206
207 crosapi::mojom::WindowDataPtr window_data =
208 crosapi::mojom::WindowData::New();
209 window_data->item_id = instance_id_;
210 window_data->window_id = window_id;
211 window_data->instance_type =
212 crosapi::mojom::InstanceType::kIsolatedWebAppInstaller;
213 window_data->icon = icon_;
214
215 lacros_service->GetRemote<crosapi::mojom::LacrosShelfItemTracker>()
216 ->AddOrUpdateWindow(std::move(window_data));
217 }
218
219#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
220}
221
222void IsolatedWebAppInstallerViewController::SetIcon(gfx::ImageSkia icon) {
223 icon_ = icon;
224}
225
Zelin Liuafae5a22023-12-18 22:16:07226void IsolatedWebAppInstallerViewController::SetViewForTesting(
227 IsolatedWebAppInstallerView* view) {
228 view_ = view;
229}
230
231void IsolatedWebAppInstallerViewController::Show() {
232 CHECK(is_initialized_) << "Show() is being called before initialized.";
233 CHECK(!view_) << "Show() should not be called twice";
Robbie McElrath6abd1392023-10-10 17:02:30234
Robbie McElrath1f6ce292023-12-08 20:15:42235 auto view = IsolatedWebAppInstallerView::Create(this);
Robbie McElrath6abd1392023-10-10 17:02:30236 view_ = view.get();
Zelin Liuafae5a22023-12-18 22:16:07237
Robbie McElrath6abd1392023-10-10 17:02:30238 std::unique_ptr<views::DialogDelegate> dialog_delegate =
239 CreateDialogDelegate(std::move(view));
240 dialog_delegate_ = dialog_delegate.get();
Robbie McElrath3afcd962023-10-20 19:18:36241
242 OnModelChanged();
243
Zelin Liu79914162024-01-08 22:50:22244 views::Widget* widget =
245 views::DialogDelegate::CreateDialogWidget(std::move(dialog_delegate),
246 /*context=*/nullptr,
247 /*parent=*/nullptr);
248
249 CHECK(!window_);
Zelin Liu79914162024-01-08 22:50:22250 window_ = widget->GetNativeWindow();
Zelin Liu882a2392024-01-10 02:45:38251 AddOrUpdateWindowToShelf();
Zelin Liu79914162024-01-08 22:50:22252
253 widget->Show();
254}
255
256void IsolatedWebAppInstallerViewController::FocusWindow() {
257 if (!window_) {
258 return;
259 }
260
261 auto* widget = views::Widget::GetWidgetForNativeWindow(window_);
262 widget->Activate();
Robbie McElrath6abd1392023-10-10 17:02:30263}
264
Robbie McElrath95b205a2023-11-10 19:01:40265// static
266bool IsolatedWebAppInstallerViewController::OnAcceptWrapper(
267 base::WeakPtr<IsolatedWebAppInstallerViewController> controller) {
268 if (controller) {
269 return controller->OnAccept();
270 }
271 return true;
272}
273
274// Returns true if the dialog should be closed.
275bool IsolatedWebAppInstallerViewController::OnAccept() {
Robbie McElrath95b205a2023-11-10 19:01:40276 switch (model_->step()) {
Robbie McElrath7cd5cb62023-11-17 19:00:51277 case IsolatedWebAppInstallerModel::Step::kShowMetadata: {
Robbie McElrath2851c1c2024-01-13 03:56:04278 model_->SetDialog(IsolatedWebAppInstallerModel::ConfirmInstallationDialog{
Robbie McElrath95b205a2023-11-10 19:01:40279 base::BindRepeating(&IsolatedWebAppInstallerViewController::
Robbie McElrath7cd5cb62023-11-17 19:00:51280 OnShowMetadataLearnMoreClicked,
Robbie McElrath2851c1c2024-01-13 03:56:04281 base::Unretained(this))});
Robbie McElrath95b205a2023-11-10 19:01:40282 OnModelChanged();
283 return false;
284 }
285
Robbie McElrath286cebf2023-11-15 18:10:26286 case IsolatedWebAppInstallerModel::Step::kInstallSuccess: {
287 webapps::AppId app_id = model_->bundle_metadata().app_id();
288#if BUILDFLAG(IS_CHROMEOS)
289 apps::AppServiceProxyFactory::GetForProfile(profile_)->Launch(
290 app_id, ui::EF_NONE, apps::LaunchSource::kFromInstaller,
291 /*window_info=*/nullptr);
292#else
293 web_app_provider_->scheduler().LaunchApp(
294 app_id, *base::CommandLine::ForCurrentProcess(),
295 /*current_directory=*/base::FilePath(),
Mohamed Mansour2778c1b2023-12-05 18:48:09296 /*url_handler_launch_url=*/std::nullopt,
297 /*protocol_handler_launch_url=*/std::nullopt,
298 /*file_launch_url=*/std::nullopt, /*launch_files=*/{},
Robbie McElrath286cebf2023-11-15 18:10:26299 base::DoNothing());
300#endif // BUILDFLAG(IS_CHROMEOS)
301 return true;
302 }
Robbie McElrath4d0a16b02023-11-10 19:57:41303
Robbie McElrath95b205a2023-11-10 19:01:40304 default:
305 NOTREACHED();
306 }
307 return true;
308}
309
310void IsolatedWebAppInstallerViewController::OnComplete() {
311 view_ = nullptr;
312 dialog_delegate_ = nullptr;
Zelin Liuafae5a22023-12-18 22:16:07313 std::move(completion_callback_).Run();
Robbie McElrath95b205a2023-11-10 19:01:40314}
315
316void IsolatedWebAppInstallerViewController::Close() {
317 if (dialog_delegate_) {
318 dialog_delegate_->CancelDialog();
319 }
320}
321
Robbie McElrathc213c5a22023-12-08 20:10:13322void IsolatedWebAppInstallerViewController::OnPrefChanged(bool enabled) {
323 if (enabled) {
324 model_->SetStep(IsolatedWebAppInstallerModel::Step::kGetMetadata);
Arthur Sonzognife132ee2024-01-15 11:01:04325 model_->SetDialog(std::nullopt);
Robbie McElrathc213c5a22023-12-08 20:10:13326 if (!installability_checker_) {
327 callback_delayer_ = std::make_unique<CallbackDelayer>(
328 kGetMetadataMinimumDelay, kProgressBarPausePercentage,
329 base::BindRepeating(&IsolatedWebAppInstallerViewController::
330 OnGetMetadataProgressUpdated,
331 weak_ptr_factory_.GetWeakPtr()));
332 installability_checker_ = InstallabilityChecker::CreateAndStart(
333 profile_, web_app_provider_, model_->bundle_path(),
334 callback_delayer_->StartDelayingCallback(base::BindOnce(
335 &IsolatedWebAppInstallerViewController::OnInstallabilityChecked,
336 weak_ptr_factory_.GetWeakPtr())));
337 }
338 } else {
339 // Disables the installer if the user has not started installation yet.
340 // If IWA is disabled after step::kInstall, we allow installation to
341 // complete and blocks the IWA from launching.
342 if (model_->step() < IsolatedWebAppInstallerModel::Step::kInstall) {
343 model_->SetStep(IsolatedWebAppInstallerModel::Step::kDisabled);
Robbie McElrath2851c1c2024-01-13 03:56:04344 model_->SetDialog(std::nullopt);
Robbie McElrathc213c5a22023-12-08 20:10:13345 installability_checker_.reset();
346 }
347 }
348 OnModelChanged();
Zelin Liuafae5a22023-12-18 22:16:07349 if (!is_initialized_) {
350 is_initialized_ = true;
351 std::move(initialized_callback_).Run();
352 }
Robbie McElrathc213c5a22023-12-08 20:10:13353}
354
355void IsolatedWebAppInstallerViewController::OnGetMetadataProgressUpdated(
356 double progress) {
357 if (view_) {
358 view_->UpdateGetMetadataProgress(progress);
359 }
360}
361
Robbie McElratha001ca92023-11-16 00:32:39362void IsolatedWebAppInstallerViewController::OnInstallabilityChecked(
363 InstallabilityChecker::Result result) {
364 absl::visit(InstallabilityCheckedVisitor(*model_, *this), result);
365}
366
Robbie McElrathc213c5a22023-12-08 20:10:13367void IsolatedWebAppInstallerViewController::OnInstallProgressUpdated(
368 double progress) {
369 if (view_) {
370 view_->UpdateInstallProgress(progress);
371 }
372}
373
Robbie McElrath1923a7b2023-11-10 21:53:22374void IsolatedWebAppInstallerViewController::OnInstallComplete(
375 base::expected<InstallIsolatedWebAppCommandSuccess,
376 InstallIsolatedWebAppCommandError> result) {
377 if (result.has_value()) {
378 model_->SetStep(IsolatedWebAppInstallerModel::Step::kInstallSuccess);
Robbie McElrath9199de322023-11-14 00:47:46379 } else {
Robbie McElrath2851c1c2024-01-13 03:56:04380 model_->SetDialog(IsolatedWebAppInstallerModel::InstallationFailedDialog{});
Robbie McElrath1923a7b2023-11-10 21:53:22381 }
Robbie McElrath9199de322023-11-14 00:47:46382 OnModelChanged();
Robbie McElrath1923a7b2023-11-10 21:53:22383}
384
Robbie McElrath7cd5cb62023-11-17 19:00:51385void IsolatedWebAppInstallerViewController::OnShowMetadataLearnMoreClicked() {
Robbie McElrath95b205a2023-11-10 19:01:40386 // TODO(crbug.com/1479140): Implement
387}
388
Robbie McElrath6abd1392023-10-10 17:02:30389void IsolatedWebAppInstallerViewController::OnSettingsLinkClicked() {
Zelin Liu0228b4c2023-11-06 20:47:31390#if BUILDFLAG(IS_CHROMEOS_ASH)
391 chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(
392 profile_, chromeos::settings::mojom::kManageIsolatedWebAppsSubpagePath);
393#endif // BUILDFLAG(IS_CHROMEOS_ASH)
394
395#if BUILDFLAG(IS_CHROMEOS_LACROS)
396 chromeos::LacrosService* service = chromeos::LacrosService::Get();
397 DCHECK(service->IsAvailable<crosapi::mojom::UrlHandler>());
398
399 GURL manage_isolated_web_apps_subpage_url =
400 GURL(chrome::kChromeUIOSSettingsURL)
401 .Resolve(
402 chromeos::settings::mojom::kManageIsolatedWebAppsSubpagePath);
403 service->GetRemote<crosapi::mojom::UrlHandler>()->OpenUrl(
404 manage_isolated_web_apps_subpage_url);
405#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
Robbie McElrath6abd1392023-10-10 17:02:30406}
407
Robbie McElrath1dcc8a02023-11-06 19:30:54408void IsolatedWebAppInstallerViewController::OnChildDialogCanceled() {
409 // Currently all child dialogs should close the installer when closed.
410 Close();
411}
412
413void IsolatedWebAppInstallerViewController::OnChildDialogAccepted() {
Robbie McElrath6abd1392023-10-10 17:02:30414 switch (model_->step()) {
Robbie McElrath7cd5cb62023-11-17 19:00:51415 case IsolatedWebAppInstallerModel::Step::kShowMetadata: {
Robbie McElrath07d866a82023-11-07 23:35:32416 model_->SetStep(IsolatedWebAppInstallerModel::Step::kInstall);
Robbie McElrath2851c1c2024-01-13 03:56:04417 model_->SetDialog(std::nullopt);
Robbie McElrath07d866a82023-11-07 23:35:32418 OnModelChanged();
Robbie McElrath1923a7b2023-11-10 21:53:22419
Robbie McElrathc213c5a22023-12-08 20:10:13420 callback_delayer_ = std::make_unique<CallbackDelayer>(
421 kInstallationMinimumDelay, kProgressBarPausePercentage,
422 base::BindRepeating(
423 &IsolatedWebAppInstallerViewController::OnInstallProgressUpdated,
424 weak_ptr_factory_.GetWeakPtr()));
Robbie McElrath1923a7b2023-11-10 21:53:22425 const SignedWebBundleMetadata& metadata = model_->bundle_metadata();
426 web_app_provider_->scheduler().InstallIsolatedWebApp(
427 metadata.url_info(), metadata.location(), metadata.version(),
428 /*optional_keep_alive=*/nullptr,
429 /*optional_profile_keep_alive=*/nullptr,
Robbie McElrathc213c5a22023-12-08 20:10:13430 callback_delayer_->StartDelayingCallback(base::BindOnce(
Robbie McElrath1923a7b2023-11-10 21:53:22431 &IsolatedWebAppInstallerViewController::OnInstallComplete,
Robbie McElrathc213c5a22023-12-08 20:10:13432 weak_ptr_factory_.GetWeakPtr())));
Robbie McElrath95b205a2023-11-10 19:01:40433 break;
Robbie McElrath1923a7b2023-11-10 21:53:22434 }
Robbie McElrath6abd1392023-10-10 17:02:30435
Robbie McElrath9199de322023-11-14 00:47:46436 case IsolatedWebAppInstallerModel::Step::kInstall:
437 // A child dialog on the install screen means the installation failed.
438 // Accepting the dialog corresponds to the Retry button.
Robbie McElrath2851c1c2024-01-13 03:56:04439 model_->SetDialog(std::nullopt);
Zelin Liuafae5a22023-12-18 22:16:07440 installability_checker_.reset();
Zelin Liud3ac79b2024-01-05 03:08:02441 pref_observer_->Reset();
Zelin Liuafae5a22023-12-18 22:16:07442 Start(base::DoNothing(), std::move(completion_callback_));
Robbie McElrath9199de322023-11-14 00:47:46443 break;
444
Robbie McElrath6abd1392023-10-10 17:02:30445 default:
446 NOTREACHED();
447 }
Robbie McElrathaa54e002023-10-30 23:07:15448}
449
Robbie McElrath3afcd962023-10-20 19:18:36450void IsolatedWebAppInstallerViewController::OnModelChanged() {
Robbie McElrath1dcc8a02023-11-06 19:30:54451 if (!view_) {
452 return;
453 }
454
Robbie McElrath6abd1392023-10-10 17:02:30455 switch (model_->step()) {
456 case IsolatedWebAppInstallerModel::Step::kDisabled:
Robbie McElrath1dcc8a02023-11-06 19:30:54457 IsolatedWebAppInstallerView::SetDialogButtons(
458 dialog_delegate_, IDS_APP_CLOSE,
Mohamed Mansour2778c1b2023-12-05 18:48:09459 /*accept_button_label_id=*/std::nullopt);
Robbie McElrath6abd1392023-10-10 17:02:30460 view_->ShowDisabledScreen();
461 break;
462
463 case IsolatedWebAppInstallerModel::Step::kGetMetadata:
Robbie McElrath1dcc8a02023-11-06 19:30:54464 IsolatedWebAppInstallerView::SetDialogButtons(
465 dialog_delegate_, IDS_APP_CANCEL,
Mohamed Mansour2778c1b2023-12-05 18:48:09466 /*accept_button_label_id=*/std::nullopt);
Robbie McElrath6abd1392023-10-10 17:02:30467 view_->ShowGetMetadataScreen();
468 break;
469
Robbie McElrath7cd5cb62023-11-17 19:00:51470 case IsolatedWebAppInstallerModel::Step::kShowMetadata:
Robbie McElrath07d866a82023-11-07 23:35:32471 IsolatedWebAppInstallerView::SetDialogButtons(
472 dialog_delegate_, IDS_APP_CANCEL, IDS_INSTALL);
Robbie McElrath6abd1392023-10-10 17:02:30473 view_->ShowMetadataScreen(model_->bundle_metadata());
474 break;
475
476 case IsolatedWebAppInstallerModel::Step::kInstall:
Robbie McElrath678ba8342023-11-08 01:04:59477 IsolatedWebAppInstallerView::SetDialogButtons(
478 dialog_delegate_, IDS_APP_CANCEL,
Mohamed Mansour2778c1b2023-12-05 18:48:09479 /*accept_button_label_id=*/std::nullopt);
Robbie McElrath6abd1392023-10-10 17:02:30480 view_->ShowInstallScreen(model_->bundle_metadata());
481 break;
482
483 case IsolatedWebAppInstallerModel::Step::kInstallSuccess:
Robbie McElrath4d0a16b02023-11-10 19:57:41484 IsolatedWebAppInstallerView::SetDialogButtons(
485 dialog_delegate_, IDS_IWA_INSTALLER_SUCCESS_FINISH,
486 IDS_IWA_INSTALLER_SUCCESS_LAUNCH_APPLICATION);
Robbie McElrath6abd1392023-10-10 17:02:30487 view_->ShowInstallSuccessScreen(model_->bundle_metadata());
488 break;
489 }
Robbie McElrath6abd1392023-10-10 17:02:30490
Robbie McElrath2851c1c2024-01-13 03:56:04491 if (model_->has_dialog()) {
492 view_->ShowDialog(model_->dialog());
Robbie McElrathaa54e002023-10-30 23:07:15493 }
Robbie McElrathaa54e002023-10-30 23:07:15494}
495
Robbie McElrath6abd1392023-10-10 17:02:30496std::unique_ptr<views::DialogDelegate>
497IsolatedWebAppInstallerViewController::CreateDialogDelegate(
498 std::unique_ptr<views::View> contents_view) {
Robbie McElrath9cffd912024-01-09 02:09:52499 gfx::Size contents_max_size = contents_view->GetMaximumSize();
Robbie McElrath6abd1392023-10-10 17:02:30500 auto delegate = std::make_unique<OnCompleteDialogDelegate>();
Robbie McElrath716353772024-01-11 00:47:37501 delegate->set_internal_name(
502 IsolatedWebAppInstallerView::kInstallerWidgetName);
Robbie McElrath6abd1392023-10-10 17:02:30503 delegate->SetOwnedByWidget(true);
504 delegate->SetContentsView(std::move(contents_view));
505 delegate->SetModalType(ui::MODAL_TYPE_WINDOW);
506 delegate->SetShowCloseButton(false);
507 delegate->SetHasWindowSizeControls(false);
Robbie McElrath9cffd912024-01-09 02:09:52508 delegate->SetCanResize(false);
509 delegate->set_fixed_width(contents_max_size.width());
Robbie McElrath6abd1392023-10-10 17:02:30510 // TODO(crbug.com/1479140): Set the title of the dialog for Alt+Tab
Robbie McElrath3afcd962023-10-20 19:18:36511 delegate->SetShowTitle(false);
Robbie McElrath6abd1392023-10-10 17:02:30512
513 delegate->SetAcceptCallbackWithClose(base::BindRepeating(
514 &IsolatedWebAppInstallerViewController::OnAcceptWrapper,
515 weak_ptr_factory_.GetWeakPtr()));
516 delegate->SetCompleteCallback(
517 base::BindOnce(&IsolatedWebAppInstallerViewController::OnComplete,
518 weak_ptr_factory_.GetWeakPtr()));
519 return delegate;
520}
521
522} // namespace web_app