Andre Le | ed1afef | 2020-09-11 01:06:55 | [diff] [blame] | 1 | // Copyright 2020 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "ash/system/phonehub/continue_browsing_chip.h" |
Andre Le | 63ca8fe | 2020-09-21 21:35:34 | [diff] [blame] | 6 | |
| 7 | #include "ash/public/cpp/new_window_delegate.h" |
Tim Song | baea059 | 2020-11-12 19:55:33 | [diff] [blame] | 8 | #include "ash/resources/vector_icons/vector_icons.h" |
Andre Le | 63ca8fe | 2020-09-21 21:35:34 | [diff] [blame] | 9 | #include "ash/root_window_controller.h" |
| 10 | #include "ash/shell.h" |
Jimmy Gong | 776ab1f | 2020-12-03 06:16:25 | [diff] [blame] | 11 | #include "ash/strings/grit/ash_strings.h" |
Andre Le | ed1afef | 2020-09-11 01:06:55 | [diff] [blame] | 12 | #include "ash/style/ash_color_provider.h" |
Tim Song | 97824893 | 2020-10-27 19:47:41 | [diff] [blame] | 13 | #include "ash/system/phonehub/phone_hub_metrics.h" |
Andre Le | 63ca8fe | 2020-09-21 21:35:34 | [diff] [blame] | 14 | #include "ash/system/phonehub/phone_hub_tray.h" |
| 15 | #include "ash/system/status_area_widget.h" |
Jimmy Gong | 776ab1f | 2020-12-03 06:16:25 | [diff] [blame] | 16 | #include "base/strings/string_number_conversions.h" |
Andre Le | 63ca8fe | 2020-09-21 21:35:34 | [diff] [blame] | 17 | #include "base/strings/utf_string_conversions.h" |
| 18 | #include "chromeos/components/multidevice/logging/logging.h" |
Kyle Horimoto | ae02ab3 | 2020-12-11 00:35:47 | [diff] [blame] | 19 | #include "chromeos/components/phonehub/user_action_recorder.h" |
Jimmy Gong | 776ab1f | 2020-12-03 06:16:25 | [diff] [blame] | 20 | #include "ui/base/l10n/l10n_util.h" |
Tim Song | baea059 | 2020-11-12 19:55:33 | [diff] [blame] | 21 | #include "ui/gfx/paint_vector_icon.h" |
Meilin Wang | 9fc2c04 | 2020-10-06 22:26:53 | [diff] [blame] | 22 | #include "ui/views/controls/highlight_path_generator.h" |
Andre Le | 63ca8fe | 2020-09-21 21:35:34 | [diff] [blame] | 23 | #include "ui/views/controls/image_view.h" |
Andre Le | ed1afef | 2020-09-11 01:06:55 | [diff] [blame] | 24 | #include "ui/views/controls/label.h" |
| 25 | #include "ui/views/layout/box_layout.h" |
| 26 | |
| 27 | namespace ash { |
| 28 | |
| 29 | namespace { |
| 30 | |
Meilin Wang | 24f7cf8 | 2020-10-26 23:13:12 | [diff] [blame] | 31 | // Appearance in dip. |
| 32 | constexpr gfx::Insets kContinueBrowsingChipInsets(8, 8); |
| 33 | constexpr int kContinueBrowsingChipSpacing = 8; |
| 34 | constexpr int kContinueBrowsingChipFaviconSpacing = 8; |
| 35 | constexpr gfx::Size kContinueBrowsingChipFaviconSize(16, 16); |
| 36 | constexpr int kTaskContinuationChipRadius = 8; |
Andre Le | 63ca8fe | 2020-09-21 21:35:34 | [diff] [blame] | 37 | constexpr int kTitleMaxLines = 2; |
Andre Le | ed1afef | 2020-09-11 01:06:55 | [diff] [blame] | 38 | |
| 39 | } // namespace |
| 40 | |
Andre Le | 63ca8fe | 2020-09-21 21:35:34 | [diff] [blame] | 41 | ContinueBrowsingChip::ContinueBrowsingChip( |
Tim Song | 97824893 | 2020-10-27 19:47:41 | [diff] [blame] | 42 | const chromeos::phonehub::BrowserTabsModel::BrowserTabMetadata& metadata, |
Jimmy Gong | 776ab1f | 2020-12-03 06:16:25 | [diff] [blame] | 43 | int index, |
Kyle Horimoto | ae02ab3 | 2020-12-11 00:35:47 | [diff] [blame] | 44 | size_t total_count, |
| 45 | chromeos::phonehub::UserActionRecorder* user_action_recorder) |
Peter Kasting | 5aacfd49 | 2020-10-31 03:33:14 | [diff] [blame] | 46 | : views::Button(base::BindRepeating(&ContinueBrowsingChip::ButtonPressed, |
| 47 | base::Unretained(this))), |
| 48 | url_(metadata.url), |
Jimmy Gong | 776ab1f | 2020-12-03 06:16:25 | [diff] [blame] | 49 | index_(index), |
Kyle Horimoto | ae02ab3 | 2020-12-11 00:35:47 | [diff] [blame] | 50 | total_count_(total_count), |
| 51 | user_action_recorder_(user_action_recorder) { |
minch | 63a73ef | 2020-10-22 17:19:45 | [diff] [blame] | 52 | auto* color_provider = AshColorProvider::Get(); |
Meilin Wang | 9fc2c04 | 2020-10-06 22:26:53 | [diff] [blame] | 53 | SetFocusBehavior(FocusBehavior::ALWAYS); |
minch | 63a73ef | 2020-10-22 17:19:45 | [diff] [blame] | 54 | focus_ring()->SetColor(color_provider->GetControlsLayerColor( |
| 55 | AshColorProvider::ControlsLayerType::kFocusRingColor)); |
Meilin Wang | 9fc2c04 | 2020-10-06 22:26:53 | [diff] [blame] | 56 | |
| 57 | // Install this highlight path generator to set the desired shape for |
| 58 | // our focus ring. |
| 59 | views::InstallRoundRectHighlightPathGenerator(this, gfx::Insets(), |
| 60 | kTaskContinuationChipRadius); |
| 61 | |
Andre Le | ed1afef | 2020-09-11 01:06:55 | [diff] [blame] | 62 | auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>( |
Meilin Wang | 24f7cf8 | 2020-10-26 23:13:12 | [diff] [blame] | 63 | views::BoxLayout::Orientation::kVertical, kContinueBrowsingChipInsets, |
Andre Le | 63ca8fe | 2020-09-21 21:35:34 | [diff] [blame] | 64 | kContinueBrowsingChipSpacing)); |
Meilin Wang | 24f7cf8 | 2020-10-26 23:13:12 | [diff] [blame] | 65 | layout->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kStart); |
Andre Le | ed1afef | 2020-09-11 01:06:55 | [diff] [blame] | 66 | layout->set_cross_axis_alignment( |
| 67 | views::BoxLayout::CrossAxisAlignment::kStart); |
| 68 | |
Meilin Wang | 24f7cf8 | 2020-10-26 23:13:12 | [diff] [blame] | 69 | // Inits the header view which consists of the favicon image and the url. |
Andre Le | 63ca8fe | 2020-09-21 21:35:34 | [diff] [blame] | 70 | auto* header_view = AddChildView(std::make_unique<views::View>()); |
| 71 | auto* header_layout = |
| 72 | header_view->SetLayoutManager(std::make_unique<views::BoxLayout>( |
| 73 | views::BoxLayout::Orientation::kHorizontal, gfx::Insets(), |
| 74 | kContinueBrowsingChipFaviconSpacing)); |
| 75 | header_layout->set_main_axis_alignment( |
Meilin Wang | 24f7cf8 | 2020-10-26 23:13:12 | [diff] [blame] | 76 | views::BoxLayout::MainAxisAlignment::kStart); |
Andre Le | 63ca8fe | 2020-09-21 21:35:34 | [diff] [blame] | 77 | header_layout->set_cross_axis_alignment( |
Meilin Wang | 24f7cf8 | 2020-10-26 23:13:12 | [diff] [blame] | 78 | views::BoxLayout::CrossAxisAlignment::kCenter); |
Andre Le | ed1afef | 2020-09-11 01:06:55 | [diff] [blame] | 79 | |
Andre Le | 63ca8fe | 2020-09-21 21:35:34 | [diff] [blame] | 80 | auto* favicon = |
| 81 | header_view->AddChildView(std::make_unique<views::ImageView>()); |
| 82 | favicon->SetImageSize(kContinueBrowsingChipFaviconSize); |
Tim Song | baea059 | 2020-11-12 19:55:33 | [diff] [blame] | 83 | |
| 84 | if (metadata.favicon.IsEmpty()) { |
| 85 | favicon->SetImage(CreateVectorIcon( |
| 86 | kPhoneHubDefaultFaviconIcon, |
| 87 | AshColorProvider::Get()->GetContentLayerColor( |
| 88 | AshColorProvider::ContentLayerType::kIconColorPrimary))); |
| 89 | } else { |
| 90 | favicon->SetImage(metadata.favicon.AsImageSkia()); |
| 91 | } |
Andre Le | 63ca8fe | 2020-09-21 21:35:34 | [diff] [blame] | 92 | |
Meilin Wang | 24f7cf8 | 2020-10-26 23:13:12 | [diff] [blame] | 93 | auto* url_label = header_view->AddChildView( |
| 94 | std::make_unique<views::Label>(base::UTF8ToUTF16(metadata.url.host()))); |
| 95 | url_label->SetAutoColorReadabilityEnabled(false); |
| 96 | url_label->SetSubpixelRenderingEnabled(false); |
| 97 | url_label->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor( |
| 98 | AshColorProvider::ContentLayerType::kTextColorPrimary)); |
| 99 | url_label->SetElideBehavior(gfx::ElideBehavior::ELIDE_TAIL); |
| 100 | |
Andre Le | 63ca8fe | 2020-09-21 21:35:34 | [diff] [blame] | 101 | auto* title_label = |
Meilin Wang | 24f7cf8 | 2020-10-26 23:13:12 | [diff] [blame] | 102 | AddChildView(std::make_unique<views::Label>(metadata.title)); |
Andre Le | 63ca8fe | 2020-09-21 21:35:34 | [diff] [blame] | 103 | title_label->SetAutoColorReadabilityEnabled(false); |
| 104 | title_label->SetSubpixelRenderingEnabled(false); |
minch | 63a73ef | 2020-10-22 17:19:45 | [diff] [blame] | 105 | title_label->SetEnabledColor(color_provider->GetContentLayerColor( |
Andre Le | 63ca8fe | 2020-09-21 21:35:34 | [diff] [blame] | 106 | AshColorProvider::ContentLayerType::kTextColorPrimary)); |
| 107 | title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); |
| 108 | title_label->SetMultiLine(true); |
| 109 | title_label->SetMaxLines(kTitleMaxLines); |
Andre Le | 63ca8fe | 2020-09-21 21:35:34 | [diff] [blame] | 110 | title_label->SetFontList( |
| 111 | title_label->font_list().DeriveWithWeight(gfx::Font::Weight::BOLD)); |
Andre Le | 11a9ee5 | 2020-11-11 22:42:59 | [diff] [blame] | 112 | |
Jan Wilken Dörrie | 85285b0 | 2021-03-11 23:38:47 | [diff] [blame^] | 113 | const std::u16string card_label = l10n_util::GetStringFUTF16( |
Jimmy Gong | 776ab1f | 2020-12-03 06:16:25 | [diff] [blame] | 114 | IDS_ASH_PHONE_HUB_CONTINUE_BROWSING_TAB_LABEL, |
| 115 | base::NumberToString16(index_ + 1), base::NumberToString16(total_count_), |
| 116 | metadata.title, base::UTF8ToUTF16(url_.spec())); |
| 117 | SetTooltipText(card_label); |
| 118 | SetAccessibleName(card_label); |
Andre Le | ed1afef | 2020-09-11 01:06:55 | [diff] [blame] | 119 | } |
| 120 | |
| 121 | void ContinueBrowsingChip::OnPaintBackground(gfx::Canvas* canvas) { |
| 122 | cc::PaintFlags flags; |
| 123 | flags.setAntiAlias(true); |
| 124 | flags.setColor(AshColorProvider::Get()->GetControlsLayerColor( |
| 125 | AshColorProvider::ControlsLayerType::kControlBackgroundColorInactive)); |
| 126 | gfx::Rect bounds = GetContentsBounds(); |
| 127 | canvas->DrawRoundRect(bounds, kTaskContinuationChipRadius, flags); |
| 128 | views::View::OnPaintBackground(canvas); |
| 129 | } |
| 130 | |
Peter Kasting | 5aacfd49 | 2020-10-31 03:33:14 | [diff] [blame] | 131 | ContinueBrowsingChip::~ContinueBrowsingChip() = default; |
| 132 | |
| 133 | const char* ContinueBrowsingChip::GetClassName() const { |
| 134 | return "ContinueBrowsingChip"; |
| 135 | } |
| 136 | |
| 137 | void ContinueBrowsingChip::ButtonPressed() { |
Andre Le | 63ca8fe | 2020-09-21 21:35:34 | [diff] [blame] | 138 | PA_LOG(INFO) << "Opening browser tab: " << url_; |
Tim Song | 97824893 | 2020-10-27 19:47:41 | [diff] [blame] | 139 | phone_hub_metrics::LogTabContinuationChipClicked(index_); |
Kyle Horimoto | ae02ab3 | 2020-12-11 00:35:47 | [diff] [blame] | 140 | user_action_recorder_->RecordBrowserTabOpened(); |
Tim Song | 97824893 | 2020-10-27 19:47:41 | [diff] [blame] | 141 | |
Andre Le | 63ca8fe | 2020-09-21 21:35:34 | [diff] [blame] | 142 | NewWindowDelegate::GetInstance()->NewTabWithUrl( |
| 143 | url_, /*from_user_interaction=*/true); |
Tim Song | 97824893 | 2020-10-27 19:47:41 | [diff] [blame] | 144 | |
Andre Le | 4a5d5cd | 2020-12-08 20:04:15 | [diff] [blame] | 145 | // Close Phone Hub bubble in current display. |
| 146 | views::Widget* const widget = GetWidget(); |
| 147 | // |widget| is null when this function is called before the view is added to a |
| 148 | // widget (in unit tests). |
| 149 | if (!widget) |
| 150 | return; |
| 151 | int64_t current_display_id = |
| 152 | display::Screen::GetScreen() |
| 153 | ->GetDisplayNearestWindow(widget->GetNativeWindow()) |
| 154 | .id(); |
| 155 | Shell::GetRootWindowControllerWithDisplayId(current_display_id) |
Andre Le | 63ca8fe | 2020-09-21 21:35:34 | [diff] [blame] | 156 | ->GetStatusAreaWidget() |
| 157 | ->phone_hub_tray() |
| 158 | ->CloseBubble(); |
Andre Le | ed1afef | 2020-09-11 01:06:55 | [diff] [blame] | 159 | } |
| 160 | |
Andre Le | ed1afef | 2020-09-11 01:06:55 | [diff] [blame] | 161 | } // namespace ash |