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_util.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/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/resource/resource_bundle.h" 26#include "ui/compositor/layer.h" 27#include "ui/compositor/layer_animation_element.h" 28#include "ui/compositor/scoped_layer_animation_settings.h" 29#include "ui/events/event_constants.h" 30#include "ui/gfx/animation/tween.h" 31#include "ui/gfx/canvas.h" 32#include "ui/gfx/image/image_skia.h" 33#include "ui/gfx/image/image_skia_operations.h" 34#include "ui/gfx/rect.h" 35#include "ui/gfx/screen.h" 36#include "ui/gfx/skia_util.h" 37#include "ui/gfx/transform.h" 38#include "ui/views/background.h" 39#include "ui/views/layout/box_layout.h" 40 41namespace { 42 43const int kTrayBackgroundAlpha = 100; 44const int kTrayBackgroundHoverAlpha = 150; 45const SkColor kTrayBackgroundPressedColor = SkColorSetRGB(66, 129, 244); 46 47const int kAnimationDurationForPopupMs = 200; 48 49// Duration of opacity animation for visibility changes. 50const int kAnimationDurationForVisibilityMs = 250; 51 52// When becoming visible delay the animation so that StatusAreaWidgetDelegate 53// can animate sibling views out of the position to be occuped by the 54// TrayBackgroundView. 55const int kShowAnimationDelayMs = 100; 56 57} // namespace 58 59using views::TrayBubbleView; 60 61namespace ash { 62 63// static 64const char TrayBackgroundView::kViewClassName[] = "tray/TrayBackgroundView"; 65 66// Used to track when the anchor widget changes position on screen so that the 67// bubble position can be updated. 68class TrayBackgroundView::TrayWidgetObserver : public views::WidgetObserver { 69 public: 70 explicit TrayWidgetObserver(TrayBackgroundView* host) 71 : host_(host) { 72 } 73 74 virtual void OnWidgetBoundsChanged(views::Widget* widget, 75 const gfx::Rect& new_bounds) OVERRIDE { 76 host_->AnchorUpdated(); 77 } 78 79 virtual void OnWidgetVisibilityChanged(views::Widget* widget, 80 bool visible) OVERRIDE { 81 host_->AnchorUpdated(); 82 } 83 84 private: 85 TrayBackgroundView* host_; 86 87 DISALLOW_COPY_AND_ASSIGN(TrayWidgetObserver); 88}; 89 90class TrayBackground : public views::Background { 91 public: 92 const static int kImageTypeDefault = 0; 93 const static int kImageTypeOnBlack = 1; 94 const static int kImageTypePressed = 2; 95 const static int kNumStates = 3; 96 97 const static int kImageHorizontal = 0; 98 const static int kImageVertical = 1; 99 const static int kNumOrientations = 2; 100 101 explicit TrayBackground(TrayBackgroundView* tray_background_view) : 102 tray_background_view_(tray_background_view) { 103 set_alpha(kTrayBackgroundAlpha); 104 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 105 leading_images_[kImageHorizontal][kImageTypeDefault] = 106 rb.GetImageNamed(IDR_AURA_TRAY_BG_HORIZ_LEFT).ToImageSkia(); 107 middle_images_[kImageHorizontal][kImageTypeDefault] = 108 rb.GetImageNamed(IDR_AURA_TRAY_BG_HORIZ_CENTER).ToImageSkia(); 109 trailing_images_[kImageHorizontal][kImageTypeDefault] = 110 rb.GetImageNamed(IDR_AURA_TRAY_BG_HORIZ_RIGHT).ToImageSkia(); 111 112 leading_images_[kImageHorizontal][kImageTypeOnBlack] = 113 rb.GetImageNamed(IDR_AURA_TRAY_BG_HORIZ_LEFT_ONBLACK).ToImageSkia(); 114 middle_images_[kImageHorizontal][kImageTypeOnBlack] = 115 rb.GetImageNamed(IDR_AURA_TRAY_BG_HORIZ_CENTER_ONBLACK).ToImageSkia(); 116 trailing_images_[kImageHorizontal][kImageTypeOnBlack] = 117 rb.GetImageNamed(IDR_AURA_TRAY_BG_HORIZ_RIGHT_ONBLACK).ToImageSkia(); 118 119 leading_images_[kImageHorizontal][kImageTypePressed] = 120 rb.GetImageNamed(IDR_AURA_TRAY_BG_HORIZ_LEFT_PRESSED).ToImageSkia(); 121 middle_images_[kImageHorizontal][kImageTypePressed] = 122 rb.GetImageNamed(IDR_AURA_TRAY_BG_HORIZ_CENTER_PRESSED).ToImageSkia(); 123 trailing_images_[kImageHorizontal][kImageTypePressed] = 124 rb.GetImageNamed(IDR_AURA_TRAY_BG_HORIZ_RIGHT_PRESSED).ToImageSkia(); 125 126 leading_images_[kImageVertical][kImageTypeDefault] = 127 rb.GetImageNamed(IDR_AURA_TRAY_BG_VERTICAL_TOP).ToImageSkia(); 128 middle_images_[kImageVertical][kImageTypeDefault] = 129 rb.GetImageNamed( 130 IDR_AURA_TRAY_BG_VERTICAL_CENTER).ToImageSkia(); 131 trailing_images_[kImageVertical][kImageTypeDefault] = 132 rb.GetImageNamed(IDR_AURA_TRAY_BG_VERTICAL_BOTTOM).ToImageSkia(); 133 134 leading_images_[kImageVertical][kImageTypeOnBlack] = 135 rb.GetImageNamed(IDR_AURA_TRAY_BG_VERTICAL_TOP_ONBLACK).ToImageSkia(); 136 middle_images_[kImageVertical][kImageTypeOnBlack] = 137 rb.GetImageNamed( 138 IDR_AURA_TRAY_BG_VERTICAL_CENTER_ONBLACK).ToImageSkia(); 139 trailing_images_[kImageVertical][kImageTypeOnBlack] = 140 rb.GetImageNamed( 141 IDR_AURA_TRAY_BG_VERTICAL_BOTTOM_ONBLACK).ToImageSkia(); 142 143 leading_images_[kImageVertical][kImageTypePressed] = 144 rb.GetImageNamed(IDR_AURA_TRAY_BG_VERTICAL_TOP_PRESSED).ToImageSkia(); 145 middle_images_[kImageVertical][kImageTypePressed] = 146 rb.GetImageNamed( 147 IDR_AURA_TRAY_BG_VERTICAL_CENTER_PRESSED).ToImageSkia(); 148 trailing_images_[kImageVertical][kImageTypePressed] = 149 rb.GetImageNamed( 150 IDR_AURA_TRAY_BG_VERTICAL_BOTTOM_PRESSED).ToImageSkia(); 151 } 152 153 virtual ~TrayBackground() {} 154 155 SkColor color() { return color_; } 156 void set_color(SkColor color) { color_ = color; } 157 void set_alpha(int alpha) { color_ = SkColorSetARGB(alpha, 0, 0, 0); } 158 159 private: 160 ShelfWidget* GetShelfWidget() const { 161 return RootWindowController::ForWindow(tray_background_view_-> 162 status_area_widget()->GetNativeWindow())->shelf(); 163 } 164 165 // Overridden from views::Background. 166 virtual void Paint(gfx::Canvas* canvas, views::View* view) const OVERRIDE { 167 int orientation = kImageHorizontal; 168 ShelfWidget* shelf_widget = GetShelfWidget(); 169 if (shelf_widget && 170 !shelf_widget->shelf_layout_manager()->IsHorizontalAlignment()) 171 orientation = kImageVertical; 172 173 int state = kImageTypeDefault; 174 if (tray_background_view_->draw_background_as_active()) 175 state = kImageTypePressed; 176 else if (shelf_widget && shelf_widget->GetDimsShelf()) 177 state = kImageTypeOnBlack; 178 else 179 state = kImageTypeDefault; 180 181 const gfx::ImageSkia* leading = leading_images_[orientation][state]; 182 const gfx::ImageSkia* middle = middle_images_[orientation][state]; 183 const gfx::ImageSkia* trailing = trailing_images_[orientation][state]; 184 185 gfx::Rect bounds(view->GetLocalBounds()); 186 gfx::Point leading_location, trailing_location; 187 gfx::Rect middle_bounds; 188 189 if (orientation == kImageHorizontal) { 190 leading_location = gfx::Point(0, 0); 191 trailing_location = gfx::Point(bounds.width() - trailing->width(), 0); 192 middle_bounds = gfx::Rect( 193 leading->width(), 194 0, 195 bounds.width() - (leading->width() + trailing->width()), 196 bounds.height()); 197 } else { 198 leading_location = gfx::Point(0, 0); 199 trailing_location = gfx::Point(0, bounds.height() - trailing->height()); 200 middle_bounds = gfx::Rect( 201 0, 202 leading->height(), 203 bounds.width(), 204 bounds.height() - (leading->height() + trailing->height())); 205 } 206 207 canvas->DrawImageInt(*leading, 208 leading_location.x(), 209 leading_location.y()); 210 211 canvas->DrawImageInt(*trailing, 212 trailing_location.x(), 213 trailing_location.y()); 214 215 canvas->TileImageInt(*middle, 216 middle_bounds.x(), 217 middle_bounds.y(), 218 middle_bounds.width(), 219 middle_bounds.height()); 220 } 221 222 SkColor color_; 223 // Reference to the TrayBackgroundView for which this is a background. 224 TrayBackgroundView* tray_background_view_; 225 226 // References to the images used as backgrounds, they are owned by the 227 // resource bundle class. 228 const gfx::ImageSkia* leading_images_[kNumOrientations][kNumStates]; 229 const gfx::ImageSkia* middle_images_[kNumOrientations][kNumStates]; 230 const gfx::ImageSkia* trailing_images_[kNumOrientations][kNumStates]; 231 232 DISALLOW_COPY_AND_ASSIGN(TrayBackground); 233}; 234 235TrayBackgroundView::TrayContainer::TrayContainer(ShelfAlignment alignment) 236 : alignment_(alignment) { 237 UpdateLayout(); 238} 239 240void TrayBackgroundView::TrayContainer::SetAlignment(ShelfAlignment alignment) { 241 if (alignment_ == alignment) 242 return; 243 alignment_ = alignment; 244 UpdateLayout(); 245} 246 247gfx::Size TrayBackgroundView::TrayContainer::GetPreferredSize() const { 248 if (size_.IsEmpty()) 249 return views::View::GetPreferredSize(); 250 return size_; 251} 252 253void TrayBackgroundView::TrayContainer::ChildPreferredSizeChanged( 254 views::View* child) { 255 PreferredSizeChanged(); 256} 257 258void TrayBackgroundView::TrayContainer::ChildVisibilityChanged(View* child) { 259 PreferredSizeChanged(); 260} 261 262void TrayBackgroundView::TrayContainer::ViewHierarchyChanged( 263 const ViewHierarchyChangedDetails& details) { 264 if (details.parent == this) 265 PreferredSizeChanged(); 266} 267 268void TrayBackgroundView::TrayContainer::UpdateLayout() { 269 // Adjust the size of status tray dark background by adding additional 270 // empty border. 271 if (alignment_ == SHELF_ALIGNMENT_BOTTOM || 272 alignment_ == SHELF_ALIGNMENT_TOP) { 273 SetBorder(views::Border::CreateEmptyBorder( 274 kPaddingFromEdgeOfShelf, 275 kPaddingFromEdgeOfShelf, 276 kPaddingFromEdgeOfShelf, 277 kPaddingFromEdgeOfShelf)); 278 279 views::BoxLayout* layout = 280 new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); 281 layout->SetDefaultFlex(1); 282 views::View::SetLayoutManager(layout); 283 } else { 284 SetBorder(views::Border::CreateEmptyBorder( 285 kPaddingFromEdgeOfShelf, 286 kPaddingFromEdgeOfShelf, 287 kPaddingFromEdgeOfShelf, 288 kPaddingFromEdgeOfShelf)); 289 290 views::BoxLayout* layout = 291 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0); 292 layout->SetDefaultFlex(1); 293 views::View::SetLayoutManager(layout); 294 } 295 PreferredSizeChanged(); 296} 297 298//////////////////////////////////////////////////////////////////////////////// 299// TrayBackgroundView 300 301TrayBackgroundView::TrayBackgroundView(StatusAreaWidget* status_area_widget) 302 : status_area_widget_(status_area_widget), 303 tray_container_(NULL), 304 shelf_alignment_(SHELF_ALIGNMENT_BOTTOM), 305 background_(NULL), 306 hide_background_animator_(this, 0, kTrayBackgroundAlpha), 307 hover_background_animator_( 308 this, 309 0, 310 kTrayBackgroundHoverAlpha - kTrayBackgroundAlpha), 311 hovered_(false), 312 draw_background_as_active_(false), 313 touch_feedback_enabled_(false), 314 widget_observer_(new TrayWidgetObserver(this)) { 315 set_notify_enter_exit_on_child(true); 316 317 // Initially we want to paint the background, but without the hover effect. 318 hide_background_animator_.SetPaintsBackground( 319 true, BACKGROUND_CHANGE_IMMEDIATE); 320 hover_background_animator_.SetPaintsBackground( 321 false, BACKGROUND_CHANGE_IMMEDIATE); 322 323 tray_container_ = new TrayContainer(shelf_alignment_); 324 SetContents(tray_container_); 325 tray_event_filter_.reset(new TrayEventFilter); 326 327 SetPaintToLayer(true); 328 SetFillsBoundsOpaquely(false); 329 // Start the tray items not visible, because visibility changes are animated. 330 views::View::SetVisible(false); 331 332 if (CommandLine::ForCurrentProcess()-> 333 HasSwitch(switches::kAshEnableTouchViewTouchFeedback)) { 334 touch_feedback_enabled_ = true; 335 } 336} 337 338TrayBackgroundView::~TrayBackgroundView() { 339 if (GetWidget()) 340 GetWidget()->RemoveObserver(widget_observer_.get()); 341} 342 343void TrayBackgroundView::Initialize() { 344 GetWidget()->AddObserver(widget_observer_.get()); 345 SetTrayBorder(); 346} 347 348void TrayBackgroundView::SetVisible(bool visible) { 349 if (visible == layer()->GetTargetVisibility()) 350 return; 351 352 if (visible) { 353 // The alignment of the shelf can change while the TrayBackgroundView is 354 // hidden. Reset the offscreen transform so that the animation to becoming 355 // visible reflects the current layout. 356 HideTransformation(); 357 // SetVisible(false) is defered until the animation for hiding is done. 358 // Otherwise the view is immediately hidden and the animation does not 359 // render. 360 views::View::SetVisible(true); 361 // If SetVisible(true) is called while animating to not visible, then 362 // views::View::SetVisible(true) is a no-op. When the previous animation 363 // ends layer->SetVisible(false) is called. To prevent this 364 // layer->SetVisible(true) immediately interrupts the animation of this 365 // property, and keeps the layer visible. 366 layer()->SetVisible(true); 367 } 368 369 ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator()); 370 animation.SetTransitionDuration(base::TimeDelta::FromMilliseconds( 371 kAnimationDurationForVisibilityMs)); 372 animation.SetPreemptionStrategy( 373 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); 374 375 if (visible) { 376 animation.SetTweenType(gfx::Tween::EASE_OUT); 377 // Show is delayed so as to allow time for other children of 378 // StatusAreaWidget to begin animating to their new positions. 379 layer()->GetAnimator()->SchedulePauseForProperties( 380 base::TimeDelta::FromMilliseconds(kShowAnimationDelayMs), 381 ui::LayerAnimationElement::OPACITY | 382 ui::LayerAnimationElement::TRANSFORM); 383 layer()->SetOpacity(1.0f); 384 gfx::Transform transform; 385 transform.Translate(0.0f, 0.0f); 386 layer()->SetTransform(transform); 387 } else { 388 // Listen only to the hide animation. As we cannot turn off visibility 389 // until the animation is over. 390 animation.AddObserver(this); 391 animation.SetTweenType(gfx::Tween::EASE_IN); 392 layer()->SetOpacity(0.0f); 393 layer()->SetVisible(false); 394 HideTransformation(); 395 } 396} 397 398const char* TrayBackgroundView::GetClassName() const { 399 return kViewClassName; 400} 401 402void TrayBackgroundView::OnMouseEntered(const ui::MouseEvent& event) { 403 hovered_ = true; 404} 405 406void TrayBackgroundView::OnMouseExited(const ui::MouseEvent& event) { 407 hovered_ = false; 408} 409 410void TrayBackgroundView::ChildPreferredSizeChanged(views::View* child) { 411 PreferredSizeChanged(); 412} 413 414void TrayBackgroundView::GetAccessibleState(ui::AXViewState* state) { 415 state->role = ui::AX_ROLE_BUTTON; 416 state->name = GetAccessibleNameForTray(); 417} 418 419void TrayBackgroundView::AboutToRequestFocusFromTabTraversal(bool reverse) { 420 // Return focus to the login view. See crbug.com/120500. 421 views::View* v = GetNextFocusableView(); 422 if (v) 423 v->AboutToRequestFocusFromTabTraversal(reverse); 424} 425 426bool TrayBackgroundView::PerformAction(const ui::Event& event) { 427 return false; 428} 429 430gfx::Rect TrayBackgroundView::GetFocusBounds() { 431 // The tray itself expands to the right and bottom edge of the screen to make 432 // sure clicking on the edges brings up the popup. However, the focus border 433 // should be only around the container. 434 return GetContentsBounds(); 435} 436 437void TrayBackgroundView::OnGestureEvent(ui::GestureEvent* event) { 438 if (touch_feedback_enabled_) { 439 if (event->type() == ui::ET_GESTURE_TAP_DOWN) { 440 SetDrawBackgroundAsActive(true); 441 } else if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || 442 event->type() == ui::ET_GESTURE_TAP_CANCEL) { 443 SetDrawBackgroundAsActive(false); 444 } 445 } 446 ActionableView::OnGestureEvent(event); 447} 448 449void TrayBackgroundView::UpdateBackground(int alpha) { 450 // The animator should never fire when the alternate shelf layout is used. 451 if (!background_ || draw_background_as_active_) 452 return; 453 background_->set_alpha(hide_background_animator_.alpha() + 454 hover_background_animator_.alpha()); 455 SchedulePaint(); 456} 457 458void TrayBackgroundView::SetContents(views::View* contents) { 459 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)); 460 AddChildView(contents); 461} 462 463void TrayBackgroundView::SetPaintsBackground( 464 bool value, BackgroundAnimatorChangeType change_type) { 465 hide_background_animator_.SetPaintsBackground(value, change_type); 466} 467 468void TrayBackgroundView::SetContentsBackground() { 469 background_ = new TrayBackground(this); 470 tray_container_->set_background(background_); 471} 472 473ShelfLayoutManager* TrayBackgroundView::GetShelfLayoutManager() { 474 return ShelfLayoutManager::ForShelf(GetWidget()->GetNativeView()); 475} 476 477void TrayBackgroundView::SetShelfAlignment(ShelfAlignment alignment) { 478 shelf_alignment_ = alignment; 479 SetTrayBorder(); 480 tray_container_->SetAlignment(alignment); 481} 482 483void TrayBackgroundView::SetTrayBorder() { 484 views::View* parent = status_area_widget_->status_area_widget_delegate(); 485 // Tray views are laid out right-to-left or bottom-to-top 486 bool on_edge = (this == parent->child_at(0)); 487 int left_edge, top_edge, right_edge, bottom_edge; 488 if (shelf_alignment() == SHELF_ALIGNMENT_BOTTOM) { 489 top_edge = ShelfLayoutManager::kShelfItemInset; 490 left_edge = 0; 491 bottom_edge = kShelfSize - 492 ShelfLayoutManager::kShelfItemInset - kShelfItemHeight; 493 right_edge = on_edge ? kPaddingFromEdgeOfShelf : 0; 494 } else if (shelf_alignment() == SHELF_ALIGNMENT_LEFT) { 495 top_edge = 0; 496 left_edge = kShelfSize - 497 ShelfLayoutManager::kShelfItemInset - kShelfItemHeight; 498 bottom_edge = on_edge ? kPaddingFromEdgeOfShelf : 0; 499 right_edge = ShelfLayoutManager::kShelfItemInset; 500 } else { // SHELF_ALIGNMENT_RIGHT 501 top_edge = 0; 502 left_edge = ShelfLayoutManager::kShelfItemInset; 503 bottom_edge = on_edge ? kPaddingFromEdgeOfShelf : 0; 504 right_edge = kShelfSize - 505 ShelfLayoutManager::kShelfItemInset - kShelfItemHeight; 506 } 507 SetBorder(views::Border::CreateEmptyBorder( 508 top_edge, left_edge, bottom_edge, right_edge)); 509} 510 511void TrayBackgroundView::OnImplicitAnimationsCompleted() { 512 // If there is another animation in the queue, the reverse animation was 513 // triggered before the completion of animating to invisible. Do not turn off 514 // the visibility so that the next animation may render. The value of 515 // layer()->GetTargetVisibility() can be incorrect if the hide animation was 516 // aborted to schedule an animation to become visible. As the new animation 517 // is not yet added to the queue. crbug.com/374236 518 if(layer()->GetAnimator()->is_animating() || 519 layer()->GetTargetVisibility()) 520 return; 521 views::View::SetVisible(false); 522} 523 524void TrayBackgroundView::HideTransformation() { 525 gfx::Transform transform; 526 if (shelf_alignment_ == SHELF_ALIGNMENT_BOTTOM || 527 shelf_alignment_ == SHELF_ALIGNMENT_TOP) 528 transform.Translate(width(), 0.0f); 529 else 530 transform.Translate(0.0f, height()); 531 layer()->SetTransform(transform); 532} 533 534void TrayBackgroundView::InitializeBubbleAnimations( 535 views::Widget* bubble_widget) { 536 wm::SetWindowVisibilityAnimationType( 537 bubble_widget->GetNativeWindow(), 538 wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE); 539 wm::SetWindowVisibilityAnimationTransition( 540 bubble_widget->GetNativeWindow(), 541 wm::ANIMATE_HIDE); 542 wm::SetWindowVisibilityAnimationDuration( 543 bubble_widget->GetNativeWindow(), 544 base::TimeDelta::FromMilliseconds(kAnimationDurationForPopupMs)); 545} 546 547aura::Window* TrayBackgroundView::GetBubbleWindowContainer() const { 548 return ash::Shell::GetContainer( 549 tray_container()->GetWidget()->GetNativeWindow()->GetRootWindow(), 550 ash::kShellWindowId_SettingBubbleContainer); 551} 552 553gfx::Rect TrayBackgroundView::GetBubbleAnchorRect( 554 views::Widget* anchor_widget, 555 TrayBubbleView::AnchorType anchor_type, 556 TrayBubbleView::AnchorAlignment anchor_alignment) const { 557 gfx::Rect rect; 558 if (anchor_widget && anchor_widget->IsVisible()) { 559 rect = anchor_widget->GetWindowBoundsInScreen(); 560 if (anchor_type == TrayBubbleView::ANCHOR_TYPE_TRAY) { 561 if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM) { 562 bool rtl = base::i18n::IsRTL(); 563 rect.Inset( 564 rtl ? kBubblePaddingHorizontalSide : 0, 565 kBubblePaddingHorizontalBottom, 566 rtl ? 0 : kBubblePaddingHorizontalSide, 567 0); 568 } else if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_LEFT) { 569 rect.Inset(0, 0, kBubblePaddingVerticalSide + 4, 570 kBubblePaddingVerticalBottom); 571 } else if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_RIGHT) { 572 rect.Inset(kBubblePaddingVerticalSide, 0, 0, 573 kBubblePaddingVerticalBottom); 574 } else { 575 // TODO(bruthig) May need to handle other ANCHOR_ALIGNMENT_ values. 576 // ie. ANCHOR_ALIGNMENT_TOP 577 DCHECK(false) << "Unhandled anchor alignment."; 578 } 579 } else if (anchor_type == TrayBubbleView::ANCHOR_TYPE_BUBBLE) { 580 // Invert the offsets to align with the bubble below. 581 // Note that with the alternate shelf layout the tips are not shown and 582 // the offsets for left and right alignment do not need to be applied. 583 int vertical_alignment = 0; 584 int horizontal_alignment = kBubblePaddingVerticalBottom; 585 if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_LEFT) 586 rect.Inset(vertical_alignment, 0, 0, horizontal_alignment); 587 else if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_RIGHT) 588 rect.Inset(0, 0, vertical_alignment, horizontal_alignment); 589 } else { 590 DCHECK(false) << "Unhandled anchor type."; 591 } 592 } else { 593 aura::Window* target_root = anchor_widget ? 594 anchor_widget->GetNativeView()->GetRootWindow() : 595 Shell::GetPrimaryRootWindow(); 596 rect = target_root->bounds(); 597 if (anchor_type == TrayBubbleView::ANCHOR_TYPE_TRAY) { 598 if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM) { 599 rect = gfx::Rect( 600 base::i18n::IsRTL() ? 601 kPaddingFromRightEdgeOfScreenBottomAlignment : 602 rect.width() - kPaddingFromRightEdgeOfScreenBottomAlignment, 603 rect.height() - kPaddingFromBottomOfScreenBottomAlignment, 604 0, 0); 605 rect = ScreenUtil::ConvertRectToScreen(target_root, rect); 606 } else if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_LEFT) { 607 rect = gfx::Rect( 608 kPaddingFromRightEdgeOfScreenBottomAlignment, 609 rect.height() - kPaddingFromBottomOfScreenBottomAlignment, 610 1, 1); 611 rect = ScreenUtil::ConvertRectToScreen(target_root, rect); 612 } else if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_RIGHT) { 613 rect = gfx::Rect( 614 rect.width() - kPaddingFromRightEdgeOfScreenBottomAlignment, 615 rect.height() - kPaddingFromBottomOfScreenBottomAlignment, 616 1, 1); 617 rect = ScreenUtil::ConvertRectToScreen(target_root, rect); 618 } else { 619 // TODO(bruthig) May need to handle other ANCHOR_ALIGNMENT_ values. 620 // ie. ANCHOR_ALIGNMENT_TOP 621 DCHECK(false) << "Unhandled anchor alignment."; 622 } 623 } else { 624 rect = gfx::Rect( 625 base::i18n::IsRTL() ? 626 kPaddingFromRightEdgeOfScreenBottomAlignment : 627 rect.width() - kPaddingFromRightEdgeOfScreenBottomAlignment, 628 rect.height() - kPaddingFromBottomOfScreenBottomAlignment, 629 0, 0); 630 } 631 } 632 return rect; 633} 634 635TrayBubbleView::AnchorAlignment TrayBackgroundView::GetAnchorAlignment() const { 636 switch (shelf_alignment_) { 637 case SHELF_ALIGNMENT_BOTTOM: 638 return TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM; 639 case SHELF_ALIGNMENT_LEFT: 640 return TrayBubbleView::ANCHOR_ALIGNMENT_LEFT; 641 case SHELF_ALIGNMENT_RIGHT: 642 return TrayBubbleView::ANCHOR_ALIGNMENT_RIGHT; 643 case SHELF_ALIGNMENT_TOP: 644 return TrayBubbleView::ANCHOR_ALIGNMENT_TOP; 645 } 646 NOTREACHED(); 647 return TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM; 648} 649 650void TrayBackgroundView::SetDrawBackgroundAsActive(bool visible) { 651 if (draw_background_as_active_ == visible) 652 return; 653 draw_background_as_active_ = visible; 654 if (!background_) 655 return; 656 657 // Do not change gradually, changing color between grey and blue is weird. 658 if (draw_background_as_active_) 659 background_->set_color(kTrayBackgroundPressedColor); 660 else if (hovered_) 661 background_->set_alpha(kTrayBackgroundHoverAlpha); 662 else 663 background_->set_alpha(kTrayBackgroundAlpha); 664 SchedulePaint(); 665} 666 667void TrayBackgroundView::UpdateBubbleViewArrow( 668 views::TrayBubbleView* bubble_view) { 669 // Nothing to do here. 670} 671 672} // namespace ash 673