blob: e37149a1e62db6350f82ee8669b73bb782f7e0d5 [file] [log] [blame]
// 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/ui/views/plugin_vm/plugin_vm_launcher_view.h"
#include <memory>
#include "base/optional.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager.h"
#include "chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager_factory.h"
#include "chrome/browser/chromeos/plugin_vm/plugin_vm_util.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/grit/chrome_unscaled_resources.h"
#include "chrome/grit/generated_resources.h"
#include "content/public/browser/browser_thread.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/text/bytes_formatting.h"
#include "ui/chromeos/devicetype_utils.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/border.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/progress_bar.h"
#include "ui/views/layout/box_layout.h"
namespace {
PluginVmLauncherView* g_plugin_vm_launcher_view = nullptr;
base::Optional<double> GetFractionComplete(int64_t bytes_processed,
int64_t bytes_to_be_processed) {
if (bytes_to_be_processed == -1 || bytes_to_be_processed == 0)
return base::nullopt;
double fraction_complete =
static_cast<double>(bytes_processed) / bytes_to_be_processed;
if (fraction_complete < 0.0 || fraction_complete > 1.0)
return base::nullopt;
return base::make_optional(fraction_complete);
}
} // namespace
void plugin_vm::ShowPluginVmLauncherView(Profile* profile) {
if (!g_plugin_vm_launcher_view) {
g_plugin_vm_launcher_view = new PluginVmLauncherView(profile);
views::DialogDelegate::CreateDialogWidget(g_plugin_vm_launcher_view,
nullptr, nullptr);
}
g_plugin_vm_launcher_view->GetWidget()->Show();
}
PluginVmLauncherView::PluginVmLauncherView(Profile* profile)
: plugin_vm_image_manager_(
plugin_vm::PluginVmImageManagerFactory::GetForProfile(profile)) {
constexpr gfx::Size kLogoImageSize(32, 32);
const ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::kVertical,
provider->GetInsetsMetric(views::InsetsMetric::INSETS_DIALOG)));
views::ImageView* logo_image = new views::ImageView();
logo_image->SetImageSize(kLogoImageSize);
logo_image->SetImage(
ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
IDR_LOGO_PLUGIN_VM_DEFAULT_32));
logo_image->SetHorizontalAlignment(views::ImageView::LEADING);
AddChildView(logo_image);
big_message_label_ =
new views::Label(GetBigMessage(), views::style::CONTEXT_DIALOG_TITLE);
big_message_label_->SetMultiLine(true);
big_message_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
AddChildView(big_message_label_);
message_label_ = new views::Label();
message_label_->SetMultiLine(true);
message_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
AddChildView(message_label_);
progress_bar_ = new views::ProgressBar();
progress_bar_->SetVisible(false);
AddChildView(progress_bar_);
big_image_ = new views::ImageView();
big_image_->SetImage(
ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
IDR_PLUGIN_VM_LAUNCHER));
big_image_->SetHorizontalAlignment(views::ImageView::CENTER);
AddChildView(big_image_);
}
int PluginVmLauncherView::GetDialogButtons() const {
switch (state_) {
case State::START_DOWNLOADING:
case State::DOWNLOADING:
case State::UNZIPPING:
return ui::DIALOG_BUTTON_CANCEL;
case State::FINISHED:
return ui::DIALOG_BUTTON_OK;
case State::ERROR:
return ui::DIALOG_BUTTON_CANCEL | ui::DIALOG_BUTTON_OK;
}
}
base::string16 PluginVmLauncherView::GetDialogButtonLabel(
ui::DialogButton button) const {
switch (state_) {
case State::START_DOWNLOADING:
case State::DOWNLOADING:
case State::UNZIPPING: {
DCHECK_EQ(button, ui::DIALOG_BUTTON_CANCEL);
return l10n_util::GetStringUTF16(IDS_APP_CANCEL);
}
case State::FINISHED: {
DCHECK_EQ(button, ui::DIALOG_BUTTON_OK);
return l10n_util::GetStringUTF16(IDS_PLUGIN_VM_LAUNCHER_LAUNCH_BUTTON);
}
case State::ERROR: {
return l10n_util::GetStringUTF16(button == ui::DIALOG_BUTTON_OK
? IDS_PLUGIN_VM_LAUNCHER_RETRY_BUTTON
: IDS_APP_CANCEL);
}
}
}
bool PluginVmLauncherView::ShouldShowWindowTitle() const {
return false;
}
bool PluginVmLauncherView::Accept() {
if (state_ == State::FINISHED) {
// Launch button has been clicked.
// TODO(https://crbug.com/904852): Launch PluginVm.
return true;
}
DCHECK_EQ(state_, State::ERROR);
// Retry button has been clicked to retry setting of PluginVm environment
// after error occurred.
StartPluginVmImageDownload();
return false;
}
bool PluginVmLauncherView::Cancel() {
if (state_ == State::DOWNLOADING)
plugin_vm_image_manager_->CancelDownload();
if (state_ == State::UNZIPPING)
plugin_vm_image_manager_->CancelUnzipping();
return true;
}
gfx::Size PluginVmLauncherView::CalculatePreferredSize() const {
const int width = ChromeLayoutProvider::Get()->GetDistanceMetric(
DISTANCE_LARGE_MODAL_DIALOG_PREFERRED_WIDTH);
return gfx::Size(width,
GetLayoutManager()->GetPreferredHeightForWidth(this, width));
}
void PluginVmLauncherView::OnDownloadStarted() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
}
void PluginVmLauncherView::OnDownloadProgressUpdated(uint64_t bytes_downloaded,
int64_t content_length) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK_EQ(state_, State::DOWNLOADING);
base::Optional<double> fraction_complete =
GetFractionComplete(bytes_downloaded, content_length);
if (fraction_complete.has_value())
progress_bar_->SetValue(fraction_complete.value());
else
progress_bar_->SetValue(-1);
}
void PluginVmLauncherView::OnDownloadCompleted() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK_EQ(state_, State::DOWNLOADING);
plugin_vm_image_manager_->StartUnzipping();
state_ = State::UNZIPPING;
OnStateUpdated();
}
void PluginVmLauncherView::OnDownloadCancelled() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
}
void PluginVmLauncherView::OnDownloadFailed() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
state_ = State::ERROR;
OnStateUpdated();
}
void PluginVmLauncherView::OnUnzippingProgressUpdated(
int64_t bytes_unzipped,
int64_t plugin_vm_image_size) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK_EQ(state_, State::UNZIPPING);
base::Optional<double> fraction_complete =
GetFractionComplete(bytes_unzipped, plugin_vm_image_size);
if (fraction_complete.has_value())
progress_bar_->SetValue(fraction_complete.value());
else
progress_bar_->SetValue(-1);
}
void PluginVmLauncherView::OnUnzipped() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK_EQ(state_, State::UNZIPPING);
state_ = State::FINISHED;
OnStateUpdated();
}
void PluginVmLauncherView::OnUnzippingFailed() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
state_ = State::ERROR;
OnStateUpdated();
}
base::string16 PluginVmLauncherView::GetBigMessage() {
switch (state_) {
case State::START_DOWNLOADING:
case State::DOWNLOADING:
case State::UNZIPPING:
return l10n_util::GetStringUTF16(
IDS_PLUGIN_VM_LAUNCHER_ENVIRONMENT_SETTING_TITLE);
case State::FINISHED:
return l10n_util::GetStringUTF16(IDS_PLUGIN_VM_LAUNCHER_FINISHED_TITLE);
case State::ERROR:
return l10n_util::GetStringUTF16(IDS_PLUGIN_VM_LAUNCHER_ERROR_TITLE);
}
}
PluginVmLauncherView::~PluginVmLauncherView() {
plugin_vm_image_manager_->RemoveObserver();
g_plugin_vm_launcher_view = nullptr;
}
void PluginVmLauncherView::AddedToWidget() {
StartPluginVmImageDownload();
}
void PluginVmLauncherView::OnStateUpdated() {
DialogModelChanged();
SetBigMessageLabel();
SetMessageLabel();
SetBigImage();
const bool progress_bar_visible =
state_ == State::DOWNLOADING || state_ == State::UNZIPPING;
progress_bar_->SetVisible(progress_bar_visible);
// Values outside the range [0,1] display an infinite loading animation.
progress_bar_->SetValue(-1);
GetWidget()->SetSize(GetWidget()->non_client_view()->GetPreferredSize());
}
base::string16 PluginVmLauncherView::GetMessage() const {
switch (state_) {
case State::START_DOWNLOADING:
case State::FINISHED:
return base::string16();
case State::DOWNLOADING:
return l10n_util::GetStringUTF16(
IDS_PLUGIN_VM_LAUNCHER_DOWNLOADING_MESSAGE);
case State::UNZIPPING:
return l10n_util::GetStringUTF16(
IDS_PLUGIN_VM_LAUNCHER_UNZIPPING_MESSAGE);
case State::ERROR:
return l10n_util::GetStringUTF16(IDS_PLUGIN_VM_LAUNCHER_ERROR_MESSAGE);
}
}
void PluginVmLauncherView::SetBigMessageLabel() {
big_message_label_->SetText(GetBigMessage());
big_message_label_->SetVisible(true);
}
void PluginVmLauncherView::SetMessageLabel() {
base::string16 message = GetMessage();
const bool message_visible = !message.empty();
message_label_->SetVisible(message_visible);
message_label_->SetText(message);
}
void PluginVmLauncherView::SetBigImage() {
if (state_ == State::ERROR) {
big_image_->SetImage(
ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
IDR_PLUGIN_VM_LAUNCHER_ERROR));
return;
}
big_image_->SetImage(
ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
IDR_PLUGIN_VM_LAUNCHER));
}
void PluginVmLauncherView::StartPluginVmImageDownload() {
plugin_vm_image_manager_->SetObserver(this);
plugin_vm_image_manager_->StartDownload();
state_ = State::DOWNLOADING;
OnStateUpdated();
}