tray_background_view.cc 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851
  1. // Copyright (c) 2012 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/system/tray/tray_background_view.h"
  5. #include <algorithm>
  6. #include <memory>
  7. #include "ash/focus_cycler.h"
  8. #include "ash/login/ui/lock_screen.h"
  9. #include "ash/public/cpp/session/session_observer.h"
  10. #include "ash/public/cpp/shelf_config.h"
  11. #include "ash/public/cpp/shell_window_ids.h"
  12. #include "ash/session/session_controller_impl.h"
  13. #include "ash/shelf/login_shelf_view.h"
  14. #include "ash/shelf/shelf_focus_cycler.h"
  15. #include "ash/shelf/shelf_layout_manager.h"
  16. #include "ash/shelf/shelf_navigation_widget.h"
  17. #include "ash/shelf/shelf_widget.h"
  18. #include "ash/shell.h"
  19. #include "ash/style/style_util.h"
  20. #include "ash/system/model/system_tray_model.h"
  21. #include "ash/system/status_area_widget.h"
  22. #include "ash/system/status_area_widget_delegate.h"
  23. #include "ash/system/tray/system_tray_notifier.h"
  24. #include "ash/system/tray/tray_constants.h"
  25. #include "ash/system/tray/tray_container.h"
  26. #include "ash/system/tray/tray_event_filter.h"
  27. #include "ash/wm/tablet_mode/tablet_mode_controller.h"
  28. #include "base/bind.h"
  29. #include "base/scoped_multi_source_observation.h"
  30. #include "base/time/time.h"
  31. #include "ui/accessibility/ax_node_data.h"
  32. #include "ui/aura/window.h"
  33. #include "ui/base/metadata/metadata_impl_macros.h"
  34. #include "ui/base/models/menu_model.h"
  35. #include "ui/base/ui_base_types.h"
  36. #include "ui/color/color_id.h"
  37. #include "ui/compositor/animation_throughput_reporter.h"
  38. #include "ui/compositor/layer.h"
  39. #include "ui/gfx/animation/tween.h"
  40. #include "ui/gfx/canvas.h"
  41. #include "ui/gfx/color_utils.h"
  42. #include "ui/gfx/geometry/rect.h"
  43. #include "ui/gfx/geometry/rounded_corners_f.h"
  44. #include "ui/gfx/geometry/size.h"
  45. #include "ui/gfx/geometry/transform.h"
  46. #include "ui/gfx/interpolated_transform.h"
  47. #include "ui/gfx/scoped_canvas.h"
  48. #include "ui/views/accessibility/view_accessibility.h"
  49. #include "ui/views/animation/animation_builder.h"
  50. #include "ui/views/animation/ink_drop.h"
  51. #include "ui/views/background.h"
  52. #include "ui/views/controls/focus_ring.h"
  53. #include "ui/views/controls/highlight_path_generator.h"
  54. #include "ui/views/controls/menu/menu_runner.h"
  55. #include "ui/views/layout/fill_layout.h"
  56. #include "ui/views/painter.h"
  57. #include "ui/views/view_class_properties.h"
  58. #include "ui/views/widget/widget.h"
  59. #include "ui/wm/core/window_animations.h"
  60. namespace ash {
  61. namespace {
  62. const int kAnimationDurationForBubblePopupMs = 200;
  63. // Duration of opacity animation for visibility changes.
  64. constexpr base::TimeDelta kAnimationDurationForVisibilityMs =
  65. base::Milliseconds(250);
  66. // Duration of opacity animation for hide animation.
  67. constexpr base::TimeDelta kAnimationDurationForHideMs = base::Milliseconds(100);
  68. // Bounce animation constants
  69. const base::TimeDelta kAnimationDurationForBounceElement =
  70. base::Milliseconds(250);
  71. const int kAnimationBounceUpDistance = 16;
  72. const int kAnimationBounceDownDistance = 8;
  73. const float kAnimationBounceScaleFactor = 0.5;
  74. // When becoming visible delay the animation so that StatusAreaWidgetDelegate
  75. // can animate sibling views out of the position to be occupied by the
  76. // TrayBackgroundView.
  77. const base::TimeDelta kShowAnimationDelayMs = base::Milliseconds(100);
  78. // Number of active requests to disable CloseBubble().
  79. int g_disable_close_bubble_on_window_activated = 0;
  80. constexpr char kFadeInAnimationSmoothnessHistogramName[] =
  81. "Ash.StatusArea.TrayBackgroundView.FadeIn";
  82. constexpr char kBounceInAnimationSmoothnessHistogramName[] =
  83. "Ash.StatusArea.TrayBackgroundView.BounceIn";
  84. constexpr char kHideAnimationSmoothnessHistogramName[] =
  85. "Ash.StatusArea.TrayBackgroundView.Hide";
  86. // Switches left and right insets if RTL mode is active.
  87. void MirrorInsetsIfNecessary(gfx::Insets* insets) {
  88. if (base::i18n::IsRTL()) {
  89. *insets = gfx::Insets::TLBR(insets->top(), insets->right(),
  90. insets->bottom(), insets->left());
  91. }
  92. }
  93. // Returns background insets relative to the contents bounds of the view and
  94. // mirrored if RTL mode is active.
  95. gfx::Insets GetMirroredBackgroundInsets(bool is_shelf_horizontal) {
  96. gfx::Insets insets;
  97. // "Primary" is the same direction as the shelf, "secondary" is orthogonal.
  98. const int primary_padding = 0;
  99. const int secondary_padding =
  100. -ash::ShelfConfig::Get()->status_area_hit_region_padding();
  101. if (is_shelf_horizontal) {
  102. insets =
  103. gfx::Insets::TLBR(secondary_padding, primary_padding, secondary_padding,
  104. primary_padding + ash::kTraySeparatorWidth);
  105. } else {
  106. insets = gfx::Insets::TLBR(primary_padding, secondary_padding,
  107. primary_padding + ash::kTraySeparatorWidth,
  108. secondary_padding);
  109. }
  110. MirrorInsetsIfNecessary(&insets);
  111. return insets;
  112. }
  113. class HighlightPathGenerator : public views::HighlightPathGenerator {
  114. public:
  115. explicit HighlightPathGenerator(TrayBackgroundView* tray_background_view)
  116. : tray_background_view_(tray_background_view), insets_(gfx::Insets()) {}
  117. HighlightPathGenerator(TrayBackgroundView* tray_background_view,
  118. gfx::Insets insets)
  119. : tray_background_view_(tray_background_view), insets_(insets) {}
  120. HighlightPathGenerator(const HighlightPathGenerator&) = delete;
  121. HighlightPathGenerator& operator=(const HighlightPathGenerator&) = delete;
  122. // HighlightPathGenerator:
  123. absl::optional<gfx::RRectF> GetRoundRect(const gfx::RectF& rect) override {
  124. gfx::RectF bounds(tray_background_view_->GetBackgroundBounds());
  125. bounds.Inset(gfx::InsetsF(insets_));
  126. return gfx::RRectF(bounds, tray_background_view_->GetRoundedCorners());
  127. }
  128. private:
  129. TrayBackgroundView* const tray_background_view_;
  130. const gfx::Insets insets_;
  131. };
  132. } // namespace
  133. // Used to track when the anchor widget changes position on screen so that the
  134. // bubble position can be updated.
  135. class TrayBackgroundView::TrayWidgetObserver : public views::WidgetObserver {
  136. public:
  137. explicit TrayWidgetObserver(TrayBackgroundView* host) : host_(host) {}
  138. TrayWidgetObserver(const TrayWidgetObserver&) = delete;
  139. TrayWidgetObserver& operator=(const TrayWidgetObserver&) = delete;
  140. void OnWidgetBoundsChanged(views::Widget* widget,
  141. const gfx::Rect& new_bounds) override {
  142. host_->AnchorUpdated();
  143. }
  144. void OnWidgetVisibilityChanged(views::Widget* widget, bool visible) override {
  145. host_->AnchorUpdated();
  146. }
  147. void Add(views::Widget* widget) { observations_.AddObservation(widget); }
  148. private:
  149. TrayBackgroundView* host_;
  150. base::ScopedMultiSourceObservation<views::Widget, views::WidgetObserver>
  151. observations_{this};
  152. };
  153. // Handles `TrayBackgroundView`'s animation on session changed.
  154. class TrayBackgroundView::TrayBackgroundViewSessionChangeHandler
  155. : public SessionObserver {
  156. public:
  157. explicit TrayBackgroundViewSessionChangeHandler(
  158. TrayBackgroundView* tray_background_view)
  159. : tray_(tray_background_view) {
  160. DCHECK(tray_);
  161. }
  162. TrayBackgroundViewSessionChangeHandler(
  163. const TrayBackgroundViewSessionChangeHandler&) = delete;
  164. TrayBackgroundViewSessionChangeHandler& operator=(
  165. const TrayBackgroundViewSessionChangeHandler&) = delete;
  166. ~TrayBackgroundViewSessionChangeHandler() override = default;
  167. private: // SessionObserver:
  168. void OnSessionStateChanged(session_manager::SessionState state) override {
  169. DisableShowAnimationInSequence();
  170. }
  171. void OnActiveUserSessionChanged(const AccountId& account_id) override {
  172. DisableShowAnimationInSequence();
  173. }
  174. // Disables the `TrayBackgroundView`'s show animation until all queued tasks
  175. // in the current task sequence are run.
  176. void DisableShowAnimationInSequence() {
  177. base::ScopedClosureRunner callback = tray_->DisableShowAnimation();
  178. base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
  179. callback.Release());
  180. }
  181. TrayBackgroundView* const tray_;
  182. ScopedSessionObserver session_observer_{this};
  183. };
  184. ////////////////////////////////////////////////////////////////////////////////
  185. // TrayBackgroundView
  186. TrayBackgroundView::TrayBackgroundView(Shelf* shelf,
  187. RoundedCornerBehavior corner_behavior)
  188. // Note the ink drop style is ignored.
  189. : ActionableView(TrayPopupInkDropStyle::FILL_BOUNDS),
  190. shelf_(shelf),
  191. tray_container_(new TrayContainer(shelf, this)),
  192. is_active_(false),
  193. separator_visible_(true),
  194. visible_preferred_(false),
  195. show_with_virtual_keyboard_(false),
  196. show_when_collapsed_(true),
  197. corner_behavior_(corner_behavior),
  198. widget_observer_(new TrayWidgetObserver(this)),
  199. handler_(new TrayBackgroundViewSessionChangeHandler(this)) {
  200. DCHECK(shelf_);
  201. SetNotifyEnterExitOnChild(true);
  202. // Override the settings of inkdrop ripple only since others like Highlight
  203. // has been set up in the base class ActionableView.
  204. StyleUtil::SetRippleParams(this, GetBackgroundInsets());
  205. views::InkDrop::Get(this)->SetMode(
  206. views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER);
  207. SetLayoutManager(std::make_unique<views::FillLayout>());
  208. SetInstallFocusRingOnFocus(true);
  209. views::FocusRing::Get(this)->SetPathGenerator(
  210. std::make_unique<HighlightPathGenerator>(this,
  211. kTrayBackgroundFocusPadding));
  212. views::FocusRing::Get(this)->SetColorId(ui::kColorAshFocusRing);
  213. SetFocusPainter(nullptr);
  214. views::HighlightPathGenerator::Install(
  215. this, std::make_unique<HighlightPathGenerator>(this));
  216. AddChildView(tray_container_);
  217. tray_event_filter_ = std::make_unique<TrayEventFilter>();
  218. // Use layer color to provide background color. Note that children views
  219. // need to have their own layers to be visible.
  220. SetPaintToLayer(ui::LAYER_SOLID_COLOR);
  221. layer()->SetFillsBoundsOpaquely(false);
  222. // Start the tray items not visible, because visibility changes are animated.
  223. views::View::SetVisible(false);
  224. }
  225. TrayBackgroundView::~TrayBackgroundView() {
  226. Shell::Get()->system_tray_model()->virtual_keyboard()->RemoveObserver(this);
  227. widget_observer_.reset();
  228. handler_.reset();
  229. }
  230. void TrayBackgroundView::Initialize() {
  231. widget_observer_->Add(GetWidget());
  232. Shell::Get()->system_tray_model()->virtual_keyboard()->AddObserver(this);
  233. UpdateBackground();
  234. }
  235. // static
  236. void TrayBackgroundView::InitializeBubbleAnimations(
  237. views::Widget* bubble_widget) {
  238. aura::Window* window = bubble_widget->GetNativeWindow();
  239. ::wm::SetWindowVisibilityAnimationType(
  240. window, ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
  241. ::wm::SetWindowVisibilityAnimationTransition(window, ::wm::ANIMATE_HIDE);
  242. ::wm::SetWindowVisibilityAnimationDuration(
  243. window, base::Milliseconds(kAnimationDurationForBubblePopupMs));
  244. }
  245. void TrayBackgroundView::SetVisiblePreferred(bool visible_preferred) {
  246. if (visible_preferred_ == visible_preferred)
  247. return;
  248. visible_preferred_ = visible_preferred;
  249. StartVisibilityAnimation(GetEffectiveVisibility());
  250. // We need to update which trays overflow after showing or hiding a tray.
  251. // If the hide animation is still playing, we do the `UpdateStatusArea(bool
  252. // should_log_visible_pod_count)` when the animation is finished.
  253. if (!layer()->GetAnimator()->is_animating() || visible_preferred_)
  254. UpdateStatusArea(true /*should_log_visible_pod_count*/);
  255. }
  256. bool TrayBackgroundView::IsShowingMenu() const {
  257. return context_menu_runner_ && context_menu_runner_->IsRunning();
  258. }
  259. void TrayBackgroundView::SetRoundedCornerBehavior(
  260. RoundedCornerBehavior corner_behavior) {
  261. corner_behavior_ = corner_behavior;
  262. UpdateBackground();
  263. }
  264. gfx::RoundedCornersF TrayBackgroundView::GetRoundedCorners() {
  265. const float radius = ShelfConfig::Get()->control_border_radius();
  266. if (shelf_->IsHorizontalAlignment()) {
  267. gfx::RoundedCornersF start_rounded = {
  268. radius, kUnifiedTrayNonRoundedSideRadius,
  269. kUnifiedTrayNonRoundedSideRadius, radius};
  270. gfx::RoundedCornersF end_rounded = {kUnifiedTrayNonRoundedSideRadius,
  271. radius, radius,
  272. kUnifiedTrayNonRoundedSideRadius};
  273. switch (corner_behavior_) {
  274. case kNotRounded:
  275. return {
  276. kUnifiedTrayNonRoundedSideRadius, kUnifiedTrayNonRoundedSideRadius,
  277. kUnifiedTrayNonRoundedSideRadius, kUnifiedTrayNonRoundedSideRadius};
  278. case kAllRounded:
  279. return {radius, radius, radius, radius};
  280. case kStartRounded:
  281. return base::i18n::IsRTL() ? end_rounded : start_rounded;
  282. case kEndRounded:
  283. return base::i18n::IsRTL() ? start_rounded : end_rounded;
  284. }
  285. }
  286. switch (corner_behavior_) {
  287. case kNotRounded:
  288. return {
  289. kUnifiedTrayNonRoundedSideRadius, kUnifiedTrayNonRoundedSideRadius,
  290. kUnifiedTrayNonRoundedSideRadius, kUnifiedTrayNonRoundedSideRadius};
  291. case kAllRounded:
  292. return {radius, radius, radius, radius};
  293. case kStartRounded:
  294. return {radius, radius, kUnifiedTrayNonRoundedSideRadius,
  295. kUnifiedTrayNonRoundedSideRadius};
  296. case kEndRounded:
  297. return {kUnifiedTrayNonRoundedSideRadius,
  298. kUnifiedTrayNonRoundedSideRadius, radius, radius};
  299. }
  300. }
  301. void TrayBackgroundView::StartVisibilityAnimation(bool visible) {
  302. if (visible == layer()->GetTargetVisibility())
  303. return;
  304. base::AutoReset<bool> is_starting_animation(&is_starting_animation_, true);
  305. if (visible) {
  306. views::View::SetVisible(true);
  307. // If SetVisible(true) is called while animating to not visible, then
  308. // views::View::SetVisible(true) is a no-op. When the previous animation
  309. // ends layer->SetVisible(false) is called. To prevent this
  310. // layer->SetVisible(true) immediately interrupts the animation of this
  311. // property, and keeps the layer visible.
  312. layer()->SetVisible(true);
  313. // We only show visible animation when `IsShowAnimationEnabled()`.
  314. if (IsShowAnimationEnabled()) {
  315. if (use_bounce_in_animation_)
  316. BounceInAnimation();
  317. else
  318. FadeInAnimation();
  319. } else {
  320. // The opacity and scale of the `layer()` may have been manipulated, so
  321. // reset it before it is shown.
  322. layer()->SetOpacity(1.0f);
  323. layer()->SetTransform(gfx::Transform());
  324. }
  325. } else {
  326. HideAnimation();
  327. }
  328. }
  329. base::ScopedClosureRunner TrayBackgroundView::DisableShowAnimation() {
  330. if (layer()->GetAnimator()->is_animating())
  331. layer()->GetAnimator()->StopAnimating();
  332. ++disable_show_animation_count_;
  333. if (disable_show_animation_count_ == 1u)
  334. OnShouldShowAnimationChanged(false);
  335. return base::ScopedClosureRunner(base::BindOnce(
  336. [](const base::WeakPtr<TrayBackgroundView>& ptr) {
  337. if (ptr) {
  338. --ptr->disable_show_animation_count_;
  339. if (ptr->IsShowAnimationEnabled())
  340. ptr->OnShouldShowAnimationChanged(true);
  341. }
  342. },
  343. weak_factory_.GetWeakPtr()));
  344. }
  345. base::ScopedClosureRunner
  346. TrayBackgroundView::DisableCloseBubbleOnWindowActivated() {
  347. ++g_disable_close_bubble_on_window_activated;
  348. return base::ScopedClosureRunner(
  349. base::BindOnce([]() { --g_disable_close_bubble_on_window_activated; }));
  350. }
  351. // static
  352. bool TrayBackgroundView::ShouldCloseBubbleOnWindowActivated() {
  353. return g_disable_close_bubble_on_window_activated == 0;
  354. }
  355. void TrayBackgroundView::UpdateStatusArea(bool should_log_visible_pod_count) {
  356. auto* status_area_widget = shelf_->GetStatusAreaWidget();
  357. if (status_area_widget) {
  358. status_area_widget->UpdateCollapseState();
  359. if (should_log_visible_pod_count)
  360. status_area_widget->LogVisiblePodCountMetric();
  361. }
  362. }
  363. void TrayBackgroundView::OnVisibilityAnimationFinished(
  364. bool should_log_visible_pod_count,
  365. bool aborted) {
  366. if (aborted && is_starting_animation_)
  367. return;
  368. if (!visible_preferred_) {
  369. views::View::SetVisible(false);
  370. UpdateStatusArea(should_log_visible_pod_count);
  371. }
  372. }
  373. void TrayBackgroundView::ShowContextMenuForViewImpl(
  374. views::View* source,
  375. const gfx::Point& point,
  376. ui::MenuSourceType source_type) {
  377. context_menu_model_ = CreateContextMenuModel();
  378. if (!context_menu_model_)
  379. return;
  380. const int run_types = views::MenuRunner::USE_ASH_SYS_UI_LAYOUT |
  381. views::MenuRunner::CONTEXT_MENU |
  382. views::MenuRunner::FIXED_ANCHOR;
  383. context_menu_runner_ = std::make_unique<views::MenuRunner>(
  384. context_menu_model_.get(), run_types,
  385. base::BindRepeating(&Shelf::UpdateAutoHideState,
  386. base::Unretained(shelf_)));
  387. views::MenuAnchorPosition anchor;
  388. switch (shelf_->alignment()) {
  389. case ShelfAlignment::kBottom:
  390. case ShelfAlignment::kBottomLocked:
  391. anchor = views::MenuAnchorPosition::kBubbleTopRight;
  392. break;
  393. case ShelfAlignment::kLeft:
  394. anchor = views::MenuAnchorPosition::kBubbleRight;
  395. break;
  396. case ShelfAlignment::kRight:
  397. anchor = views::MenuAnchorPosition::kBubbleLeft;
  398. break;
  399. }
  400. context_menu_runner_->RunMenuAt(
  401. source->GetWidget(), /*button_controller=*/nullptr,
  402. source->GetBoundsInScreen(), anchor, source_type);
  403. }
  404. void TrayBackgroundView::AboutToRequestFocusFromTabTraversal(bool reverse) {
  405. Shelf* shelf = Shelf::ForWindow(GetWidget()->GetNativeWindow());
  406. StatusAreaWidgetDelegate* delegate =
  407. shelf->GetStatusAreaWidget()->status_area_widget_delegate();
  408. if (!delegate || !delegate->ShouldFocusOut(reverse))
  409. return;
  410. shelf_->shelf_focus_cycler()->FocusOut(reverse, SourceView::kStatusAreaView);
  411. }
  412. void TrayBackgroundView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
  413. ActionableView::GetAccessibleNodeData(node_data);
  414. node_data->SetName(GetAccessibleNameForTray());
  415. if (LockScreen::HasInstance()) {
  416. GetViewAccessibility().OverrideNextFocus(LockScreen::Get()->widget());
  417. }
  418. Shelf* shelf = Shelf::ForWindow(GetWidget()->GetNativeWindow());
  419. ShelfWidget* shelf_widget = shelf->shelf_widget();
  420. GetViewAccessibility().OverridePreviousFocus(shelf_widget->hotseat_widget());
  421. GetViewAccessibility().OverrideNextFocus(shelf_widget->navigation_widget());
  422. }
  423. void TrayBackgroundView::ChildPreferredSizeChanged(views::View* child) {
  424. PreferredSizeChanged();
  425. }
  426. std::unique_ptr<ui::Layer> TrayBackgroundView::RecreateLayer() {
  427. if (layer()->GetAnimator()->is_animating())
  428. OnVisibilityAnimationFinished(/*should_log_visible_pod_count=*/false,
  429. /*aborted=*/false);
  430. return views::View::RecreateLayer();
  431. }
  432. void TrayBackgroundView::OnThemeChanged() {
  433. ActionableView::OnThemeChanged();
  434. UpdateBackground();
  435. StyleUtil::ConfigureInkDropAttributes(this, StyleUtil::kBaseColor |
  436. StyleUtil::kInkDropOpacity |
  437. StyleUtil::kHighlightOpacity);
  438. }
  439. void TrayBackgroundView::OnVirtualKeyboardVisibilityChanged() {
  440. // We call the base class' SetVisible to skip animations.
  441. if (GetVisible() != GetEffectiveVisibility())
  442. views::View::SetVisible(GetEffectiveVisibility());
  443. }
  444. TrayBubbleView* TrayBackgroundView::GetBubbleView() {
  445. return nullptr;
  446. }
  447. views::Widget* TrayBackgroundView::GetBubbleWidget() const {
  448. return nullptr;
  449. }
  450. void TrayBackgroundView::ShowBubble() {}
  451. void TrayBackgroundView::CalculateTargetBounds() {
  452. tray_container_->CalculateTargetBounds();
  453. }
  454. void TrayBackgroundView::UpdateLayout() {
  455. UpdateBackground();
  456. tray_container_->UpdateLayout();
  457. }
  458. void TrayBackgroundView::UpdateAfterLoginStatusChange() {
  459. // Handled in subclasses.
  460. }
  461. void TrayBackgroundView::UpdateAfterStatusAreaCollapseChange() {
  462. views::View::SetVisible(GetEffectiveVisibility());
  463. }
  464. void TrayBackgroundView::BubbleResized(const TrayBubbleView* bubble_view) {}
  465. void TrayBackgroundView::OnAnyBubbleVisibilityChanged(
  466. views::Widget* bubble_widget,
  467. bool visible) {}
  468. void TrayBackgroundView::UpdateBackground() {
  469. layer()->SetRoundedCornerRadius(GetRoundedCorners());
  470. layer()->SetIsFastRoundedCorner(true);
  471. layer()->SetBackgroundBlur(
  472. ShelfConfig::Get()->GetShelfControlButtonBlurRadius());
  473. layer()->SetColor(ShelfConfig::Get()->GetShelfControlButtonColor());
  474. layer()->SetClipRect(GetBackgroundBounds());
  475. }
  476. void TrayBackgroundView::OnAnimationAborted() {
  477. OnVisibilityAnimationFinished(/*should_log_visible_pod_count=*/true,
  478. /*aborted=*/true);
  479. }
  480. void TrayBackgroundView::OnAnimationEnded() {
  481. OnVisibilityAnimationFinished(/*should_log_visible_pod_count=*/true,
  482. /*aborted=*/false);
  483. }
  484. void TrayBackgroundView::FadeInAnimation() {
  485. gfx::Transform transform;
  486. if (shelf_->IsHorizontalAlignment())
  487. transform.Translate(width(), 0.0f);
  488. else
  489. transform.Translate(0.0f, height());
  490. ui::AnimationThroughputReporter reporter(
  491. layer()->GetAnimator(),
  492. metrics_util::ForSmoothness(base::BindRepeating([](int smoothness) {
  493. DCHECK(0 <= smoothness && smoothness <= 100);
  494. base::UmaHistogramPercentage(kFadeInAnimationSmoothnessHistogramName,
  495. smoothness);
  496. })));
  497. views::AnimationBuilder()
  498. .SetPreemptionStrategy(
  499. ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
  500. .OnAborted(base::BindOnce(
  501. [](base::WeakPtr<TrayBackgroundView> view) {
  502. if (view)
  503. view->OnAnimationAborted();
  504. },
  505. weak_factory_.GetWeakPtr()))
  506. .OnEnded(base::BindOnce(
  507. [](base::WeakPtr<TrayBackgroundView> view) {
  508. if (view)
  509. view->OnAnimationEnded();
  510. },
  511. weak_factory_.GetWeakPtr()))
  512. .Once()
  513. .SetDuration(kShowAnimationDelayMs)
  514. .Then()
  515. .SetDuration(base::TimeDelta())
  516. .SetOpacity(this, 0.0f)
  517. .SetTransform(this, transform)
  518. .Then()
  519. .SetDuration(kAnimationDurationForVisibilityMs)
  520. .SetOpacity(this, 1.0f)
  521. .SetTransform(this, gfx::Transform());
  522. }
  523. void TrayBackgroundView::BounceInAnimation() {
  524. gfx::Vector2dF bounce_up_location;
  525. gfx::Vector2dF bounce_down_location;
  526. switch (shelf_->alignment()) {
  527. case ShelfAlignment::kLeft:
  528. bounce_up_location = gfx::Vector2dF(kAnimationBounceUpDistance, 0);
  529. bounce_down_location = gfx::Vector2dF(-kAnimationBounceDownDistance, 0);
  530. break;
  531. case ShelfAlignment::kRight:
  532. bounce_up_location = gfx::Vector2dF(-kAnimationBounceUpDistance, 0);
  533. bounce_down_location = gfx::Vector2dF(kAnimationBounceDownDistance, 0);
  534. break;
  535. case ShelfAlignment::kBottom:
  536. case ShelfAlignment::kBottomLocked:
  537. default:
  538. bounce_up_location = gfx::Vector2dF(0, -kAnimationBounceUpDistance);
  539. bounce_down_location = gfx::Vector2dF(0, kAnimationBounceDownDistance);
  540. }
  541. gfx::Transform initial_scale;
  542. initial_scale.Scale3d(kAnimationBounceScaleFactor,
  543. kAnimationBounceScaleFactor, 1);
  544. gfx::Transform initial_state =
  545. gfx::TransformAboutPivot(GetLocalBounds().CenterPoint(), initial_scale);
  546. gfx::Transform scale_about_pivot = gfx::TransformAboutPivot(
  547. GetLocalBounds().CenterPoint(), gfx::Transform());
  548. scale_about_pivot.Translate(bounce_up_location);
  549. gfx::Transform move_down;
  550. move_down.Translate(bounce_down_location);
  551. ui::AnimationThroughputReporter reporter(
  552. layer()->GetAnimator(),
  553. metrics_util::ForSmoothness(base::BindRepeating([](int smoothness) {
  554. DCHECK(0 <= smoothness && smoothness <= 100);
  555. base::UmaHistogramPercentage(kBounceInAnimationSmoothnessHistogramName,
  556. smoothness);
  557. })));
  558. views::AnimationBuilder()
  559. .SetPreemptionStrategy(
  560. ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
  561. .OnAborted(base::BindOnce(
  562. [](base::WeakPtr<TrayBackgroundView> view) {
  563. if (view)
  564. view->OnAnimationAborted();
  565. },
  566. weak_factory_.GetWeakPtr()))
  567. .OnEnded(base::BindOnce(
  568. [](base::WeakPtr<TrayBackgroundView> view) {
  569. if (view)
  570. view->OnAnimationEnded();
  571. },
  572. weak_factory_.GetWeakPtr()))
  573. .Once()
  574. .SetDuration(base::TimeDelta())
  575. .SetOpacity(this, 1.0)
  576. .SetTransform(this, std::move(initial_state))
  577. .Then()
  578. .SetDuration(kAnimationDurationForBounceElement)
  579. .SetTransform(this, std::move(scale_about_pivot),
  580. gfx::Tween::FAST_OUT_SLOW_IN_3)
  581. .Then()
  582. .SetDuration(kAnimationDurationForBounceElement)
  583. .SetTransform(this, std::move(move_down), gfx::Tween::EASE_OUT_4)
  584. .Then()
  585. .SetDuration(kAnimationDurationForBounceElement)
  586. .SetTransform(this, gfx::Transform(), gfx::Tween::FAST_OUT_SLOW_IN_3);
  587. }
  588. // Any visibility updates should be called after the hide animation is
  589. // finished, otherwise the view will disappear immediately without animation
  590. // once the view's visibility is set to false.
  591. void TrayBackgroundView::HideAnimation() {
  592. gfx::Transform scale;
  593. scale.Scale3d(kAnimationBounceScaleFactor, kAnimationBounceScaleFactor, 1);
  594. gfx::Transform scale_about_pivot =
  595. gfx::TransformAboutPivot(GetLocalBounds().CenterPoint(), scale);
  596. ui::AnimationThroughputReporter reporter(
  597. layer()->GetAnimator(),
  598. metrics_util::ForSmoothness(base::BindRepeating([](int smoothness) {
  599. DCHECK(0 <= smoothness && smoothness <= 100);
  600. base::UmaHistogramPercentage(kHideAnimationSmoothnessHistogramName,
  601. smoothness);
  602. })));
  603. views::AnimationBuilder()
  604. .SetPreemptionStrategy(
  605. ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
  606. .OnAborted(base::BindOnce(
  607. [](base::WeakPtr<TrayBackgroundView> view) {
  608. if (view)
  609. view->OnAnimationAborted();
  610. },
  611. weak_factory_.GetWeakPtr()))
  612. .OnEnded(base::BindOnce(
  613. [](base::WeakPtr<TrayBackgroundView> view) {
  614. if (view)
  615. view->OnAnimationEnded();
  616. },
  617. weak_factory_.GetWeakPtr()))
  618. .Once()
  619. .SetDuration(kAnimationDurationForHideMs)
  620. .SetVisibility(this, false)
  621. .SetTransform(this, std::move(scale_about_pivot))
  622. .SetOpacity(this, 0.0f);
  623. }
  624. void TrayBackgroundView::SetIsActive(bool is_active) {
  625. if (is_active_ == is_active)
  626. return;
  627. is_active_ = is_active;
  628. views::InkDrop::Get(this)->AnimateToState(
  629. is_active_ ? views::InkDropState::ACTIVATED
  630. : views::InkDropState::DEACTIVATED,
  631. nullptr);
  632. }
  633. views::View* TrayBackgroundView::GetBubbleAnchor() const {
  634. return tray_container_;
  635. }
  636. gfx::Insets TrayBackgroundView::GetBubbleAnchorInsets() const {
  637. gfx::Insets anchor_insets = GetBubbleAnchor()->GetInsets();
  638. gfx::Insets tray_bg_insets = GetInsets();
  639. if (shelf_->alignment() == ShelfAlignment::kBottom ||
  640. shelf_->alignment() == ShelfAlignment::kBottomLocked) {
  641. return gfx::Insets::TLBR(-tray_bg_insets.top(), anchor_insets.left(),
  642. -tray_bg_insets.bottom(), anchor_insets.right());
  643. } else {
  644. return gfx::Insets::TLBR(anchor_insets.top(), -tray_bg_insets.left(),
  645. anchor_insets.bottom(), -tray_bg_insets.right());
  646. }
  647. }
  648. aura::Window* TrayBackgroundView::GetBubbleWindowContainer() {
  649. return Shell::GetContainer(
  650. tray_container()->GetWidget()->GetNativeWindow()->GetRootWindow(),
  651. kShellWindowId_SettingBubbleContainer);
  652. }
  653. gfx::Rect TrayBackgroundView::GetBackgroundBounds() const {
  654. gfx::Rect bounds = GetLocalBounds();
  655. bounds.Inset(GetBackgroundInsets());
  656. return bounds;
  657. }
  658. bool TrayBackgroundView::PerformAction(const ui::Event& event) {
  659. if (GetBubbleWidget())
  660. CloseBubble();
  661. else
  662. ShowBubble();
  663. return true;
  664. }
  665. void TrayBackgroundView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
  666. UpdateBackground();
  667. ActionableView::OnBoundsChanged(previous_bounds);
  668. }
  669. bool TrayBackgroundView::ShouldEnterPushedState(const ui::Event& event) {
  670. if (is_active_)
  671. return false;
  672. return ActionableView::ShouldEnterPushedState(event);
  673. }
  674. void TrayBackgroundView::HandlePerformActionResult(bool action_performed,
  675. const ui::Event& event) {
  676. // When an action is performed, ink drop ripple is handled in SetIsActive().
  677. if (action_performed)
  678. return;
  679. ActionableView::HandlePerformActionResult(action_performed, event);
  680. }
  681. std::unique_ptr<ui::SimpleMenuModel>
  682. TrayBackgroundView::CreateContextMenuModel() {
  683. return nullptr;
  684. }
  685. views::PaintInfo::ScaleType TrayBackgroundView::GetPaintScaleType() const {
  686. return views::PaintInfo::ScaleType::kUniformScaling;
  687. }
  688. gfx::Insets TrayBackgroundView::GetBackgroundInsets() const {
  689. gfx::Insets insets =
  690. GetMirroredBackgroundInsets(shelf_->IsHorizontalAlignment());
  691. // |insets| are relative to contents bounds. Change them to be relative to
  692. // local bounds.
  693. gfx::Insets local_contents_insets =
  694. GetLocalBounds().InsetsFrom(GetContentsBounds());
  695. MirrorInsetsIfNecessary(&local_contents_insets);
  696. insets += local_contents_insets;
  697. if (Shell::Get()->IsInTabletMode() && ShelfConfig::Get()->is_in_app()) {
  698. insets += gfx::Insets::VH(
  699. ShelfConfig::Get()->in_app_control_button_height_inset(), 0);
  700. }
  701. return insets;
  702. }
  703. bool TrayBackgroundView::GetEffectiveVisibility() {
  704. // When the virtual keyboard is visible, the effective visibility of the view
  705. // is solely determined by |show_with_virtual_keyboard_|.
  706. if (Shell::Get()
  707. ->system_tray_model()
  708. ->virtual_keyboard()
  709. ->arc_keyboard_visible()) {
  710. return show_with_virtual_keyboard_;
  711. }
  712. if (!visible_preferred_)
  713. return false;
  714. DCHECK(GetWidget());
  715. // When the status area is collapsed, the effective visibility of the view is
  716. // determined by |show_when_collapsed_|.
  717. StatusAreaWidget::CollapseState collapse_state =
  718. Shelf::ForWindow(GetWidget()->GetNativeWindow())
  719. ->GetStatusAreaWidget()
  720. ->collapse_state();
  721. if (collapse_state == StatusAreaWidget::CollapseState::COLLAPSED)
  722. return show_when_collapsed_;
  723. return true;
  724. }
  725. BEGIN_METADATA(TrayBackgroundView, ActionableView)
  726. END_METADATA
  727. } // namespace ash