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

Side by Side Diff: ash/system/tray/tray_background_view.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/tray_background_view.h ('k') | ash/system/tray/tray_bubble_wrapper.h » ('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/tray_background_view.h"
6
7 #include "ash/common/material_design/material_design_controller.h"
8 #include "ash/common/shelf/shelf_constants.h"
9 #include "ash/common/shelf/wm_shelf.h"
10 #include "ash/common/shelf/wm_shelf_util.h"
11 #include "ash/common/shell_window_ids.h"
12 #include "ash/common/system/tray/tray_constants.h"
13 #include "ash/screen_util.h"
14 #include "ash/shell.h"
15 #include "ash/system/status_area_widget.h"
16 #include "ash/system/status_area_widget_delegate.h"
17 #include "ash/system/tray/system_tray.h"
18 #include "ash/system/tray/tray_event_filter.h"
19 #include "ash/wm/window_animations.h"
20 #include "base/command_line.h"
21 #include "grit/ash_resources.h"
22 #include "ui/accessibility/ax_view_state.h"
23 #include "ui/aura/window.h"
24 #include "ui/aura/window_event_dispatcher.h"
25 #include "ui/base/nine_image_painter_factory.h"
26 #include "ui/base/ui_base_switches_util.h"
27 #include "ui/compositor/layer.h"
28 #include "ui/compositor/layer_animation_element.h"
29 #include "ui/compositor/scoped_layer_animation_settings.h"
30 #include "ui/events/event_constants.h"
31 #include "ui/gfx/animation/tween.h"
32 #include "ui/gfx/canvas.h"
33 #include "ui/gfx/geometry/rect.h"
34 #include "ui/gfx/image/image_skia.h"
35 #include "ui/gfx/image/image_skia_operations.h"
36 #include "ui/gfx/nine_image_painter.h"
37 #include "ui/gfx/skia_util.h"
38 #include "ui/gfx/transform.h"
39 #include "ui/views/background.h"
40 #include "ui/views/layout/box_layout.h"
41 #include "ui/wm/core/window_animations.h"
42
43 namespace {
44
45 const int kAnimationDurationForPopupMs = 200;
46
47 // Duration of opacity animation for visibility changes.
48 const int kAnimationDurationForVisibilityMs = 250;
49
50 // When becoming visible delay the animation so that StatusAreaWidgetDelegate
51 // can animate sibling views out of the position to be occuped by the
52 // TrayBackgroundView.
53 const int kShowAnimationDelayMs = 100;
54
55 } // namespace
56
57 using views::TrayBubbleView;
58
59 namespace ash {
60
61 // static
62 const char TrayBackgroundView::kViewClassName[] = "tray/TrayBackgroundView";
63
64 // Used to track when the anchor widget changes position on screen so that the
65 // bubble position can be updated.
66 class TrayBackgroundView::TrayWidgetObserver : public views::WidgetObserver {
67 public:
68 explicit TrayWidgetObserver(TrayBackgroundView* host)
69 : host_(host) {
70 }
71
72 void OnWidgetBoundsChanged(views::Widget* widget,
73 const gfx::Rect& new_bounds) override {
74 host_->AnchorUpdated();
75 }
76
77 void OnWidgetVisibilityChanged(views::Widget* widget, bool visible) override {
78 host_->AnchorUpdated();
79 }
80
81 private:
82 TrayBackgroundView* host_;
83
84 DISALLOW_COPY_AND_ASSIGN(TrayWidgetObserver);
85 };
86
87 class TrayBackground : public views::Background {
88 public:
89 const static int kImageTypeDefault = 0;
90 const static int kImageTypeOnBlack = 1;
91 const static int kImageTypePressed = 2;
92 const static int kNumStates = 3;
93
94 const static int kImageHorizontal = 0;
95 const static int kImageVertical = 1;
96 const static int kNumOrientations = 2;
97
98 explicit TrayBackground(TrayBackgroundView* tray_background_view) :
99 tray_background_view_(tray_background_view) {
100 }
101
102 ~TrayBackground() override {}
103
104 private:
105 WmShelf* GetShelf() const {
106 return tray_background_view_->GetShelf();
107 }
108
109 void PaintMaterial(gfx::Canvas* canvas, views::View* view) const {
110 SkColor background_color = SK_ColorTRANSPARENT;
111 if (GetShelf()->GetBackgroundType() ==
112 ShelfBackgroundType::SHELF_BACKGROUND_DEFAULT) {
113 background_color = SkColorSetA(kShelfBaseColor,
114 GetShelfConstant(SHELF_BACKGROUND_ALPHA));
115 }
116
117 // TODO(bruthig|tdanderson): The background should be changed using a
118 // fade in/out animation.
119 const int kCornerRadius = 2;
120
121 SkPaint background_paint;
122 background_paint.setFlags(SkPaint::kAntiAlias_Flag);
123 background_paint.setColor(background_color);
124 canvas->DrawRoundRect(view->GetLocalBounds(), kCornerRadius,
125 background_paint);
126
127 if (tray_background_view_->draw_background_as_active()) {
128 SkPaint highlight_paint;
129 highlight_paint.setFlags(SkPaint::kAntiAlias_Flag);
130 highlight_paint.setColor(kShelfButtonActivatedHighlightColor);
131 canvas->DrawRoundRect(view->GetLocalBounds(), kCornerRadius,
132 highlight_paint);
133 }
134 }
135
136 void PaintNonMaterial(gfx::Canvas* canvas, views::View* view) const {
137 const int kGridSizeForPainter = 9;
138 const int kImages[kNumOrientations][kNumStates][kGridSizeForPainter] = {
139 { // Horizontal
140 IMAGE_GRID_HORIZONTAL(IDR_AURA_TRAY_BG_HORIZ),
141 IMAGE_GRID_HORIZONTAL(IDR_AURA_TRAY_BG_HORIZ_ONBLACK),
142 IMAGE_GRID_HORIZONTAL(IDR_AURA_TRAY_BG_HORIZ_PRESSED),
143 },
144 { // Vertical
145 IMAGE_GRID_VERTICAL(IDR_AURA_TRAY_BG_VERTICAL),
146 IMAGE_GRID_VERTICAL(IDR_AURA_TRAY_BG_VERTICAL_ONBLACK),
147 IMAGE_GRID_VERTICAL(IDR_AURA_TRAY_BG_VERTICAL_PRESSED),
148 }
149 };
150
151 WmShelf* shelf = GetShelf();
152 const int orientation = IsHorizontalAlignment(shelf->GetAlignment())
153 ? kImageHorizontal
154 : kImageVertical;
155
156 int state = kImageTypeDefault;
157 if (tray_background_view_->draw_background_as_active())
158 state = kImageTypePressed;
159 else if (shelf->IsDimmed())
160 state = kImageTypeOnBlack;
161 else
162 state = kImageTypeDefault;
163
164 ui::CreateNineImagePainter(kImages[orientation][state])
165 ->Paint(canvas, view->GetLocalBounds());
166 }
167
168 // Overridden from views::Background.
169 void Paint(gfx::Canvas* canvas, views::View* view) const override {
170 if (MaterialDesignController::IsShelfMaterial())
171 PaintMaterial(canvas, view);
172 else
173 PaintNonMaterial(canvas, view);
174 }
175
176 // Reference to the TrayBackgroundView for which this is a background.
177 TrayBackgroundView* tray_background_view_;
178
179 DISALLOW_COPY_AND_ASSIGN(TrayBackground);
180 };
181
182 TrayBackgroundView::TrayContainer::TrayContainer(ShelfAlignment alignment)
183 : alignment_(alignment) {
184 UpdateLayout();
185 }
186
187 void TrayBackgroundView::TrayContainer::SetAlignment(ShelfAlignment alignment) {
188 if (alignment_ == alignment)
189 return;
190 alignment_ = alignment;
191 UpdateLayout();
192 }
193
194 gfx::Size TrayBackgroundView::TrayContainer::GetPreferredSize() const {
195 if (size_.IsEmpty())
196 return views::View::GetPreferredSize();
197 return size_;
198 }
199
200 void TrayBackgroundView::TrayContainer::ChildPreferredSizeChanged(
201 views::View* child) {
202 PreferredSizeChanged();
203 }
204
205 void TrayBackgroundView::TrayContainer::ChildVisibilityChanged(View* child) {
206 PreferredSizeChanged();
207 }
208
209 void TrayBackgroundView::TrayContainer::ViewHierarchyChanged(
210 const ViewHierarchyChangedDetails& details) {
211 if (details.parent == this)
212 PreferredSizeChanged();
213 }
214
215 // TODO(tdanderson): Adjust TrayContainer borders according to the material
216 // design specs. See crbug.com/617295.
217 void TrayBackgroundView::TrayContainer::UpdateLayout() {
218 // Adjust the size of status tray dark background by adding additional
219 // empty border.
220 views::BoxLayout::Orientation orientation =
221 IsHorizontalAlignment(alignment_) ? views::BoxLayout::kHorizontal
222 : views::BoxLayout::kVertical;
223 SetBorder(views::Border::CreateEmptyBorder(
224 kAdjustBackgroundPadding, kAdjustBackgroundPadding,
225 kAdjustBackgroundPadding, kAdjustBackgroundPadding));
226
227 views::BoxLayout* layout = new views::BoxLayout(orientation, 0, 0, 0);
228 layout->SetDefaultFlex(1);
229 views::View::SetLayoutManager(layout);
230 PreferredSizeChanged();
231 }
232
233 ////////////////////////////////////////////////////////////////////////////////
234 // TrayBackgroundView
235
236 TrayBackgroundView::TrayBackgroundView(StatusAreaWidget* status_area_widget)
237 : status_area_widget_(status_area_widget),
238 tray_container_(NULL),
239 shelf_alignment_(SHELF_ALIGNMENT_BOTTOM),
240 background_(NULL),
241 draw_background_as_active_(false),
242 widget_observer_(new TrayWidgetObserver(this)) {
243 DCHECK(status_area_widget->wm_shelf());
244 set_notify_enter_exit_on_child(true);
245
246 tray_container_ = new TrayContainer(shelf_alignment_);
247 SetContents(tray_container_);
248 tray_event_filter_.reset(new TrayEventFilter);
249
250 SetPaintToLayer(true);
251 layer()->SetFillsBoundsOpaquely(false);
252 // Start the tray items not visible, because visibility changes are animated.
253 views::View::SetVisible(false);
254 }
255
256 TrayBackgroundView::~TrayBackgroundView() {
257 if (GetWidget())
258 GetWidget()->RemoveObserver(widget_observer_.get());
259 StopObservingImplicitAnimations();
260 }
261
262 void TrayBackgroundView::Initialize() {
263 GetWidget()->AddObserver(widget_observer_.get());
264 }
265
266 // static
267 void TrayBackgroundView::InitializeBubbleAnimations(
268 views::Widget* bubble_widget) {
269 aura::Window* window = bubble_widget->GetNativeWindow();
270 ::wm::SetWindowVisibilityAnimationType(
271 window, ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
272 ::wm::SetWindowVisibilityAnimationTransition(window, ::wm::ANIMATE_HIDE);
273 ::wm::SetWindowVisibilityAnimationDuration(
274 window, base::TimeDelta::FromMilliseconds(kAnimationDurationForPopupMs));
275 }
276
277 void TrayBackgroundView::SetVisible(bool visible) {
278 if (visible == layer()->GetTargetVisibility())
279 return;
280
281 if (visible) {
282 // The alignment of the shelf can change while the TrayBackgroundView is
283 // hidden. Reset the offscreen transform so that the animation to becoming
284 // visible reflects the current layout.
285 HideTransformation();
286 // SetVisible(false) is defered until the animation for hiding is done.
287 // Otherwise the view is immediately hidden and the animation does not
288 // render.
289 views::View::SetVisible(true);
290 // If SetVisible(true) is called while animating to not visible, then
291 // views::View::SetVisible(true) is a no-op. When the previous animation
292 // ends layer->SetVisible(false) is called. To prevent this
293 // layer->SetVisible(true) immediately interrupts the animation of this
294 // property, and keeps the layer visible.
295 layer()->SetVisible(true);
296 }
297
298 ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator());
299 animation.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
300 kAnimationDurationForVisibilityMs));
301 animation.SetPreemptionStrategy(
302 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
303
304 if (visible) {
305 animation.SetTweenType(gfx::Tween::EASE_OUT);
306 // Show is delayed so as to allow time for other children of
307 // StatusAreaWidget to begin animating to their new positions.
308 layer()->GetAnimator()->SchedulePauseForProperties(
309 base::TimeDelta::FromMilliseconds(kShowAnimationDelayMs),
310 ui::LayerAnimationElement::OPACITY |
311 ui::LayerAnimationElement::TRANSFORM);
312 layer()->SetOpacity(1.0f);
313 gfx::Transform transform;
314 transform.Translate(0.0f, 0.0f);
315 layer()->SetTransform(transform);
316 } else {
317 // Listen only to the hide animation. As we cannot turn off visibility
318 // until the animation is over.
319 animation.AddObserver(this);
320 animation.SetTweenType(gfx::Tween::EASE_IN);
321 layer()->SetOpacity(0.0f);
322 layer()->SetVisible(false);
323 HideTransformation();
324 }
325 }
326
327 const char* TrayBackgroundView::GetClassName() const {
328 return kViewClassName;
329 }
330
331 void TrayBackgroundView::ChildPreferredSizeChanged(views::View* child) {
332 PreferredSizeChanged();
333 }
334
335 void TrayBackgroundView::GetAccessibleState(ui::AXViewState* state) {
336 ActionableView::GetAccessibleState(state);
337 state->name = GetAccessibleNameForTray();
338 }
339
340 void TrayBackgroundView::AboutToRequestFocusFromTabTraversal(bool reverse) {
341 // Return focus to the login view. See crbug.com/120500.
342 views::View* v = GetNextFocusableView();
343 if (v)
344 v->AboutToRequestFocusFromTabTraversal(reverse);
345 }
346
347 bool TrayBackgroundView::PerformAction(const ui::Event& event) {
348 return false;
349 }
350
351 gfx::Rect TrayBackgroundView::GetFocusBounds() {
352 // The tray itself expands to the right and bottom edge of the screen to make
353 // sure clicking on the edges brings up the popup. However, the focus border
354 // should be only around the container.
355 return GetContentsBounds();
356 }
357
358 void TrayBackgroundView::OnGestureEvent(ui::GestureEvent* event) {
359 if (switches::IsTouchFeedbackEnabled()) {
360 if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
361 SetDrawBackgroundAsActive(true);
362 } else if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN ||
363 event->type() == ui::ET_GESTURE_TAP_CANCEL) {
364 SetDrawBackgroundAsActive(false);
365 }
366 }
367 ActionableView::OnGestureEvent(event);
368 }
369
370 void TrayBackgroundView::UpdateBackground(int alpha) {
371 // The animator should never fire when the alternate shelf layout is used.
372 if (!background_ || draw_background_as_active_)
373 return;
374 SchedulePaint();
375 }
376
377 void TrayBackgroundView::SetContents(views::View* contents) {
378 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
379 AddChildView(contents);
380 }
381 void TrayBackgroundView::SetContentsBackground() {
382 background_ = new TrayBackground(this);
383 tray_container_->set_background(background_);
384 }
385
386 WmShelf* TrayBackgroundView::GetShelf() {
387 return status_area_widget_->wm_shelf();
388 }
389
390 void TrayBackgroundView::SetShelfAlignment(ShelfAlignment alignment) {
391 shelf_alignment_ = alignment;
392 tray_container_->SetAlignment(alignment);
393 }
394
395 void TrayBackgroundView::OnImplicitAnimationsCompleted() {
396 // If there is another animation in the queue, the reverse animation was
397 // triggered before the completion of animating to invisible. Do not turn off
398 // the visibility so that the next animation may render. The value of
399 // layer()->GetTargetVisibility() can be incorrect if the hide animation was
400 // aborted to schedule an animation to become visible. As the new animation
401 // is not yet added to the queue. crbug.com/374236
402 if(layer()->GetAnimator()->is_animating() ||
403 layer()->GetTargetVisibility())
404 return;
405 views::View::SetVisible(false);
406 }
407
408 bool TrayBackgroundView::RequiresNotificationWhenAnimatorDestroyed() const {
409 // This is needed so that OnImplicitAnimationsCompleted() is called even upon
410 // destruction of the animator. This can occure when parallel animations
411 // caused by ScreenRotationAnimator end before the animations of
412 // TrayBackgroundView. This allows for a proper update to the visual state of
413 // the view. (crbug.com/476667)
414 return true;
415 }
416
417 void TrayBackgroundView::HideTransformation() {
418 gfx::Transform transform;
419 if (IsHorizontalAlignment(shelf_alignment_))
420 transform.Translate(width(), 0.0f);
421 else
422 transform.Translate(0.0f, height());
423 layer()->SetTransform(transform);
424 }
425
426 gfx::Rect TrayBackgroundView::GetBubbleAnchorRect(
427 views::Widget* anchor_widget,
428 TrayBubbleView::AnchorType anchor_type,
429 TrayBubbleView::AnchorAlignment anchor_alignment) const {
430 gfx::Rect rect;
431 if (anchor_widget && anchor_widget->IsVisible()) {
432 rect = anchor_widget->GetWindowBoundsInScreen();
433 if (anchor_type == TrayBubbleView::ANCHOR_TYPE_TRAY) {
434 if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM) {
435 bool rtl = base::i18n::IsRTL();
436 rect.Inset(
437 rtl ? kBubblePaddingHorizontalSide : 0,
438 kBubblePaddingHorizontalBottom,
439 rtl ? 0 : kBubblePaddingHorizontalSide,
440 0);
441 } else if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_LEFT) {
442 rect.Inset(0, 0, kBubblePaddingVerticalSide + 4,
443 kBubblePaddingVerticalBottom);
444 } else if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_RIGHT) {
445 rect.Inset(kBubblePaddingVerticalSide, 0, 0,
446 kBubblePaddingVerticalBottom);
447 } else {
448 // TODO(bruthig) May need to handle other ANCHOR_ALIGNMENT_ values.
449 // ie. ANCHOR_ALIGNMENT_TOP
450 DCHECK(false) << "Unhandled anchor alignment.";
451 }
452 } else if (anchor_type == TrayBubbleView::ANCHOR_TYPE_BUBBLE) {
453 // Invert the offsets to align with the bubble below.
454 // Note that with the alternate shelf layout the tips are not shown and
455 // the offsets for left and right alignment do not need to be applied.
456 int vertical_alignment = 0;
457 int horizontal_alignment = kBubblePaddingVerticalBottom;
458 if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_LEFT)
459 rect.Inset(vertical_alignment, 0, 0, horizontal_alignment);
460 else if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_RIGHT)
461 rect.Inset(0, 0, vertical_alignment, horizontal_alignment);
462 } else {
463 DCHECK(false) << "Unhandled anchor type.";
464 }
465 } else {
466 aura::Window* target_root = anchor_widget ?
467 anchor_widget->GetNativeView()->GetRootWindow() :
468 Shell::GetPrimaryRootWindow();
469 rect = target_root->bounds();
470 if (anchor_type == TrayBubbleView::ANCHOR_TYPE_TRAY) {
471 if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM) {
472 rect = gfx::Rect(
473 base::i18n::IsRTL() ?
474 kPaddingFromRightEdgeOfScreenBottomAlignment :
475 rect.width() - kPaddingFromRightEdgeOfScreenBottomAlignment,
476 rect.height() - kPaddingFromBottomOfScreenBottomAlignment,
477 0, 0);
478 rect = ScreenUtil::ConvertRectToScreen(target_root, rect);
479 } else if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_LEFT) {
480 rect = gfx::Rect(
481 kPaddingFromRightEdgeOfScreenBottomAlignment,
482 rect.height() - kPaddingFromBottomOfScreenBottomAlignment,
483 1, 1);
484 rect = ScreenUtil::ConvertRectToScreen(target_root, rect);
485 } else if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_RIGHT) {
486 rect = gfx::Rect(
487 rect.width() - kPaddingFromRightEdgeOfScreenBottomAlignment,
488 rect.height() - kPaddingFromBottomOfScreenBottomAlignment,
489 1, 1);
490 rect = ScreenUtil::ConvertRectToScreen(target_root, rect);
491 } else {
492 // TODO(bruthig) May need to handle other ANCHOR_ALIGNMENT_ values.
493 // ie. ANCHOR_ALIGNMENT_TOP
494 DCHECK(false) << "Unhandled anchor alignment.";
495 }
496 } else {
497 rect = gfx::Rect(
498 base::i18n::IsRTL() ?
499 kPaddingFromRightEdgeOfScreenBottomAlignment :
500 rect.width() - kPaddingFromRightEdgeOfScreenBottomAlignment,
501 rect.height() - kPaddingFromBottomOfScreenBottomAlignment,
502 0, 0);
503 }
504 }
505 return rect;
506 }
507
508 TrayBubbleView::AnchorAlignment TrayBackgroundView::GetAnchorAlignment() const {
509 if (shelf_alignment_ == SHELF_ALIGNMENT_LEFT)
510 return TrayBubbleView::ANCHOR_ALIGNMENT_LEFT;
511 if (shelf_alignment_ == SHELF_ALIGNMENT_RIGHT)
512 return TrayBubbleView::ANCHOR_ALIGNMENT_RIGHT;
513 return TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM;
514 }
515
516 void TrayBackgroundView::SetDrawBackgroundAsActive(bool visible) {
517 if (draw_background_as_active_ == visible)
518 return;
519 draw_background_as_active_ = visible;
520 if (!background_)
521 return;
522 SchedulePaint();
523 }
524
525 void TrayBackgroundView::UpdateBubbleViewArrow(
526 views::TrayBubbleView* bubble_view) {
527 // Nothing to do here.
528 }
529
530 } // namespace ash
OLDNEW
« no previous file with comments | « ash/system/tray/tray_background_view.h ('k') | ash/system/tray/tray_bubble_wrapper.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698