Bluetooth: don't connect to unconnectable devices or disconnect
[chromium-blink-merge.git] / ash / system / tray / tray_background_view.cc
blob857ab38903d092adc9ad885a624e70cb8c6cca6f
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.
5 #include "ash/system/tray/tray_background_view.h"
7 #include "ash/root_window_controller.h"
8 #include "ash/screen_ash.h"
9 #include "ash/shelf/shelf_layout_manager.h"
10 #include "ash/shell.h"
11 #include "ash/shell_window_ids.h"
12 #include "ash/system/status_area_widget.h"
13 #include "ash/system/status_area_widget_delegate.h"
14 #include "ash/system/tray/tray_constants.h"
15 #include "ash/system/tray/tray_event_filter.h"
16 #include "ash/wm/property_util.h"
17 #include "ash/wm/window_animations.h"
18 #include "ui/aura/root_window.h"
19 #include "ui/aura/window.h"
20 #include "ui/base/accessibility/accessible_view_state.h"
21 #include "ui/gfx/canvas.h"
22 #include "ui/gfx/rect.h"
23 #include "ui/gfx/screen.h"
24 #include "ui/gfx/skia_util.h"
25 #include "ui/views/background.h"
26 #include "ui/views/layout/box_layout.h"
28 namespace {
30 const SkColor kTrayBackgroundAlpha = 100;
31 const SkColor kTrayBackgroundHoverAlpha = 150;
33 // Adjust the size of TrayContainer with additional padding.
34 const int kTrayContainerVerticalPaddingBottomAlignment = 1;
35 const int kTrayContainerHorizontalPaddingBottomAlignment = 1;
36 const int kTrayContainerVerticalPaddingVerticalAlignment = 1;
37 const int kTrayContainerHorizontalPaddingVerticalAlignment = 1;
39 const int kAnimationDurationForPopupMS = 200;
41 } // namespace
43 using views::TrayBubbleView;
45 namespace ash {
46 namespace internal {
48 // Used to track when the anchor widget changes position on screen so that the
49 // bubble position can be updated.
50 class TrayBackgroundView::TrayWidgetObserver : public views::WidgetObserver {
51 public:
52 explicit TrayWidgetObserver(TrayBackgroundView* host)
53 : host_(host) {
56 virtual void OnWidgetBoundsChanged(views::Widget* widget,
57 const gfx::Rect& new_bounds) OVERRIDE {
58 host_->AnchorUpdated();
61 virtual void OnWidgetVisibilityChanged(views::Widget* widget,
62 bool visible) OVERRIDE {
63 host_->AnchorUpdated();
66 private:
67 TrayBackgroundView* host_;
69 DISALLOW_COPY_AND_ASSIGN(TrayWidgetObserver);
72 class TrayBackground : public views::Background {
73 public:
74 TrayBackground() : alpha_(kTrayBackgroundAlpha) {}
75 virtual ~TrayBackground() {}
77 void set_alpha(int alpha) { alpha_ = alpha; }
79 private:
80 // Overridden from views::Background.
81 virtual void Paint(gfx::Canvas* canvas, views::View* view) const OVERRIDE {
82 SkPaint paint;
83 paint.setAntiAlias(true);
84 paint.setStyle(SkPaint::kFill_Style);
85 paint.setColor(SkColorSetARGB(alpha_, 0, 0, 0));
86 SkPath path;
87 gfx::Rect bounds(view->GetLocalBounds());
88 SkScalar radius = SkIntToScalar(kTrayRoundedBorderRadius);
89 path.addRoundRect(gfx::RectToSkRect(bounds), radius, radius);
90 canvas->DrawPath(path, paint);
93 int alpha_;
95 DISALLOW_COPY_AND_ASSIGN(TrayBackground);
98 TrayBackgroundView::TrayContainer::TrayContainer(ShelfAlignment alignment)
99 : alignment_(alignment) {
100 UpdateLayout();
103 void TrayBackgroundView::TrayContainer::SetAlignment(ShelfAlignment alignment) {
104 if (alignment_ == alignment)
105 return;
106 alignment_ = alignment;
107 UpdateLayout();
110 gfx::Size TrayBackgroundView::TrayContainer::GetPreferredSize() {
111 if (size_.IsEmpty())
112 return views::View::GetPreferredSize();
113 return size_;
116 void TrayBackgroundView::TrayContainer::ChildPreferredSizeChanged(
117 views::View* child) {
118 PreferredSizeChanged();
121 void TrayBackgroundView::TrayContainer::ChildVisibilityChanged(View* child) {
122 PreferredSizeChanged();
125 void TrayBackgroundView::TrayContainer::ViewHierarchyChanged(bool is_add,
126 View* parent,
127 View* child) {
128 if (parent == this)
129 PreferredSizeChanged();
132 void TrayBackgroundView::TrayContainer::UpdateLayout() {
133 // Adjust the size of status tray dark background by adding additional
134 // empty border.
135 if (alignment_ == SHELF_ALIGNMENT_BOTTOM ||
136 alignment_ == SHELF_ALIGNMENT_TOP) {
137 set_border(views::Border::CreateEmptyBorder(
138 kTrayContainerVerticalPaddingBottomAlignment,
139 kTrayContainerHorizontalPaddingBottomAlignment,
140 kTrayContainerVerticalPaddingBottomAlignment,
141 kTrayContainerHorizontalPaddingBottomAlignment));
142 views::BoxLayout* layout =
143 new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0);
144 layout->set_spread_blank_space(true);
145 views::View::SetLayoutManager(layout);
146 } else {
147 set_border(views::Border::CreateEmptyBorder(
148 kTrayContainerVerticalPaddingVerticalAlignment,
149 kTrayContainerHorizontalPaddingVerticalAlignment,
150 kTrayContainerVerticalPaddingVerticalAlignment,
151 kTrayContainerHorizontalPaddingVerticalAlignment));
152 views::BoxLayout* layout =
153 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0);
154 layout->set_spread_blank_space(true);
155 views::View::SetLayoutManager(layout);
157 PreferredSizeChanged();
160 ////////////////////////////////////////////////////////////////////////////////
161 // TrayBackgroundView
163 TrayBackgroundView::TrayBackgroundView(
164 internal::StatusAreaWidget* status_area_widget)
165 : status_area_widget_(status_area_widget),
166 tray_container_(NULL),
167 shelf_alignment_(SHELF_ALIGNMENT_BOTTOM),
168 background_(NULL),
169 ALLOW_THIS_IN_INITIALIZER_LIST(hide_background_animator_(
170 this, 0, kTrayBackgroundAlpha)),
171 ALLOW_THIS_IN_INITIALIZER_LIST(hover_background_animator_(
172 this, 0, kTrayBackgroundHoverAlpha - kTrayBackgroundAlpha)),
173 ALLOW_THIS_IN_INITIALIZER_LIST(widget_observer_(
174 new TrayWidgetObserver(this))) {
175 set_notify_enter_exit_on_child(true);
177 // Initially we want to paint the background, but without the hover effect.
178 SetPaintsBackground(true, internal::BackgroundAnimator::CHANGE_IMMEDIATE);
179 hover_background_animator_.SetPaintsBackground(false,
180 internal::BackgroundAnimator::CHANGE_IMMEDIATE);
182 tray_container_ = new TrayContainer(shelf_alignment_);
183 SetContents(tray_container_);
184 tray_event_filter_.reset(new TrayEventFilter);
187 TrayBackgroundView::~TrayBackgroundView() {
188 if (GetWidget())
189 GetWidget()->RemoveObserver(widget_observer_.get());
192 void TrayBackgroundView::Initialize() {
193 GetWidget()->AddObserver(widget_observer_.get());
194 SetBorder();
197 void TrayBackgroundView::OnMouseEntered(const ui::MouseEvent& event) {
198 hover_background_animator_.SetPaintsBackground(true,
199 internal::BackgroundAnimator::CHANGE_ANIMATE);
202 void TrayBackgroundView::OnMouseExited(const ui::MouseEvent& event) {
203 hover_background_animator_.SetPaintsBackground(false,
204 internal::BackgroundAnimator::CHANGE_ANIMATE);
207 void TrayBackgroundView::ChildPreferredSizeChanged(views::View* child) {
208 PreferredSizeChanged();
211 void TrayBackgroundView::OnPaintFocusBorder(gfx::Canvas* canvas) {
212 // The tray itself expands to the right and bottom edge of the screen to make
213 // sure clicking on the edges brings up the popup. However, the focus border
214 // should be only around the container.
215 if (HasFocus() && (focusable() || IsAccessibilityFocusable()))
216 DrawBorder(canvas, GetContentsBounds());
219 void TrayBackgroundView::GetAccessibleState(ui::AccessibleViewState* state) {
220 state->role = ui::AccessibilityTypes::ROLE_PUSHBUTTON;
221 state->name = GetAccessibleNameForTray();
224 void TrayBackgroundView::AboutToRequestFocusFromTabTraversal(bool reverse) {
225 // Return focus to the login view. See crbug.com/120500.
226 views::View* v = GetNextFocusableView();
227 if (v)
228 v->AboutToRequestFocusFromTabTraversal(reverse);
231 bool TrayBackgroundView::PerformAction(const ui::Event& event) {
232 return false;
235 void TrayBackgroundView::UpdateBackground(int alpha) {
236 if (background_) {
237 background_->set_alpha(hide_background_animator_.alpha() +
238 hover_background_animator_.alpha());
240 SchedulePaint();
243 void TrayBackgroundView::SetContents(views::View* contents) {
244 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
245 AddChildView(contents);
248 void TrayBackgroundView::SetPaintsBackground(
249 bool value,
250 internal::BackgroundAnimator::ChangeType change_type) {
251 hide_background_animator_.SetPaintsBackground(value, change_type);
254 void TrayBackgroundView::SetContentsBackground() {
255 background_ = new internal::TrayBackground;
256 tray_container_->set_background(background_);
259 ShelfLayoutManager* TrayBackgroundView::GetShelfLayoutManager() {
260 return ShelfLayoutManager::ForLauncher(GetWidget()->GetNativeView());
263 void TrayBackgroundView::SetShelfAlignment(ShelfAlignment alignment) {
264 shelf_alignment_ = alignment;
265 SetBorder();
266 tray_container_->SetAlignment(alignment);
269 void TrayBackgroundView::SetBorder() {
270 views::View* parent = status_area_widget_->status_area_widget_delegate();
271 // Tray views are laid out right-to-left or bottom-to-top
272 int on_edge = (this == parent->child_at(0));
273 // Change the border padding for different shelf alignment.
274 if (shelf_alignment() == SHELF_ALIGNMENT_BOTTOM) {
275 set_border(views::Border::CreateEmptyBorder(
276 0, 0,
277 on_edge ? kPaddingFromBottomOfScreenBottomAlignment :
278 kPaddingFromBottomOfScreenBottomAlignment - 1,
279 on_edge ? kPaddingFromRightEdgeOfScreenBottomAlignment : 0));
280 } else if (shelf_alignment() == SHELF_ALIGNMENT_TOP) {
281 set_border(views::Border::CreateEmptyBorder(
282 on_edge ? kPaddingFromBottomOfScreenBottomAlignment :
283 kPaddingFromBottomOfScreenBottomAlignment - 1,
284 0, 0,
285 on_edge ? kPaddingFromRightEdgeOfScreenBottomAlignment : 0));
286 } else if (shelf_alignment() == SHELF_ALIGNMENT_LEFT) {
287 set_border(views::Border::CreateEmptyBorder(
288 0, kPaddingFromOuterEdgeOfLauncherVerticalAlignment,
289 on_edge ? kPaddingFromBottomOfScreenVerticalAlignment : 0,
290 kPaddingFromInnerEdgeOfLauncherVerticalAlignment));
291 } else {
292 set_border(views::Border::CreateEmptyBorder(
293 0, kPaddingFromInnerEdgeOfLauncherVerticalAlignment,
294 on_edge ? kPaddingFromBottomOfScreenVerticalAlignment : 0,
295 kPaddingFromOuterEdgeOfLauncherVerticalAlignment));
299 void TrayBackgroundView::InitializeBubbleAnimations(
300 views::Widget* bubble_widget) {
301 views::corewm::SetWindowVisibilityAnimationType(
302 bubble_widget->GetNativeWindow(),
303 views::corewm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
304 views::corewm::SetWindowVisibilityAnimationTransition(
305 bubble_widget->GetNativeWindow(),
306 views::corewm::ANIMATE_HIDE);
307 views::corewm::SetWindowVisibilityAnimationDuration(
308 bubble_widget->GetNativeWindow(),
309 base::TimeDelta::FromMilliseconds(kAnimationDurationForPopupMS));
312 aura::Window* TrayBackgroundView::GetBubbleWindowContainer() const {
313 return ash::Shell::GetContainer(
314 tray_container()->GetWidget()->GetNativeWindow()->GetRootWindow(),
315 ash::internal::kShellWindowId_SettingBubbleContainer);
318 gfx::Rect TrayBackgroundView::GetBubbleAnchorRect(
319 views::Widget* anchor_widget,
320 TrayBubbleView::AnchorType anchor_type,
321 TrayBubbleView::AnchorAlignment anchor_alignment) const {
322 gfx::Rect rect;
323 if (anchor_widget && anchor_widget->IsVisible()) {
324 rect = anchor_widget->GetWindowBoundsInScreen();
325 if (anchor_type == TrayBubbleView::ANCHOR_TYPE_TRAY) {
326 if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM) {
327 bool rtl = base::i18n::IsRTL();
328 rect.Inset(
329 rtl ? kPaddingFromRightEdgeOfScreenBottomAlignment : 0,
330 kTrayBubbleAnchorTopInsetBottomAnchor,
331 rtl ? 0 : kPaddingFromRightEdgeOfScreenBottomAlignment,
332 kPaddingFromBottomOfScreenBottomAlignment);
333 } else if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_LEFT) {
334 rect.Inset(0, 0, kPaddingFromInnerEdgeOfLauncherVerticalAlignment + 5,
335 kPaddingFromBottomOfScreenVerticalAlignment);
336 } else {
337 rect.Inset(kPaddingFromInnerEdgeOfLauncherVerticalAlignment + 1,
338 0, 0, kPaddingFromBottomOfScreenVerticalAlignment);
340 } else if (anchor_type == TrayBubbleView::ANCHOR_TYPE_BUBBLE) {
341 // Invert the offsets to align with the bubble below.
342 if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_LEFT) {
343 rect.Inset(kPaddingFromInnerEdgeOfLauncherVerticalAlignment,
344 0, 0, kPaddingFromBottomOfScreenVerticalAlignment);
345 } else if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_RIGHT) {
346 rect.Inset(0, 0, kPaddingFromInnerEdgeOfLauncherVerticalAlignment,
347 kPaddingFromBottomOfScreenVerticalAlignment);
352 // TODO(jennyz): May need to add left/right alignment in the following code.
353 if (rect.IsEmpty()) {
354 aura::RootWindow* target_root = anchor_widget ?
355 anchor_widget->GetNativeView()->GetRootWindow() :
356 Shell::GetPrimaryRootWindow();
357 rect = target_root->bounds();
358 rect = gfx::Rect(
359 base::i18n::IsRTL() ? kPaddingFromRightEdgeOfScreenBottomAlignment :
360 rect.width() - kPaddingFromRightEdgeOfScreenBottomAlignment,
361 rect.height() - kPaddingFromBottomOfScreenBottomAlignment,
362 0, 0);
363 rect = ScreenAsh::ConvertRectToScreen(target_root, rect);
365 return rect;
368 TrayBubbleView::AnchorAlignment TrayBackgroundView::GetAnchorAlignment() const {
369 switch (shelf_alignment_) {
370 case SHELF_ALIGNMENT_BOTTOM:
371 return TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM;
372 case SHELF_ALIGNMENT_LEFT:
373 return TrayBubbleView::ANCHOR_ALIGNMENT_LEFT;
374 case SHELF_ALIGNMENT_RIGHT:
375 return TrayBubbleView::ANCHOR_ALIGNMENT_RIGHT;
376 case SHELF_ALIGNMENT_TOP:
377 return TrayBubbleView::ANCHOR_ALIGNMENT_TOP;
379 NOTREACHED();
380 return TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM;
383 void TrayBackgroundView::UpdateBubbleViewArrow(
384 views::TrayBubbleView* bubble_view) {
385 aura::RootWindow* root_window =
386 bubble_view->GetWidget()->GetNativeView()->GetRootWindow();
387 ash::internal::ShelfLayoutManager* shelf =
388 ShelfLayoutManager::ForLauncher(root_window);
389 bubble_view->SetArrowPaintType(
390 shelf->IsVisible() ? views::BubbleBorder::PAINT_NORMAL :
391 views::BubbleBorder::PAINT_TRANSPARENT);
394 } // namespace internal
395 } // namespace ash