Commit 418ae710 authored by Meilin Wang's avatar Meilin Wang Committed by Commit Bot

[CrOS PhoneHub] Add onboarding UI.

Demo: https://screenshot.googleplex.com/47REAoUwTx7sigJ.png

This CL:
1. Introduces |PhoneHubInterstitialView| with a customized layout that
   can be reused by onboarding, disconnecting/connecting and error
   state UI.
2. Introduces |OnboardingView| which serves as an entry point for
   eligible users to set up the Phone Hub feature.

Remaining work includes implementing the button click handlers.

BUG=1106937,1126208

Change-Id: Ib1b93b47ee1b715c991811b35afdfdc57b2f5c7b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2406662
Commit-Queue: Meilin Wang <meilinw@chromium.org>
Reviewed-by: default avatarMitsuru Oshima <oshima@chromium.org>
Reviewed-by: default avatarTim Song <tengs@chromium.org>
Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#807766}
parent 9f90c933
......@@ -1099,6 +1099,10 @@ component("ash") {
"system/palette/tools/metalayer_mode.h",
"system/phonehub/continue_browsing_chip.cc",
"system/phonehub/continue_browsing_chip.h",
"system/phonehub/onboarding_view.cc",
"system/phonehub/onboarding_view.h",
"system/phonehub/phone_hub_interstitial_view.cc",
"system/phonehub/phone_hub_interstitial_view.h",
"system/phonehub/phone_hub_tray.cc",
"system/phonehub/phone_hub_tray.h",
"system/phonehub/phone_status_view.cc",
......@@ -1605,6 +1609,7 @@ component("ash") {
public_deps = [
"//ash/public/cpp",
"//ash/public/cpp/resources:ash_public_unscaled_resources",
"//ash/public/cpp/vector_icons",
"//ash/resources/vector_icons",
"//ash/strings",
......
......@@ -987,7 +987,18 @@ This file contains the strings for ash.
<message name="IDS_ASH_PHONE_HUB_TASK_CONTINUATION_TITLE" desc="Title of the task continuation section (where users pick up unfinished task left off from their phone, currently only support web browsing) in phone hub bubble.">
Continue browsing
</message>
<message name="IDS_ASH_PHONE_HUB_ONBOARDING_DIALOG_TITLE" desc="The title of the onboarding dialog that pops up for existing multidevice users to ask for permission when the user enables this feature.">
Turn on Phone Hub
</message>
<message name="IDS_ASH_PHONE_HUB_ONBOARDING_DIALOG_DESCRIPTION" desc="The description of the onboarding dialog that pops up for existing multidevice users to ask for permission when the user enables this feature." translateable="false">
View quick actions to extend the phone internet connection, control DND and locate your phone. Also view active Chrome tabs from your phone on your Chromebook.
</message>
<message name="IDS_ASH_PHONE_HUB_ONBOARDING_DIALOG_DISMISS_BUTTON" desc="Dimiss button on the onboarding dialog for user to opt out this feature.">
Dismiss
</message>
<message name="IDS_ASH_PHONE_HUB_ONBOARDING_DIALOG_GET_STARTED_BUTTON" desc="Get started button on the onboarding dialog for user to opt in this feature and start the consent flow.">
Get started
</message>
<message name="IDS_ASH_STYLUS_TOOLS_CAPTURE_REGION_ACTION" desc="Title of the capture region action in the stylus tools (a pop-up panel next to the status tray). This causes a partial screenshot to be taken (the user selects an area of the screen to take a screenshot of).">
Capture region
......
800ae8d74defeb2085d8aef35f359369bd30a44d
\ No newline at end of file
1558a170e9347c34d04793f77b600a66fed0dc63
\ No newline at end of file
521872fe426f822efa2c43a8c5d21dc7c837c36c
\ No newline at end of file
b766203faf43597bb001b2379463fb14e0fd97a7
\ No newline at end of file
......@@ -19,6 +19,7 @@
<include name="IDR_SETTINGS_LOGO_192" file="unscaled_resources/settings_logo_192.png" type="BINDATA" />
<include name="IDR_DISCOVER_APP_192" file="unscaled_resources/discover_app_logo_192.png" type="BINDATA" />
<include name="IDR_RELEASE_NOTES_APP_192" file="unscaled_resources/release_notes_logo_192.png" type="BINDATA" />
<include name="IDR_PHONE_HUB_ONBOARDING_IMAGE" file="unscaled_resources/phone_hub_onboarding_image.png" type="BINDATA" />
</includes>
</release>
</grit>
// Copyright 2020 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 "ash/system/phonehub/onboarding_view.h"
#include <algorithm>
#include <memory>
#include <vector>
#include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_provider.h"
#include "ash/system/phonehub/phone_hub_interstitial_view.h"
#include "ash/system/unified/rounded_label_button.h"
#include "base/strings/string16.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/layout/fill_layout.h"
namespace ash {
namespace {
// Tag value used to uniquely identify the "Dismiss" and "Get started" buttons.
constexpr int kDismissButtonTag = 1;
constexpr int kGetStartedTag = 2;
} // namespace
OnboardingView::OnboardingView() {
SetLayoutManager(std::make_unique<views::FillLayout>());
content_view_ = AddChildView(std::make_unique<PhoneHubInterstitialView>());
// TODO(meilinw): Replace PNG file with vector icon. See
// https://crbug.com/1127996.
gfx::ImageSkia* image =
ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
IDR_PHONE_HUB_ONBOARDING_IMAGE);
content_view_->SetImage(*image);
content_view_->SetTitle(
l10n_util::GetStringUTF16(IDS_ASH_PHONE_HUB_ONBOARDING_DIALOG_TITLE));
content_view_->SetDescription(l10n_util::GetStringUTF16(
IDS_ASH_PHONE_HUB_ONBOARDING_DIALOG_DESCRIPTION));
// Add "Dismiss" and "Get started" buttons.
auto* dismiss = new views::LabelButton(
this, l10n_util::GetStringUTF16(
IDS_ASH_PHONE_HUB_ONBOARDING_DIALOG_DISMISS_BUTTON));
dismiss->SetEnabledTextColors(AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kTextColorPrimary));
dismiss->set_tag(kDismissButtonTag);
auto* get_started = new RoundedLabelButton(
this, l10n_util::GetStringUTF16(
IDS_ASH_PHONE_HUB_ONBOARDING_DIALOG_GET_STARTED_BUTTON));
get_started->set_tag(kGetStartedTag);
content_view_->SetButtons({std::move(dismiss), std::move(get_started)});
}
OnboardingView::~OnboardingView() = default;
void OnboardingView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
// TODO(meilinw): implement button pressed actions.
}
BEGIN_METADATA(OnboardingView, views::View)
END_METADATA
} // namespace ash
// Copyright 2020 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.
#ifndef ASH_SYSTEM_PHONEHUB_ONBOARDING_VIEW_H_
#define ASH_SYSTEM_PHONEHUB_ONBOARDING_VIEW_H_
#include "ash/ash_export.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/metadata/metadata_header_macros.h"
#include "ui/views/view.h"
namespace ash {
class PhoneHubInterstitialView;
// An additional entry point UI to ask the existing multidevice users to opt in
// and set up the Phone feature on this device.
class ASH_EXPORT OnboardingView : public views::View,
public views::ButtonListener {
public:
METADATA_HEADER(OnboardingView);
OnboardingView();
OnboardingView(const OnboardingView&) = delete;
OnboardingView& operator=(const OnboardingView&) = delete;
~OnboardingView() override;
// views::ButtonListener:
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
private:
// The view responsible for displaying the onboarding UI contents.
// Owned by view hierarchy.
PhoneHubInterstitialView* content_view_ = nullptr;
};
} // namespace ash
#endif // ASH_SYSTEM_PHONEHUB_ONBOARDING_VIEW_H_
// Copyright 2020 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 "ash/system/phonehub/phone_hub_interstitial_view.h"
#include <memory>
#include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/tray/tray_popup_item_style.h"
#include "ash/system/unified/rounded_label_button.h"
#include "base/strings/string16.h"
#include "skia/ext/image_operations.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/grid_layout.h"
namespace ash {
namespace {
// Appearance.
// TODO(meilinw): Update those constants to spec.
constexpr int kImageWidthDip = 330;
constexpr int kImageHeightDip = 200;
constexpr int kDialogContentWidthDip = 330;
constexpr int kHorizontalPaddingDip = 20;
constexpr int kVerticalPaddingDip = 20;
constexpr int kTitleBottomPaddingDip = 10;
constexpr int kButtonSpacingDip = 10;
constexpr int kButtonContainerTopPaddingDip = 45;
// Adds a ColumnSet on |layout| with a single View column and padding columns
// on either side of it with |padding| width.
void AddColumnWithSidePadding(views::GridLayout* layout, int padding, int id) {
views::ColumnSet* column_set = layout->AddColumnSet(id);
column_set->AddPaddingColumn(views::GridLayout::kFixedSize, padding);
column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER,
views::GridLayout::kFixedSize,
views::GridLayout::ColumnSize::kFixed,
kDialogContentWidthDip, 0);
column_set->AddPaddingColumn(views::GridLayout::kFixedSize, padding);
}
} // namespace
PhoneHubInterstitialView::PhoneHubInterstitialView() {
InitLayout();
}
PhoneHubInterstitialView::~PhoneHubInterstitialView() = default;
void PhoneHubInterstitialView::SetImage(const gfx::ImageSkia& image) {
// Expect a non-empty string for the title.
DCHECK(!image.isNull());
image_->SetImage(image);
}
void PhoneHubInterstitialView::SetTitle(const base::string16& title) {
// Expect a non-empty string for the title.
DCHECK(!title.empty());
title_->SetText(title);
}
void PhoneHubInterstitialView::SetDescription(const base::string16& desc) {
// Expect a non-empty string for the description.
DCHECK(!desc.empty());
description_->SetText(desc);
}
void PhoneHubInterstitialView::SetButtons(
const std::vector<views::Button*>& buttons) {
for (auto* button : buttons)
button_container_->AddChildView(std::move(button));
}
void PhoneHubInterstitialView::InitLayout() {
SetPaintToLayer();
layer()->SetFillsBoundsOpaquely(false);
// Set up layout column.
views::GridLayout* layout =
SetLayoutManager(std::make_unique<views::GridLayout>());
const int kColumnSetId = 0;
AddColumnWithSidePadding(layout, kHorizontalPaddingDip, kColumnSetId);
// Set up layout row for the image view.
layout->StartRow(views::GridLayout::kFixedSize, kColumnSetId);
image_ = layout->AddView(std::make_unique<views::ImageView>());
image_->SetImageSize(gfx::Size(kImageWidthDip, kImageHeightDip));
// Set up layout row for the title view, which should be left-aligned.
layout->StartRow(views::GridLayout::kFixedSize, kColumnSetId);
title_ =
layout->AddView(std::make_unique<views::Label>(), 1, 1,
views::GridLayout::LEADING, views::GridLayout::CENTER);
TrayPopupItemStyle title_style(TrayPopupItemStyle::FontStyle::SUB_HEADER);
title_style.SetupLabel(title_);
// Set up layout row for the multi-line description view.
layout->StartRowWithPadding(views::GridLayout::kFixedSize, kColumnSetId,
views::GridLayout::kFixedSize,
kTitleBottomPaddingDip);
description_ = layout->AddView(std::make_unique<views::Label>());
TrayPopupItemStyle body_style(
TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL);
body_style.SetupLabel(description_);
description_->SetMultiLine(true);
description_->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
// Set up the layout row for the button container view, which should be
// right-aligned.
layout->StartRowWithPadding(views::GridLayout::kFixedSize, kColumnSetId,
views::GridLayout::kFixedSize,
kButtonContainerTopPaddingDip);
button_container_ =
layout->AddView(std::make_unique<views::View>(), 1, 1,
views::GridLayout::TRAILING, views::GridLayout::CENTER);
button_container_->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal, gfx::Insets(),
kButtonSpacingDip));
// Set up the layout row for the bottom spacing.
layout->AddPaddingRow(views::GridLayout::kFixedSize, kVerticalPaddingDip);
}
BEGIN_METADATA(PhoneHubInterstitialView, views::View)
END_METADATA
} // namespace ash
// Copyright 2020 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.
#ifndef ASH_SYSTEM_PHONEHUB_PHONE_HUB_INTERSTITIAL_VIEW_H_
#define ASH_SYSTEM_PHONEHUB_PHONE_HUB_INTERSTITIAL_VIEW_H_
#include <vector>
#include "ash/ash_export.h"
#include "ui/views/metadata/metadata_header_macros.h"
#include "ui/views/view.h"
namespace views {
class Button;
class ImageView;
class ImageSkia;
class Label;
} // namespace views
namespace ash {
// A interstitial view for Phone Hub with a customized layout that can be shared
// by the initial onboarding, connecting/disconnecting and error state UI.
class ASH_EXPORT PhoneHubInterstitialView : public views::View {
public:
METADATA_HEADER(PhoneHubInterstitialView);
PhoneHubInterstitialView();
PhoneHubInterstitialView(const PhoneHubInterstitialView&) = delete;
PhoneHubInterstitialView& operator=(const PhoneHubInterstitialView&) = delete;
~PhoneHubInterstitialView() override;
void SetImage(const gfx::ImageSkia& image);
void SetTitle(const base::string16& title);
void SetDescription(const base::string16& desc);
void SetButtons(const std::vector<views::Button*>& buttons);
private:
void InitLayout();
views::ImageView* image_ = nullptr;
views::Label* title_ = nullptr;
views::Label* description_ = nullptr;
views::View* button_container_ = nullptr;
};
} // namespace ash
#endif // ASH_SYSTEM_PHONEHUB_PHONE_HUB_INTERSTITIAL_VIEW_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment