tray_background_view.cc revision 3551c9c881056c480085172ff9840cab31610854
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/ash_switches.h"
8#include "ash/root_window_controller.h"
9#include "ash/screen_ash.h"
10#include "ash/shelf/shelf_layout_manager.h"
11#include "ash/shelf/shelf_widget.h"
12#include "ash/shell.h"
13#include "ash/shell_window_ids.h"
14#include "ash/system/status_area_widget.h"
15#include "ash/system/status_area_widget_delegate.h"
16#include "ash/system/tray/system_tray.h"
17#include "ash/system/tray/tray_constants.h"
18#include "ash/system/tray/tray_event_filter.h"
19#include "ash/wm/property_util.h"
20#include "ash/wm/window_animations.h"
21#include "grit/ash_resources.h"
22#include "ui/aura/root_window.h"
23#include "ui/aura/window.h"
24#include "ui/base/accessibility/accessible_view_state.h"
25#include "ui/base/resource/resource_bundle.h"
26#include "ui/gfx/canvas.h"
27#include "ui/gfx/image/image_skia.h"
28#include "ui/gfx/image/image_skia_operations.h"
29#include "ui/gfx/rect.h"
30#include "ui/gfx/screen.h"
31#include "ui/gfx/skia_util.h"
32#include "ui/views/background.h"
33#include "ui/views/layout/box_layout.h"
34
35namespace {
36
37const int kTrayBackgroundAlpha = 100;
38const int kTrayBackgroundHoverAlpha = 150;
39const SkColor kTrayBackgroundPressedColor = SkColorSetRGB(66, 129, 244);
40
41// Adjust the size of TrayContainer with additional padding.
42const int kTrayContainerVerticalPaddingBottomAlignment  = 1;
43const int kTrayContainerHorizontalPaddingBottomAlignment  = 1;
44const int kTrayContainerVerticalPaddingVerticalAlignment  = 1;
45const int kTrayContainerHorizontalPaddingVerticalAlignment = 1;
46
47const int kAnimationDurationForPopupMS = 200;
48
49}  // namespace
50
51using views::TrayBubbleView;
52
53namespace ash {
54namespace internal {
55
56// static
57const char TrayBackgroundView::kViewClassName[] = "tray/TrayBackgroundView";
58
59// Used to track when the anchor widget changes position on screen so that the
60// bubble position can be updated.
61class TrayBackgroundView::TrayWidgetObserver : public views::WidgetObserver {
62 public:
63  explicit TrayWidgetObserver(TrayBackgroundView* host)
64      : host_(host) {
65  }
66
67  virtual void OnWidgetBoundsChanged(views::Widget* widget,
68                                     const gfx::Rect& new_bounds) OVERRIDE {
69    host_->AnchorUpdated();
70  }
71
72  virtual void OnWidgetVisibilityChanged(views::Widget* widget,
73                                         bool visible) OVERRIDE {
74    host_->AnchorUpdated();
75  }
76
77 private:
78  TrayBackgroundView* host_;
79
80  DISALLOW_COPY_AND_ASSIGN(TrayWidgetObserver);
81};
82
83class TrayBackground : public views::Background {
84 public:
85  const static int kImageTypeDefault = 0;
86  const static int kImageTypeOnBlack = 1;
87  const static int kImageTypePressed = 2;
88  const static int kNumStates = 3;
89
90  const static int kImageHorizontal = 0;
91  const static int kImageVertical = 1;
92  const static int kNumOrientations = 2;
93
94  explicit TrayBackground(TrayBackgroundView* tray_background_view) :
95      tray_background_view_(tray_background_view) {
96    set_alpha(kTrayBackgroundAlpha);
97    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
98    leading_images_[kImageHorizontal][kImageTypeDefault] =
99        rb.GetImageNamed(IDR_AURA_TRAY_BG_HORIZ_LEFT).ToImageSkia();
100    middle_images_[kImageHorizontal][kImageTypeDefault] =
101        rb.GetImageNamed(IDR_AURA_TRAY_BG_HORIZ_CENTER).ToImageSkia();
102    trailing_images_[kImageHorizontal][kImageTypeDefault] =
103        rb.GetImageNamed(IDR_AURA_TRAY_BG_HORIZ_RIGHT).ToImageSkia();
104
105    leading_images_[kImageHorizontal][kImageTypeOnBlack] =
106        rb.GetImageNamed(IDR_AURA_TRAY_BG_HORIZ_LEFT_ONBLACK).ToImageSkia();
107    middle_images_[kImageHorizontal][kImageTypeOnBlack] =
108        rb.GetImageNamed(IDR_AURA_TRAY_BG_HORIZ_CENTER_ONBLACK).ToImageSkia();
109    trailing_images_[kImageHorizontal][kImageTypeOnBlack] =
110        rb.GetImageNamed(IDR_AURA_TRAY_BG_HORIZ_RIGHT_ONBLACK).ToImageSkia();
111
112    leading_images_[kImageHorizontal][kImageTypePressed] =
113        rb.GetImageNamed(IDR_AURA_TRAY_BG_HORIZ_LEFT_PRESSED).ToImageSkia();
114    middle_images_[kImageHorizontal][kImageTypePressed] =
115        rb.GetImageNamed(IDR_AURA_TRAY_BG_HORIZ_CENTER_PRESSED).ToImageSkia();
116    trailing_images_[kImageHorizontal][kImageTypePressed] =
117        rb.GetImageNamed(IDR_AURA_TRAY_BG_HORIZ_RIGHT_PRESSED).ToImageSkia();
118
119    leading_images_[kImageVertical][kImageTypeDefault] =
120        rb.GetImageNamed(IDR_AURA_TRAY_BG_VERTICAL_TOP).ToImageSkia();
121    middle_images_[kImageVertical][kImageTypeDefault] =
122        rb.GetImageNamed(
123            IDR_AURA_TRAY_BG_VERTICAL_CENTER).ToImageSkia();
124    trailing_images_[kImageVertical][kImageTypeDefault] =
125        rb.GetImageNamed(IDR_AURA_TRAY_BG_VERTICAL_BOTTOM).ToImageSkia();
126
127    leading_images_[kImageVertical][kImageTypeOnBlack] =
128        rb.GetImageNamed(IDR_AURA_TRAY_BG_VERTICAL_TOP_ONBLACK).ToImageSkia();
129    middle_images_[kImageVertical][kImageTypeOnBlack] =
130        rb.GetImageNamed(
131            IDR_AURA_TRAY_BG_VERTICAL_CENTER_ONBLACK).ToImageSkia();
132    trailing_images_[kImageVertical][kImageTypeOnBlack] =
133        rb.GetImageNamed(
134            IDR_AURA_TRAY_BG_VERTICAL_BOTTOM_ONBLACK).ToImageSkia();
135
136    leading_images_[kImageVertical][kImageTypePressed] =
137        rb.GetImageNamed(IDR_AURA_TRAY_BG_VERTICAL_TOP_PRESSED).ToImageSkia();
138    middle_images_[kImageVertical][kImageTypePressed] =
139        rb.GetImageNamed(
140            IDR_AURA_TRAY_BG_VERTICAL_CENTER_PRESSED).ToImageSkia();
141    trailing_images_[kImageVertical][kImageTypePressed] =
142        rb.GetImageNamed(
143            IDR_AURA_TRAY_BG_VERTICAL_BOTTOM_PRESSED).ToImageSkia();
144  }
145
146  virtual ~TrayBackground() {}
147
148  SkColor color() { return color_; }
149  void set_color(SkColor color) { color_ = color; }
150  void set_alpha(int alpha) { color_ = SkColorSetARGB(alpha, 0, 0, 0); }
151
152 private:
153  ShelfWidget* GetShelfWidget() const {
154    return RootWindowController::ForWindow(tray_background_view_->
155        status_area_widget()->GetNativeWindow())->shelf();
156  }
157
158  void PaintForAlternateShelf(gfx::Canvas* canvas, views::View* view) const {
159    int orientation = kImageHorizontal;
160    ShelfWidget* shelf_widget = GetShelfWidget();
161    if (shelf_widget &&
162        !shelf_widget->shelf_layout_manager()->IsHorizontalAlignment())
163      orientation = kImageVertical;
164
165    int state = kImageTypeDefault;
166    if (tray_background_view_->IsPressed())
167      state = kImageTypePressed;
168    else if (shelf_widget && shelf_widget->GetDimsShelf())
169      state = kImageTypeOnBlack;
170    else
171      state = kImageTypeDefault;
172
173    const gfx::ImageSkia* leading = leading_images_[orientation][state];
174    const gfx::ImageSkia* middle = middle_images_[orientation][state];
175    const gfx::ImageSkia* trailing = trailing_images_[orientation][state];
176
177    gfx::Rect bounds(view->GetLocalBounds());
178    gfx::Point leading_location, trailing_location;
179    gfx::Rect middle_bounds;
180
181    if (orientation == kImageHorizontal) {
182      leading_location = gfx::Point(0, 0);
183      trailing_location = gfx::Point(bounds.width() - trailing->width(), 0);
184      middle_bounds = gfx::Rect(
185          leading->width(),
186          0,
187          bounds.width() - (leading->width() + trailing->width()),
188          bounds.height());
189    } else {
190      leading_location = gfx::Point(0, 0);
191      trailing_location = gfx::Point(0, bounds.height() - trailing->height());
192      middle_bounds = gfx::Rect(
193          0,
194          leading->height(),
195          bounds.width(),
196          bounds.height() - (leading->height() + trailing->height()));
197    }
198
199    canvas->DrawImageInt(*leading,
200                         leading_location.x(),
201                         leading_location.y());
202
203    canvas->DrawImageInt(*trailing,
204                         trailing_location.x(),
205                         trailing_location.y());
206
207    canvas->TileImageInt(*middle,
208                         middle_bounds.x(),
209                         middle_bounds.y(),
210                         middle_bounds.width(),
211                         middle_bounds.height());
212  }
213
214  // Overridden from views::Background.
215  virtual void Paint(gfx::Canvas* canvas, views::View* view) const OVERRIDE {
216    if (ash::switches::UseAlternateShelfLayout()) {
217      PaintForAlternateShelf(canvas, view);
218    } else {
219      SkPaint paint;
220      paint.setAntiAlias(true);
221      paint.setStyle(SkPaint::kFill_Style);
222      paint.setColor(color_);
223      SkPath path;
224      gfx::Rect bounds(view->GetLocalBounds());
225      SkScalar radius = SkIntToScalar(kTrayRoundedBorderRadius);
226      path.addRoundRect(gfx::RectToSkRect(bounds), radius, radius);
227      canvas->DrawPath(path, paint);
228    }
229  }
230
231  SkColor color_;
232  // Reference to the TrayBackgroundView for which this is a background.
233  TrayBackgroundView* tray_background_view_;
234
235  // References to the images used as backgrounds, they are owned by the
236  // resource bundle class.
237  const gfx::ImageSkia* leading_images_[kNumOrientations][kNumStates];
238  const gfx::ImageSkia* middle_images_[kNumOrientations][kNumStates];
239  const gfx::ImageSkia* trailing_images_[kNumOrientations][kNumStates];
240
241  DISALLOW_COPY_AND_ASSIGN(TrayBackground);
242};
243
244TrayBackgroundView::TrayContainer::TrayContainer(ShelfAlignment alignment)
245    : alignment_(alignment) {
246  UpdateLayout();
247}
248
249void TrayBackgroundView::TrayContainer::SetAlignment(ShelfAlignment alignment) {
250  if (alignment_ == alignment)
251    return;
252  alignment_ = alignment;
253  UpdateLayout();
254}
255
256gfx::Size TrayBackgroundView::TrayContainer::GetPreferredSize() {
257  if (size_.IsEmpty())
258    return views::View::GetPreferredSize();
259  return size_;
260}
261
262void TrayBackgroundView::TrayContainer::ChildPreferredSizeChanged(
263    views::View* child) {
264  PreferredSizeChanged();
265}
266
267void TrayBackgroundView::TrayContainer::ChildVisibilityChanged(View* child) {
268  PreferredSizeChanged();
269}
270
271void TrayBackgroundView::TrayContainer::ViewHierarchyChanged(
272    const ViewHierarchyChangedDetails& details) {
273  if (details.parent == this)
274    PreferredSizeChanged();
275}
276
277void TrayBackgroundView::TrayContainer::UpdateLayout() {
278  // Adjust the size of status tray dark background by adding additional
279  // empty border.
280  if (alignment_ == SHELF_ALIGNMENT_BOTTOM ||
281      alignment_ == SHELF_ALIGNMENT_TOP) {
282    int vertical_padding = kTrayContainerVerticalPaddingBottomAlignment;
283    int horizontal_padding = kTrayContainerHorizontalPaddingBottomAlignment;
284    if (ash::switches::UseAlternateShelfLayout()) {
285      vertical_padding = kPaddingFromEdgeOfShelf;
286      horizontal_padding = kPaddingFromEdgeOfShelf;
287    }
288    set_border(views::Border::CreateEmptyBorder(
289        vertical_padding,
290        horizontal_padding,
291        vertical_padding,
292        horizontal_padding));
293
294    views::BoxLayout* layout =
295        new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0);
296    layout->set_spread_blank_space(true);
297    views::View::SetLayoutManager(layout);
298  } else {
299    int vertical_padding = kTrayContainerVerticalPaddingVerticalAlignment;
300    int horizontal_padding = kTrayContainerHorizontalPaddingVerticalAlignment;
301    if (ash::switches::UseAlternateShelfLayout()) {
302      vertical_padding = kPaddingFromEdgeOfShelf;
303      horizontal_padding = kPaddingFromEdgeOfShelf;
304    }
305    set_border(views::Border::CreateEmptyBorder(
306        vertical_padding,
307        horizontal_padding,
308        vertical_padding,
309        horizontal_padding));
310
311    views::BoxLayout* layout =
312        new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0);
313    layout->set_spread_blank_space(true);
314    views::View::SetLayoutManager(layout);
315  }
316  PreferredSizeChanged();
317}
318
319////////////////////////////////////////////////////////////////////////////////
320// TrayBackgroundView
321
322TrayBackgroundView::TrayBackgroundView(
323    internal::StatusAreaWidget* status_area_widget)
324    : status_area_widget_(status_area_widget),
325      tray_container_(NULL),
326      shelf_alignment_(SHELF_ALIGNMENT_BOTTOM),
327      background_(NULL),
328      hide_background_animator_(this, 0, kTrayBackgroundAlpha),
329      hover_background_animator_(
330          this, 0, kTrayBackgroundHoverAlpha - kTrayBackgroundAlpha),
331      hovered_(false),
332      pressed_(false),
333      widget_observer_(new TrayWidgetObserver(this)) {
334  set_notify_enter_exit_on_child(true);
335
336  // Initially we want to paint the background, but without the hover effect.
337  SetPaintsBackground(true, internal::BackgroundAnimator::CHANGE_IMMEDIATE);
338  hover_background_animator_.SetPaintsBackground(false,
339      internal::BackgroundAnimator::CHANGE_IMMEDIATE);
340
341  tray_container_ = new TrayContainer(shelf_alignment_);
342  SetContents(tray_container_);
343  tray_event_filter_.reset(new TrayEventFilter);
344}
345
346TrayBackgroundView::~TrayBackgroundView() {
347  if (GetWidget())
348    GetWidget()->RemoveObserver(widget_observer_.get());
349}
350
351void TrayBackgroundView::Initialize() {
352  GetWidget()->AddObserver(widget_observer_.get());
353  SetBorder();
354}
355
356const char* TrayBackgroundView::GetClassName() const {
357  return kViewClassName;
358}
359
360void TrayBackgroundView::OnMouseEntered(const ui::MouseEvent& event) {
361  hovered_ = true;
362  if (!background_)
363    return;
364  if (pressed_)
365    return;
366
367  hover_background_animator_.SetPaintsBackground(true,
368      internal::BackgroundAnimator::CHANGE_ANIMATE);
369}
370
371void TrayBackgroundView::OnMouseExited(const ui::MouseEvent& event) {
372  hovered_ = false;
373  if (!background_)
374    return;
375  if (pressed_)
376    return;
377
378  hover_background_animator_.SetPaintsBackground(false,
379      internal::BackgroundAnimator::CHANGE_ANIMATE);
380}
381
382void TrayBackgroundView::ChildPreferredSizeChanged(views::View* child) {
383  PreferredSizeChanged();
384}
385
386void TrayBackgroundView::OnPaintFocusBorder(gfx::Canvas* canvas) {
387  // The tray itself expands to the right and bottom edge of the screen to make
388  // sure clicking on the edges brings up the popup. However, the focus border
389  // should be only around the container.
390  if (HasFocus() && (focusable() || IsAccessibilityFocusable()))
391    DrawBorder(canvas, GetContentsBounds());
392}
393
394void TrayBackgroundView::GetAccessibleState(ui::AccessibleViewState* state) {
395  state->role = ui::AccessibilityTypes::ROLE_PUSHBUTTON;
396  state->name = GetAccessibleNameForTray();
397}
398
399void TrayBackgroundView::AboutToRequestFocusFromTabTraversal(bool reverse) {
400  // Return focus to the login view. See crbug.com/120500.
401  views::View* v = GetNextFocusableView();
402  if (v)
403    v->AboutToRequestFocusFromTabTraversal(reverse);
404}
405
406bool TrayBackgroundView::PerformAction(const ui::Event& event) {
407  return false;
408}
409
410void TrayBackgroundView::UpdateBackground(int alpha) {
411  if (!background_)
412    return;
413  if (pressed_)
414    return;
415
416  background_->set_alpha(hide_background_animator_.alpha() +
417                         hover_background_animator_.alpha());
418  SchedulePaint();
419}
420
421void TrayBackgroundView::SetContents(views::View* contents) {
422  SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
423  AddChildView(contents);
424}
425
426void TrayBackgroundView::SetPaintsBackground(
427    bool value,
428    internal::BackgroundAnimator::ChangeType change_type) {
429  hide_background_animator_.SetPaintsBackground(value, change_type);
430}
431
432void TrayBackgroundView::SetContentsBackground() {
433  background_ = new internal::TrayBackground(this);
434  tray_container_->set_background(background_);
435}
436
437ShelfLayoutManager* TrayBackgroundView::GetShelfLayoutManager() {
438  return ShelfLayoutManager::ForLauncher(GetWidget()->GetNativeView());
439}
440
441void TrayBackgroundView::SetShelfAlignment(ShelfAlignment alignment) {
442  shelf_alignment_ = alignment;
443  SetBorder();
444  tray_container_->SetAlignment(alignment);
445}
446
447void TrayBackgroundView::SetBorder() {
448  views::View* parent = status_area_widget_->status_area_widget_delegate();
449
450  if (ash::switches::UseAlternateShelfLayout()) {
451    set_border(views::Border::CreateEmptyBorder(
452        0,
453        0,
454        ShelfLayoutManager::kAutoHideSize,
455        0));
456  } else {
457    // Tray views are laid out right-to-left or bottom-to-top
458    int on_edge = (this == parent->child_at(0));
459    // Change the border padding for different shelf alignment.
460    if (shelf_alignment() == SHELF_ALIGNMENT_BOTTOM) {
461      set_border(views::Border::CreateEmptyBorder(
462          0, 0,
463          on_edge ? kPaddingFromBottomOfScreenBottomAlignment :
464                    kPaddingFromBottomOfScreenBottomAlignment - 1,
465          on_edge ? kPaddingFromRightEdgeOfScreenBottomAlignment : 0));
466    } else if (shelf_alignment() == SHELF_ALIGNMENT_TOP) {
467      set_border(views::Border::CreateEmptyBorder(
468          on_edge ? kPaddingFromBottomOfScreenBottomAlignment :
469                    kPaddingFromBottomOfScreenBottomAlignment - 1,
470          0, 0,
471          on_edge ? kPaddingFromRightEdgeOfScreenBottomAlignment : 0));
472    } else if (shelf_alignment() == SHELF_ALIGNMENT_LEFT) {
473      set_border(views::Border::CreateEmptyBorder(
474          0, kPaddingFromOuterEdgeOfLauncherVerticalAlignment,
475          on_edge ? kPaddingFromBottomOfScreenVerticalAlignment : 0,
476          kPaddingFromInnerEdgeOfLauncherVerticalAlignment));
477    } else {
478      set_border(views::Border::CreateEmptyBorder(
479          0, kPaddingFromInnerEdgeOfLauncherVerticalAlignment,
480          on_edge ? kPaddingFromBottomOfScreenVerticalAlignment : 0,
481          kPaddingFromOuterEdgeOfLauncherVerticalAlignment));
482    }
483  }
484}
485
486void TrayBackgroundView::InitializeBubbleAnimations(
487    views::Widget* bubble_widget) {
488  views::corewm::SetWindowVisibilityAnimationType(
489      bubble_widget->GetNativeWindow(),
490      views::corewm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
491  views::corewm::SetWindowVisibilityAnimationTransition(
492      bubble_widget->GetNativeWindow(),
493      views::corewm::ANIMATE_HIDE);
494  views::corewm::SetWindowVisibilityAnimationDuration(
495      bubble_widget->GetNativeWindow(),
496      base::TimeDelta::FromMilliseconds(kAnimationDurationForPopupMS));
497}
498
499bool TrayBackgroundView::IsPressed() {
500  return pressed_;
501}
502
503aura::Window* TrayBackgroundView::GetBubbleWindowContainer() const {
504  return ash::Shell::GetContainer(
505      tray_container()->GetWidget()->GetNativeWindow()->GetRootWindow(),
506      ash::internal::kShellWindowId_SettingBubbleContainer);
507}
508
509gfx::Rect TrayBackgroundView::GetBubbleAnchorRect(
510    views::Widget* anchor_widget,
511    TrayBubbleView::AnchorType anchor_type,
512    TrayBubbleView::AnchorAlignment anchor_alignment) const {
513  gfx::Rect rect;
514  if (anchor_widget && anchor_widget->IsVisible()) {
515    rect = anchor_widget->GetWindowBoundsInScreen();
516    if (anchor_type == TrayBubbleView::ANCHOR_TYPE_TRAY) {
517      if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM) {
518        bool rtl = base::i18n::IsRTL();
519        rect.Inset(
520            rtl ? kPaddingFromRightEdgeOfScreenBottomAlignment : 0,
521            kTrayBubbleAnchorTopInsetBottomAnchor,
522            rtl ? 0 : kPaddingFromRightEdgeOfScreenBottomAlignment,
523            kPaddingFromBottomOfScreenBottomAlignment);
524      } else if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_LEFT) {
525        rect.Inset(0, 0, kPaddingFromInnerEdgeOfLauncherVerticalAlignment + 5,
526                   kPaddingFromBottomOfScreenVerticalAlignment);
527      } else {
528        rect.Inset(kPaddingFromInnerEdgeOfLauncherVerticalAlignment + 1,
529                   0, 0, kPaddingFromBottomOfScreenVerticalAlignment);
530      }
531    } else if (anchor_type == TrayBubbleView::ANCHOR_TYPE_BUBBLE) {
532      // Invert the offsets to align with the bubble below.
533      // Note that with the alternate shelf layout the tips are not shown and
534      // the offsets for left and right alignment do not need to be applied.
535      int vertical_alignment = ash::switches::UseAlternateShelfLayout() ?
536          0 : kPaddingFromInnerEdgeOfLauncherVerticalAlignment;
537      if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_LEFT) {
538        rect.Inset(vertical_alignment,
539                   0, 0, kPaddingFromBottomOfScreenVerticalAlignment);
540      } else if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_RIGHT) {
541        rect.Inset(0, 0, vertical_alignment,
542                   kPaddingFromBottomOfScreenVerticalAlignment);
543      }
544    }
545  }
546
547  // TODO(jennyz): May need to add left/right alignment in the following code.
548  if (rect.IsEmpty()) {
549    aura::RootWindow* target_root = anchor_widget ?
550        anchor_widget->GetNativeView()->GetRootWindow() :
551        Shell::GetPrimaryRootWindow();
552    rect = target_root->bounds();
553    rect = gfx::Rect(
554        base::i18n::IsRTL() ? kPaddingFromRightEdgeOfScreenBottomAlignment :
555        rect.width() - kPaddingFromRightEdgeOfScreenBottomAlignment,
556        rect.height() - kPaddingFromBottomOfScreenBottomAlignment,
557        0, 0);
558    rect = ScreenAsh::ConvertRectToScreen(target_root, rect);
559  }
560  return rect;
561}
562
563TrayBubbleView::AnchorAlignment TrayBackgroundView::GetAnchorAlignment() const {
564  switch (shelf_alignment_) {
565    case SHELF_ALIGNMENT_BOTTOM:
566      return TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM;
567    case SHELF_ALIGNMENT_LEFT:
568      return TrayBubbleView::ANCHOR_ALIGNMENT_LEFT;
569    case SHELF_ALIGNMENT_RIGHT:
570      return TrayBubbleView::ANCHOR_ALIGNMENT_RIGHT;
571    case SHELF_ALIGNMENT_TOP:
572      return TrayBubbleView::ANCHOR_ALIGNMENT_TOP;
573  }
574  NOTREACHED();
575  return TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM;
576}
577
578void TrayBackgroundView::SetBubbleVisible(bool visible) {
579  pressed_ = visible;
580  if (!background_)
581    return;
582
583  // Do not change gradually, changing color between grey and blue is weird.
584  if (pressed_)
585    background_->set_color(kTrayBackgroundPressedColor);
586  else if (hovered_)
587    background_->set_alpha(kTrayBackgroundHoverAlpha);
588  else
589    background_->set_alpha(kTrayBackgroundAlpha);
590  SchedulePaint();
591}
592
593void TrayBackgroundView::UpdateBubbleViewArrow(
594    views::TrayBubbleView* bubble_view) {
595  if (switches::UseAlternateShelfLayout())
596    return;
597
598  aura::RootWindow* root_window =
599      bubble_view->GetWidget()->GetNativeView()->GetRootWindow();
600  ash::internal::ShelfLayoutManager* shelf =
601      ShelfLayoutManager::ForLauncher(root_window);
602  bubble_view->SetArrowPaintType(
603      (shelf && shelf->IsVisible()) ?
604      views::BubbleBorder::PAINT_NORMAL :
605      views::BubbleBorder::PAINT_TRANSPARENT);
606}
607
608}  // namespace internal
609}  // namespace ash
610