1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
ash / system / tray / tray_background_view.h [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_SYSTEM_TRAY_TRAY_BACKGROUND_VIEW_H_
#define ASH_SYSTEM_TRAY_TRAY_BACKGROUND_VIEW_H_
#include <memory>
#include "ash/ash_export.h"
#include "ash/constants/tray_background_view_catalog.h"
#include "ash/system/model/virtual_keyboard_model.h"
#include "ash/system/tray/tray_bubble_view.h"
#include "ash/system/user/login_status.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "ui/base/mojom/menu_source_type.mojom-forward.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/views/context_menu_controller.h"
namespace ui {
class Event;
} // namespace ui
namespace views {
class AnimationAbortHandle;
class MenuRunner;
class View;
} // namespace views
namespace ash {
class Shelf;
class TrayContainer;
// Base class for some children of StatusAreaWidget. This class handles setting
// and animating the background when the Launcher is shown/hidden. Note that
// events targeting a `TrayBackgroundView`'s view hierarchy are ignored while
// the `TrayBackgroundView`'s hide animation is running.
class ASH_EXPORT TrayBackgroundView : public views::Button,
public views::ContextMenuController,
public TrayBubbleView::Delegate,
public VirtualKeyboardModel::Observer {
METADATA_HEADER(TrayBackgroundView, views::Button)
public:
// Inherit from this class to be notified of events that happen for a specific
// `TrayBackgroundView`.
class Observer : public base::CheckedObserver {
public:
// Called when the `TrayBackgroundView`'s preferred visibility changes.
// `visible_preferred` is the new preferred visibility.
virtual void OnVisiblePreferredChanged(bool visible_preferred) = 0;
};
// Records TrayBackgroundView.Pressed metrics for all types of trays. All
// nested buttons inside `TrayBackgroundView` should use this delegate if they
// want to record the TrayBackgroundView.Pressed metric.
class TrayButtonControllerDelegate
: public Button::DefaultButtonControllerDelegate {
public:
TrayButtonControllerDelegate(views::Button* button,
TrayBackgroundViewCatalogName catalog_name);
void NotifyClick(const ui::Event& event) override;
private:
// The catalog name, used to record metrics on feature integrations.
TrayBackgroundViewCatalogName catalog_name_;
};
enum RoundedCornerBehavior {
kNotRounded,
kStartRounded,
kEndRounded,
kAllRounded
};
TrayBackgroundView(Shelf* shelf,
const TrayBackgroundViewCatalogName catalog_name,
RoundedCornerBehavior corner_behavior = kAllRounded);
TrayBackgroundView(const TrayBackgroundView&) = delete;
TrayBackgroundView& operator=(const TrayBackgroundView&) = delete;
~TrayBackgroundView() override;
void AddTrayBackgroundViewObserver(Observer* observer);
void RemoveTrayBackgroundViewObserver(Observer* observer);
// Called after the tray has been added to the widget containing it.
virtual void Initialize();
// Initializes animations for the bubble. This contains only a fade out
// animation that hides `bubble_widget` when it becomes invisible.
static void InitializeBubbleAnimations(views::Widget* bubble_widget);
// views::Button:
void OnThemeChanged() override;
// VirtualKeyboardModel::Observer:
void OnVirtualKeyboardVisibilityChanged() override;
// Updates PreviousFocus and NextFocus accessibility properties for the
// TrayBackgroundView.
void UpdateAccessibleNavFocus(Shelf* shelf);
// Returns the associated tray bubble view, if one exists. Otherwise returns
// nullptr.
virtual TrayBubbleView* GetBubbleView();
// Returns the associated tray bubble widget, if a bubble exists. Otherwise
// returns nullptr.
virtual views::Widget* GetBubbleWidget() const;
// Returns a lock that prevents window activation from closing bubbles.
[[nodiscard]] static base::ScopedClosureRunner
DisableCloseBubbleOnWindowActivated();
// Whether a window activation change should close bubbles.
static bool ShouldCloseBubbleOnWindowActivated();
// Closes the associated tray bubble view if it exists and is currently
// showing.
virtual void CloseBubbleInternal() {}
// Shows the associated tray bubble if one exists.
virtual void ShowBubble();
// Calculates the ideal bounds that this view should have depending on the
// constraints.
virtual void CalculateTargetBounds();
// Makes this view's bounds and layout match its calculated target bounds.
virtual void UpdateLayout();
// Called to update the tray button after the login status changes.
virtual void UpdateAfterLoginStatusChange();
// Called whenever the lock state changes. `locked` represents the current
// lock state.
void UpdateAfterLockStateChange(bool locked);
// Called whenever the status area's collapse state changes.
virtual void UpdateAfterStatusAreaCollapseChange();
// Called when the anchor (tray or bubble) may have moved or changed.
virtual void AnchorUpdated() {}
// TODO(crbug.com/379818907): In process of deprecation; derived classes that
// override this use it to set their accessible names.
virtual std::u16string GetAccessibleNameForTray();
// Called when a locale change is detected. It should reload any strings the
// view may be using. Note that the locale is not expected to change after the
// user logs in.
virtual void HandleLocaleChange() = 0;
// Hides the bubble associated with |bubble_view|. Called when the widget
// is closed.
virtual void HideBubbleWithView(const TrayBubbleView* bubble_view) = 0;
// Called by the bubble wrapper when a click event occurs outside the bubble.
// May close the bubble.
virtual void ClickedOutsideBubble(const ui::LocatedEvent& event) = 0;
// Returns true if tray bubble view is cached when hidden
virtual bool CacheBubbleViewForHide() const;
// Updates the background layer.
virtual void UpdateBackground();
// Updates the color of either the icon or the label of this view based on the
// active state specified by `is_active`.
virtual void UpdateTrayItemColor(bool is_active) = 0;
// Calls `CloseBubbleInternal` which is implemented by each child tray view.
// The focusing behavior is handled in this method.
void CloseBubble();
// Gets the anchor for bubbles, which is tray_container().
views::View* GetBubbleAnchor() const;
// Gets additional insets for positioning bubbles relative to
// tray_container().
gfx::Insets GetBubbleAnchorInsets() const;
// Returns the container window for the bubble (on the proper display).
aura::Window* GetBubbleWindowContainer();
// Helper function that calculates background bounds relative to local bounds
// based on background insets returned from GetBackgroundInsets().
gfx::Rect GetBackgroundBounds() const;
// Sets whether the tray item should be shown by default (e.g. it is
// activated). The effective visibility of the tray item is determined by the
// current state of the status tray (i.e. whether the virtual keyboard is
// showing or if it is collapsed).
virtual void SetVisiblePreferred(bool visible_preferred);
bool visible_preferred() const { return visible_preferred_; }
// Disables bounce in and fade in animation. The animation will remain
// disabled until the returned scoped closure runner is run.
[[nodiscard]] base::ScopedClosureRunner DisableShowAnimation();
// Registers a client's request to use custom visibility animations. The
// custom animation must be executed by the client; `TrayBackgroundView` does
// not run any custom animations (it will simply do nothing rather than run
// the default visibility animations). Custom animations will be used until
// the returned scoped closure runner is run.
[[nodiscard]] base::ScopedClosureRunner SetUseCustomVisibilityAnimations();
// Returns true if the view is showing a context menu.
bool IsShowingMenu() const;
// Set the rounded corner behavior for this tray item.
void SetRoundedCornerBehavior(RoundedCornerBehavior corner_behavior);
// Returns the corners based on the `corner_behavior_`;
gfx::RoundedCornersF GetRoundedCorners();
// Returns a weak pointer to this instance.
base::WeakPtr<TrayBackgroundView> GetWeakPtr();
// Checks if we should show bounce in or fade in animation.
bool IsShowAnimationEnabled();
// Callbacks for Animations
void OnHideAnimationStarted();
void OnAnimationAborted();
virtual void OnAnimationEnded();
void SetIsActive(bool is_active);
bool is_active() const { return is_active_; }
TrayContainer* tray_container() const { return tray_container_; }
Shelf* shelf() { return shelf_; }
TrayBackgroundViewCatalogName catalog_name() const { return catalog_name_; }
// Updates the visibility of this tray's separator.
void set_separator_visibility(bool visible) { separator_visible_ = visible; }
// Sets whether to show the view when the status area is collapsed.
void set_show_when_collapsed(bool show_when_collapsed) {
show_when_collapsed_ = show_when_collapsed;
}
// Sets whether changes in lock state should cause this tray's bubble to close
// if it is currently open.
void set_should_close_bubble_on_lock_state_change(
bool should_close_bubble_on_lock_state_change) {
should_close_bubble_on_lock_state_change_ =
should_close_bubble_on_lock_state_change;
}
protected:
// views::Button:
void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
bool ShouldEnterPushedState(const ui::Event& event) override;
views::PaintInfo::ScaleType GetPaintScaleType() const override;
virtual void OnShouldShowAnimationChanged(bool should_animate) {}
// Specifies the menu that appears when this tray is right-clicked if
// `SetContextMenuEnabled(true)` has been called. Default implementation
// returns a nullptr, in which case no context menu is shown.
virtual std::unique_ptr<ui::SimpleMenuModel> CreateContextMenuModel();
// After hide animation is finished/aborted/removed, we will need to do an
// update to the view's visibility and the view's status area widget state.
virtual void OnVisibilityAnimationFinished(bool should_log_visible_pod_count,
bool aborted);
// Used to start and stop pulse animation on tray button.
void StartPulseAnimation();
void StopPulseAnimation();
// Used to bounce in animation on tray button.
void BounceInAnimation(bool scale_animation = true);
void SetContextMenuEnabled(bool should_enable_menu) {
set_context_menu_controller(should_enable_menu ? this : nullptr);
}
// Logs the tray's visibility UMA.
void TrackVisibilityUMA(bool visible_preferred) const;
void set_show_with_virtual_keyboard(bool show_with_virtual_keyboard) {
show_with_virtual_keyboard_ = show_with_virtual_keyboard;
}
void set_use_bounce_in_animation(bool use_bounce_in_animation) {
use_bounce_in_animation_ = use_bounce_in_animation;
}
private:
class TrayWidgetObserver;
class TrayBackgroundViewSessionChangeHandler;
friend class StatusAreaWidgetTest;
void StartVisibilityAnimation(bool visible);
// Updates status area widget by calling `UpdateCollapseState()` and
// `LogVisiblePodCountMetric()`.
void UpdateStatusArea(bool should_log_visible_pod_count);
// views::ContextMenuController:
void ShowContextMenuForViewImpl(
views::View* source,
const gfx::Point& point,
ui::mojom::MenuSourceType source_type) override;
// views::View:
void AboutToRequestFocusFromTabTraversal(bool reverse) override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
void ChildPreferredSizeChanged(views::View* child) override;
// In some cases, we expect the layer's visibility to be set to false right
// away when the layer is replaced. See
// `OverviewButtonTrayTest.HideAnimationAlwaysCompletesOnDelete` test as an
// example. We use `::wm::RecreateLayers(root_window)` to create fresh layers
// for the window. If we don't override this method, the old layer and its
// child layers will still be there until all the animation finished.
std::unique_ptr<ui::Layer> RecreateLayer() override;
// Applies transformations to the `layer()` to animate the view when
// `SetVisible(false)` is called.
void FadeInAnimation();
void HideAnimation();
// Helper function that calculates background insets relative to local bounds.
gfx::Insets GetBackgroundInsets() const;
// Returns the effective visibility of the tray item based on the current
// state.
bool GetEffectiveVisibility();
// Checks if we should use custom visibility animations.
bool ShouldUseCustomVisibilityAnimations() const;
// For Material Next: Updates the background color based on active state.
void UpdateBackgroundColor(bool active);
// Add and remove ripple_layer_ from parent.
void AddRippleLayer();
void RemoveRippleLayer();
// Start playing the pulse animation on button. ONLY called in
// `StartPulseAnimation()` when all layers are ready.
void PlayPulseAnimation();
void StartPulseAnimationCoolDownTimer();
// The shelf containing the system tray for this view.
raw_ptr<Shelf> shelf_;
// The catalog name, used to record metrics on feature integrations.
const TrayBackgroundViewCatalogName catalog_name_;
// Convenience pointer to the contents view.
raw_ptr<TrayContainer> tray_container_;
// A separate layer for ripple aimation.
std::unique_ptr<ui::Layer> ripple_layer_;
// The handle to abort ripple and pulse animation.
std::unique_ptr<views::AnimationAbortHandle>
ripple_and_pulse_animation_abort_handle_;
base::OneShotTimer pulse_animation_cool_down_timer_;
// Determines if the view is active. This changes how the ink drop ripples
// behave.
bool is_active_;
// Visibility of this tray's separator which is a line of 1x32px and 4px to
// right of tray.
bool separator_visible_;
// During virtual keyboard is shown, visibility changes to TrayBackgroundView
// are ignored. In such case, preferred visibility is reflected after the
// virtual keyboard is hidden.
bool visible_preferred_;
// If true, the view always shows up when virtual keyboard is visible.
bool show_with_virtual_keyboard_;
// If true, the view is visible when the status area is collapsed.
bool show_when_collapsed_;
bool use_bounce_in_animation_ = true;
bool is_starting_animation_ = false;
// Number of active requests to disable the bounce-in and fade-in animation.
size_t disable_show_animation_count_ = 0;
// Number of active requests to use custom visibility animations.
size_t use_custom_visibility_animation_count_ = 0;
// The shape of this tray which is only applied to the horizontal tray.
// Defaults to `kAllRounded`.
RoundedCornerBehavior corner_behavior_;
std::unique_ptr<TrayWidgetObserver> widget_observer_;
std::unique_ptr<TrayBackgroundViewSessionChangeHandler> handler_;
std::unique_ptr<ui::SimpleMenuModel> context_menu_model_;
std::unique_ptr<views::MenuRunner> context_menu_runner_;
// Whether changes in lock state should cause this tray's bubble to close if
// it is currently open.
bool should_close_bubble_on_lock_state_change_;
base::ObserverList<Observer> observers_;
base::WeakPtrFactory<TrayBackgroundView> weak_factory_{this};
};
} // namespace ash
#endif // ASH_SYSTEM_TRAY_TRAY_BACKGROUND_VIEW_H_