Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(451)

Side by Side Diff: ash/system/tray/system_tray_bubble.cc

Issue 2099603002: Reland: mash: Convert TrayBackgroundView to wm common types (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix conflict Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ash/system/tray/system_tray_bubble.h ('k') | ash/system/tray/system_tray_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
5 #include "ash/system/tray/system_tray_bubble.h"
6
7 #include "ash/common/system/tray/system_tray_delegate.h"
8 #include "ash/common/system/tray/system_tray_item.h"
9 #include "ash/common/system/tray/tray_constants.h"
10 #include "ash/common/system/tray/tray_popup_item_container.h"
11 #include "ash/common/wm_shell.h"
12 #include "ash/shell.h"
13 #include "ash/system/tray/system_tray.h"
14 #include "ash/system/tray/tray_bubble_wrapper.h"
15 #include "base/threading/thread_task_runner_handle.h"
16 #include "ui/compositor/layer.h"
17 #include "ui/compositor/layer_animation_observer.h"
18 #include "ui/compositor/scoped_layer_animation_settings.h"
19 #include "ui/gfx/canvas.h"
20 #include "ui/views/layout/box_layout.h"
21 #include "ui/views/view.h"
22 #include "ui/views/widget/widget.h"
23
24 using views::TrayBubbleView;
25
26 namespace ash {
27
28 namespace {
29
30 // Normally a detailed view is the same size as the default view. However,
31 // when showing a detailed view directly (e.g. clicking on a notification),
32 // we may not know the height of the default view, or the default view may
33 // be too short, so we use this as a default and minimum height for any
34 // detailed view.
35 const int kDetailedBubbleMaxHeight = kTrayPopupItemHeight * 5;
36
37 // Duration of swipe animation used when transitioning from a default to
38 // detailed view or vice versa.
39 const int kSwipeDelayMS = 150;
40
41 // Implicit animation observer that deletes itself and the layer at the end of
42 // the animation.
43 class AnimationObserverDeleteLayer : public ui::ImplicitAnimationObserver {
44 public:
45 explicit AnimationObserverDeleteLayer(ui::Layer* layer)
46 : layer_(layer) {
47 }
48
49 ~AnimationObserverDeleteLayer() override {}
50
51 void OnImplicitAnimationsCompleted() override {
52 base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
53 }
54
55 private:
56 std::unique_ptr<ui::Layer> layer_;
57
58 DISALLOW_COPY_AND_ASSIGN(AnimationObserverDeleteLayer);
59 };
60
61 } // namespace
62
63 // SystemTrayBubble
64
65 SystemTrayBubble::SystemTrayBubble(
66 ash::SystemTray* tray,
67 const std::vector<ash::SystemTrayItem*>& items,
68 BubbleType bubble_type)
69 : tray_(tray),
70 bubble_view_(NULL),
71 items_(items),
72 bubble_type_(bubble_type),
73 autoclose_delay_(0) {
74 }
75
76 SystemTrayBubble::~SystemTrayBubble() {
77 DestroyItemViews();
78 // Reset the host pointer in bubble_view_ in case its destruction is deferred.
79 if (bubble_view_)
80 bubble_view_->reset_delegate();
81 }
82
83 void SystemTrayBubble::UpdateView(
84 const std::vector<ash::SystemTrayItem*>& items,
85 BubbleType bubble_type) {
86 DCHECK(bubble_type != BUBBLE_TYPE_NOTIFICATION);
87
88 std::unique_ptr<ui::Layer> scoped_layer;
89 if (bubble_type != bubble_type_) {
90 base::TimeDelta swipe_duration =
91 base::TimeDelta::FromMilliseconds(kSwipeDelayMS);
92 scoped_layer = bubble_view_->RecreateLayer();
93 // Keep the reference to layer as we need it after releasing it.
94 ui::Layer* layer = scoped_layer.get();
95 DCHECK(layer);
96 layer->SuppressPaint();
97
98 // When transitioning from detailed view to default view, animate the
99 // existing view (slide out towards the right).
100 if (bubble_type == BUBBLE_TYPE_DEFAULT) {
101 ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
102 settings.AddObserver(
103 new AnimationObserverDeleteLayer(scoped_layer.release()));
104 settings.SetTransitionDuration(swipe_duration);
105 settings.SetTweenType(gfx::Tween::EASE_OUT);
106 gfx::Transform transform;
107 transform.Translate(layer->bounds().width(), 0.0);
108 layer->SetTransform(transform);
109 }
110
111 {
112 // Add a shadow layer to make the old layer darker as the animation
113 // progresses.
114 ui::Layer* shadow = new ui::Layer(ui::LAYER_SOLID_COLOR);
115 shadow->SetColor(SK_ColorBLACK);
116 shadow->SetOpacity(0.01f);
117 shadow->SetBounds(layer->bounds());
118 layer->Add(shadow);
119 layer->StackAtTop(shadow);
120 {
121 // Animate the darkening effect a little longer than the swipe-in. This
122 // is to make sure the darkening animation does not end up finishing
123 // early, because the dark layer goes away at the end of the animation,
124 // and there is a brief moment when the old view is still visible, but
125 // it does not have the shadow layer on top.
126 ui::ScopedLayerAnimationSettings settings(shadow->GetAnimator());
127 settings.AddObserver(new AnimationObserverDeleteLayer(shadow));
128 settings.SetTransitionDuration(swipe_duration +
129 base::TimeDelta::FromMilliseconds(150));
130 settings.SetTweenType(gfx::Tween::LINEAR);
131 shadow->SetOpacity(0.15f);
132 }
133 }
134 }
135
136 DestroyItemViews();
137 bubble_view_->RemoveAllChildViews(true);
138
139 items_ = items;
140 bubble_type_ = bubble_type;
141 CreateItemViews(WmShell::Get()->system_tray_delegate()->GetUserLoginStatus());
142
143 // Close bubble view if we failed to create the item view.
144 if (!bubble_view_->has_children()) {
145 Close();
146 return;
147 }
148
149 bubble_view_->GetWidget()->GetContentsView()->Layout();
150 // Make sure that the bubble is large enough for the default view.
151 if (bubble_type_ == BUBBLE_TYPE_DEFAULT) {
152 bubble_view_->SetMaxHeight(0); // Clear max height limit.
153 }
154
155 if (scoped_layer) {
156 // When transitioning from default view to detailed view, animate the new
157 // view (slide in from the right).
158 if (bubble_type == BUBBLE_TYPE_DETAILED) {
159 ui::Layer* new_layer = bubble_view_->layer();
160
161 // Make sure the new layer is stacked above the old layer during the
162 // animation.
163 new_layer->parent()->StackAbove(new_layer, scoped_layer.get());
164
165 gfx::Rect bounds = new_layer->bounds();
166 gfx::Transform transform;
167 transform.Translate(bounds.width(), 0.0);
168 new_layer->SetTransform(transform);
169 {
170 ui::ScopedLayerAnimationSettings settings(new_layer->GetAnimator());
171 settings.AddObserver(
172 new AnimationObserverDeleteLayer(scoped_layer.release()));
173 settings.SetTransitionDuration(
174 base::TimeDelta::FromMilliseconds(kSwipeDelayMS));
175 settings.SetTweenType(gfx::Tween::EASE_OUT);
176 new_layer->SetTransform(gfx::Transform());
177 }
178 }
179 }
180 }
181
182 void SystemTrayBubble::InitView(views::View* anchor,
183 LoginStatus login_status,
184 TrayBubbleView::InitParams* init_params) {
185 DCHECK(anchor);
186 DCHECK(!bubble_view_);
187
188 if (bubble_type_ == BUBBLE_TYPE_DETAILED &&
189 init_params->max_height < kDetailedBubbleMaxHeight) {
190 init_params->max_height = kDetailedBubbleMaxHeight;
191 } else if (bubble_type_ == BUBBLE_TYPE_NOTIFICATION) {
192 init_params->close_on_deactivate = false;
193 }
194 // The TrayBubbleView will use |anchor| and |tray_| to determine the parent
195 // container for the bubble.
196 bubble_view_ = TrayBubbleView::Create(anchor, tray_, init_params);
197 bubble_view_->set_adjust_if_offscreen(false);
198 CreateItemViews(login_status);
199
200 if (bubble_view_->CanActivate()) {
201 bubble_view_->NotifyAccessibilityEvent(
202 ui::AX_EVENT_ALERT, true);
203 }
204 }
205
206 void SystemTrayBubble::FocusDefaultIfNeeded() {
207 views::FocusManager* manager = bubble_view_->GetFocusManager();
208 if (!manager || manager->GetFocusedView())
209 return;
210
211 views::View* view = manager->GetNextFocusableView(NULL, NULL, false, false);
212 if (view)
213 view->RequestFocus();
214 }
215
216 void SystemTrayBubble::DestroyItemViews() {
217 for (std::vector<ash::SystemTrayItem*>::iterator it = items_.begin();
218 it != items_.end();
219 ++it) {
220 switch (bubble_type_) {
221 case BUBBLE_TYPE_DEFAULT:
222 (*it)->DestroyDefaultView();
223 break;
224 case BUBBLE_TYPE_DETAILED:
225 (*it)->DestroyDetailedView();
226 break;
227 case BUBBLE_TYPE_NOTIFICATION:
228 (*it)->DestroyNotificationView();
229 break;
230 }
231 }
232 }
233
234 void SystemTrayBubble::BubbleViewDestroyed() {
235 bubble_view_ = NULL;
236 }
237
238 void SystemTrayBubble::StartAutoCloseTimer(int seconds) {
239 autoclose_.Stop();
240 autoclose_delay_ = seconds;
241 if (autoclose_delay_) {
242 autoclose_.Start(FROM_HERE,
243 base::TimeDelta::FromSeconds(autoclose_delay_),
244 this, &SystemTrayBubble::Close);
245 }
246 }
247
248 void SystemTrayBubble::StopAutoCloseTimer() {
249 autoclose_.Stop();
250 }
251
252 void SystemTrayBubble::RestartAutoCloseTimer() {
253 if (autoclose_delay_)
254 StartAutoCloseTimer(autoclose_delay_);
255 }
256
257 void SystemTrayBubble::Close() {
258 tray_->HideBubbleWithView(bubble_view());
259 }
260
261 void SystemTrayBubble::SetVisible(bool is_visible) {
262 if (!bubble_view_)
263 return;
264 views::Widget* bubble_widget = bubble_view_->GetWidget();
265 if (is_visible)
266 bubble_widget->Show();
267 else
268 bubble_widget->Hide();
269 }
270
271 bool SystemTrayBubble::IsVisible() {
272 return bubble_view() && bubble_view()->GetWidget()->IsVisible();
273 }
274
275 bool SystemTrayBubble::ShouldShowShelf() const {
276 for (std::vector<ash::SystemTrayItem*>::const_iterator it = items_.begin();
277 it != items_.end();
278 ++it) {
279 if ((*it)->ShouldShowShelf())
280 return true;
281 }
282 return false;
283 }
284
285 void SystemTrayBubble::CreateItemViews(LoginStatus login_status) {
286 std::vector<views::View*> item_views;
287 // If a system modal dialog is present, create the same tray as
288 // in locked state.
289 if (WmShell::Get()->IsSystemModalWindowOpen() &&
290 login_status != LoginStatus::NOT_LOGGED_IN) {
291 login_status = LoginStatus::LOCKED;
292 }
293
294 views::View* focus_view = NULL;
295 for (size_t i = 0; i < items_.size(); ++i) {
296 views::View* view = NULL;
297 switch (bubble_type_) {
298 case BUBBLE_TYPE_DEFAULT:
299 view = items_[i]->CreateDefaultView(login_status);
300 if (items_[i]->restore_focus())
301 focus_view = view;
302 break;
303 case BUBBLE_TYPE_DETAILED:
304 view = items_[i]->CreateDetailedView(login_status);
305 break;
306 case BUBBLE_TYPE_NOTIFICATION:
307 view = items_[i]->CreateNotificationView(login_status);
308 break;
309 }
310 if (view)
311 item_views.push_back(view);
312 }
313
314 bool is_default_bubble = bubble_type_ == BUBBLE_TYPE_DEFAULT;
315 for (size_t i = 0; i < item_views.size(); ++i) {
316 // For default view, draw bottom border for each item, except the last
317 // 2 items, which are the bottom header row and the one just above it.
318 bubble_view_->AddChildView(new TrayPopupItemContainer(
319 item_views[i], is_default_bubble,
320 is_default_bubble && (i < item_views.size() - 2)));
321 }
322 if (focus_view)
323 focus_view->RequestFocus();
324 }
325
326 } // namespace ash
OLDNEW
« no previous file with comments | « ash/system/tray/system_tray_bubble.h ('k') | ash/system/tray/system_tray_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698