shelf_shutdown_confirmation_bubble.cc 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. // Copyright 2022 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. #include "ash/shelf/shelf_shutdown_confirmation_bubble.h"
  5. #include "ash/constants/ash_features.h"
  6. #include "ash/strings/grit/ash_strings.h"
  7. #include "ash/style/ash_color_provider.h"
  8. #include "ash/style/pill_button.h"
  9. #include "ash/system/tray/tray_popup_utils.h"
  10. #include "ash/system/tray/tray_utils.h"
  11. #include "base/bind.h"
  12. #include "base/callback_forward.h"
  13. #include "base/callback_helpers.h"
  14. #include "base/metrics/histogram_functions.h"
  15. #include "base/notreached.h"
  16. #include "base/strings/strcat.h"
  17. #include "base/time/time.h"
  18. #include "components/strings/grit/components_strings.h"
  19. #include "components/vector_icons/vector_icons.h"
  20. #include "ui/accessibility/ax_node_data.h"
  21. #include "ui/aura/window.h"
  22. #include "ui/base/l10n/l10n_util.h"
  23. #include "ui/base/models/image_model.h"
  24. #include "ui/gfx/geometry/size.h"
  25. #include "ui/gfx/image/image_skia_operations.h"
  26. #include "ui/gfx/paint_vector_icon.h"
  27. #include "ui/gfx/vector_icon_types.h"
  28. #include "ui/views/controls/label.h"
  29. #include "ui/views/layout/box_layout.h"
  30. #include "ui/views/layout/flex_layout.h"
  31. #include "ui/views/layout/layout_provider.h"
  32. namespace ash {
  33. namespace {
  34. // The preferred width of the shutdown confirmation bubble's content.
  35. constexpr int kBubblePreferredWidth = 175;
  36. // The insets of the shutdown confirmation bubble. The value of
  37. // Insets-leading-side is taken from the system.
  38. constexpr int kShutdownConfirmationBubbleInsetsBottom = 12;
  39. constexpr int kShutdownConfirmationBubbleInsetsTop = 8;
  40. gfx::Insets GetShutdownConfirmationBubbleInsets() {
  41. gfx::Insets insets = GetTrayBubbleInsets();
  42. insets.set_top(kShutdownConfirmationBubbleInsetsTop);
  43. insets.set_bottom(kShutdownConfirmationBubbleInsetsBottom);
  44. return insets;
  45. }
  46. // Histogram for tracking the number of actions on the shelf shutdown
  47. // confirmation bubble.
  48. constexpr char kActionHistogramName[] =
  49. "Ash.Shelf.ShutdownConfirmationBubble.Action";
  50. // Histogram for tracking the time delta between bubble opened and actions taken
  51. // on the shelf shutdown confirmation bubble.
  52. constexpr char kActionDurationHistogramPrefix[] =
  53. "Ash.Shelf.ShutdownConfirmationBubble.ActionDuration.";
  54. // Suffix for shutdown confirmation action. Should match suffixes of the
  55. // Ash.Shelf.ShutdownConfirmationBubble.ActionDuration.* metrics in
  56. // metadata/ash/histograms.xml
  57. std::string BubbleActionSuffix(
  58. ShelfShutdownConfirmationBubble::BubbleAction action) {
  59. switch (action) {
  60. case ShelfShutdownConfirmationBubble::kCancelled:
  61. return "Cancel";
  62. case ShelfShutdownConfirmationBubble::kConfirmed:
  63. return "Confirm";
  64. case ShelfShutdownConfirmationBubble::kDismissed:
  65. return "Dismiss";
  66. case ShelfShutdownConfirmationBubble::kOpened:
  67. case ShelfShutdownConfirmationBubble::kMaxValue:
  68. NOTREACHED();
  69. return "";
  70. }
  71. }
  72. } // namespace
  73. ShelfShutdownConfirmationBubble::ShelfShutdownConfirmationBubble(
  74. views::View* anchor,
  75. ShelfAlignment alignment,
  76. base::OnceClosure on_confirm_callback,
  77. base::OnceClosure on_cancel_callback)
  78. : ShelfBubble(anchor, alignment),
  79. bubble_opened_timestamp_(base::TimeTicks::Now()) {
  80. DCHECK(on_confirm_callback);
  81. DCHECK(on_cancel_callback);
  82. confirm_callback_ = std::move(on_confirm_callback);
  83. cancel_callback_ = std::move(on_cancel_callback);
  84. auto* layout_provider = views::LayoutProvider::Get();
  85. const gfx::Insets kShutdownConfirmationBubbleInsets =
  86. GetShutdownConfirmationBubbleInsets();
  87. const gfx::Insets dialog_insets =
  88. layout_provider->GetInsetsMetric(views::INSETS_DIALOG);
  89. set_margins(kShutdownConfirmationBubbleInsets + dialog_insets);
  90. set_close_on_deactivate(true);
  91. SetCloseCallback(base::BindOnce(&ShelfShutdownConfirmationBubble::OnClosed,
  92. base::Unretained(this)));
  93. views::FlexLayout* layout =
  94. SetLayoutManager(std::make_unique<views::FlexLayout>());
  95. layout->SetOrientation(views::LayoutOrientation::kVertical);
  96. layout->SetMainAxisAlignment(views::LayoutAlignment::kStart);
  97. layout->SetCrossAxisAlignment(views::LayoutAlignment::kStart);
  98. // Set up the icon.
  99. icon_ = AddChildView(std::make_unique<views::ImageView>());
  100. icon_->SetProperty(
  101. views::kMarginsKey,
  102. gfx::Insets::TLBR(0, 0,
  103. layout_provider->GetDistanceMetric(
  104. views::DISTANCE_UNRELATED_CONTROL_VERTICAL),
  105. 0));
  106. // Set up the title view.
  107. title_ = AddChildView(std::make_unique<views::Label>());
  108. title_->SetMultiLine(true);
  109. title_->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
  110. TrayPopupUtils::SetLabelFontList(title_,
  111. TrayPopupUtils::FontStyle::kSubHeader);
  112. title_->SetText(
  113. l10n_util::GetStringUTF16(IDS_ASH_SHUTDOWN_CONFIRMATION_TITLE));
  114. title_->SetProperty(
  115. views::kMarginsKey,
  116. gfx::Insets::TLBR(0, 0,
  117. layout_provider->GetDistanceMetric(
  118. views::DISTANCE_DIALOG_CONTENT_MARGIN_BOTTOM_TEXT),
  119. 0));
  120. // Set up layout row for the buttons of cancellation and confirmation.
  121. views::View* button_container = AddChildView(std::make_unique<views::View>());
  122. button_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
  123. views::BoxLayout::Orientation::kHorizontal, gfx::Insets(),
  124. layout_provider->GetDistanceMetric(
  125. views::DISTANCE_RELATED_BUTTON_HORIZONTAL)));
  126. auto cancel_button = std::make_unique<PillButton>(
  127. base::BindRepeating(&ShelfShutdownConfirmationBubble::OnCancelled,
  128. base::Unretained(this)),
  129. l10n_util::GetStringUTF16(IDS_CANCEL), PillButton::Type::kIconless,
  130. /*icon=*/nullptr);
  131. cancel_button->SetID(static_cast<int>(ButtonId::kCancel));
  132. cancel_ = button_container->AddChildView(std::move(cancel_button));
  133. auto confirm_button = std::make_unique<PillButton>(
  134. base::BindRepeating(&ShelfShutdownConfirmationBubble::OnConfirmed,
  135. base::Unretained(this)),
  136. l10n_util::GetStringUTF16(IDS_ASH_SHUTDOWN_CONFIRM_BUTTON),
  137. PillButton::Type::kIconless, /*icon=*/nullptr);
  138. confirm_button->SetID(static_cast<int>(ButtonId::kShutdown));
  139. confirm_ = button_container->AddChildView(std::move(confirm_button));
  140. CreateBubble();
  141. auto bubble_border =
  142. std::make_unique<views::BubbleBorder>(arrow(), GetShadow());
  143. bubble_border->set_insets(kShutdownConfirmationBubbleInsets);
  144. bubble_border->SetCornerRadius(
  145. views::LayoutProvider::Get()->GetCornerRadiusMetric(
  146. views::Emphasis::kHigh));
  147. GetBubbleFrameView()->SetBubbleBorder(std::move(bubble_border));
  148. GetBubbleFrameView()->SetBackgroundColor(GetBackgroundColor());
  149. GetWidget()->Show();
  150. base::UmaHistogramEnumeration(kActionHistogramName,
  151. ShelfShutdownConfirmationBubble::kOpened);
  152. }
  153. ShelfShutdownConfirmationBubble::~ShelfShutdownConfirmationBubble() {
  154. // In case shutdown confirmation bubble was dismissed, the pointer of the
  155. // ShelfShutdownConfirmationBubble in LoginShelfView shall be cleaned up.
  156. if (cancel_callback_) {
  157. std::move(cancel_callback_).Run();
  158. }
  159. }
  160. void ShelfShutdownConfirmationBubble::OnThemeChanged() {
  161. views::View::OnThemeChanged();
  162. auto* color_provider = AshColorProvider::Get();
  163. SkColor icon_color = color_provider->GetContentLayerColor(
  164. AshColorProvider::ContentLayerType::kButtonIconColor);
  165. icon_->SetImage(
  166. gfx::CreateVectorIcon(vector_icons::kWarningOutlineIcon, icon_color));
  167. SkColor label_color = color_provider->GetContentLayerColor(
  168. AshColorProvider::ContentLayerType::kTextColorPrimary);
  169. title_->SetEnabledColor(label_color);
  170. SkColor button_color = color_provider->GetContentLayerColor(
  171. AshColorProvider::ContentLayerType::kButtonLabelColor);
  172. cancel_->SetEnabledTextColors(button_color);
  173. confirm_->SetEnabledTextColors(button_color);
  174. }
  175. void ShelfShutdownConfirmationBubble::GetAccessibleNodeData(
  176. ui::AXNodeData* node_data) {
  177. node_data->role = ax::mojom::Role::kDialog;
  178. node_data->SetName(title_->GetText());
  179. }
  180. std::u16string ShelfShutdownConfirmationBubble::GetAccessibleWindowTitle()
  181. const {
  182. return title_->GetText();
  183. }
  184. void ShelfShutdownConfirmationBubble::OnCancelled() {
  185. dialog_result_ = DialogResult::kCancelled;
  186. GetWidget()->Close();
  187. }
  188. void ShelfShutdownConfirmationBubble::OnConfirmed() {
  189. dialog_result_ = DialogResult::kConfirmed;
  190. GetWidget()->Close();
  191. }
  192. void ShelfShutdownConfirmationBubble::OnClosed() {
  193. switch (dialog_result_) {
  194. case DialogResult::kCancelled:
  195. ReportBubbleAction(ShelfShutdownConfirmationBubble::kCancelled);
  196. std::move(cancel_callback_).Run();
  197. break;
  198. case DialogResult::kConfirmed:
  199. ReportBubbleAction(ShelfShutdownConfirmationBubble::kConfirmed);
  200. std::move(confirm_callback_).Run();
  201. break;
  202. case DialogResult::kNone:
  203. ReportBubbleAction(ShelfShutdownConfirmationBubble::kDismissed);
  204. break;
  205. }
  206. }
  207. gfx::Size ShelfShutdownConfirmationBubble::CalculatePreferredSize() const {
  208. return gfx::Size(kBubblePreferredWidth,
  209. GetHeightForWidth(kBubblePreferredWidth));
  210. }
  211. bool ShelfShutdownConfirmationBubble::ShouldCloseOnPressDown() {
  212. return true;
  213. }
  214. bool ShelfShutdownConfirmationBubble::ShouldCloseOnMouseExit() {
  215. return false;
  216. }
  217. void ShelfShutdownConfirmationBubble::ReportBubbleAction(
  218. ShelfShutdownConfirmationBubble::BubbleAction action) {
  219. base::UmaHistogramEnumeration(kActionHistogramName, action);
  220. const std::string action_suffix = BubbleActionSuffix(action);
  221. auto elapsed_time = base::TimeTicks::Now() - bubble_opened_timestamp_;
  222. base::UmaHistogramMediumTimes(
  223. base::StrCat({kActionDurationHistogramPrefix, action_suffix}),
  224. elapsed_time);
  225. }
  226. } // namespace ash