• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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/shelf/shelf_button.h"
6 
7 #include <algorithm>
8 
9 #include "ash/ash_constants.h"
10 #include "ash/ash_switches.h"
11 #include "ash/shelf/shelf_button_host.h"
12 #include "ash/shelf/shelf_layout_manager.h"
13 #include "grit/ash_resources.h"
14 #include "skia/ext/image_operations.h"
15 #include "ui/base/accessibility/accessible_view_state.h"
16 #include "ui/base/resource/resource_bundle.h"
17 #include "ui/compositor/layer.h"
18 #include "ui/compositor/scoped_layer_animation_settings.h"
19 #include "ui/events/event_constants.h"
20 #include "ui/gfx/animation/animation_delegate.h"
21 #include "ui/gfx/animation/throb_animation.h"
22 #include "ui/gfx/canvas.h"
23 #include "ui/gfx/image/image.h"
24 #include "ui/gfx/image/image_skia_operations.h"
25 #include "ui/gfx/skbitmap_operations.h"
26 #include "ui/views/controls/image_view.h"
27 
28 namespace {
29 
30 // Size of the bar. This is along the opposite axis of the shelf. For example,
31 // if the shelf is aligned horizontally then this is the height of the bar.
32 const int kBarSize = 3;
33 const int kIconSize = 32;
34 const int kHopSpacing = 2;
35 const int kIconPad = 8;
36 const int kAlternateIconPad = 5;
37 const int kAlternateIconPadVertical = 6;
38 const int kHopUpMS = 0;
39 const int kHopDownMS = 200;
40 const int kAttentionThrobDurationMS = 800;
41 
ShouldHop(int state)42 bool ShouldHop(int state) {
43   return state & ash::internal::ShelfButton::STATE_HOVERED ||
44          state & ash::internal::ShelfButton::STATE_ACTIVE ||
45          state & ash::internal::ShelfButton::STATE_FOCUSED;
46 }
47 
48 // Simple AnimationDelegate that owns a single ThrobAnimation instance to
49 // keep all Draw Attention animations in sync.
50 class ShelfButtonAnimation : public gfx::AnimationDelegate {
51  public:
52   class Observer {
53    public:
54     virtual void AnimationProgressed() = 0;
55 
56    protected:
~Observer()57     virtual ~Observer() {}
58   };
59 
GetInstance()60   static ShelfButtonAnimation* GetInstance() {
61     static ShelfButtonAnimation* s_instance = new ShelfButtonAnimation();
62     return s_instance;
63   }
64 
AddObserver(Observer * observer)65   void AddObserver(Observer* observer) {
66     observers_.AddObserver(observer);
67   }
68 
RemoveObserver(Observer * observer)69   void RemoveObserver(Observer* observer) {
70     observers_.RemoveObserver(observer);
71     if (!observers_.might_have_observers())
72       animation_.Stop();
73   }
74 
GetAlpha()75   int GetAlpha() {
76     return GetThrobAnimation().CurrentValueBetween(0, 255);
77   }
78 
GetAnimation()79   double GetAnimation() {
80     return GetThrobAnimation().GetCurrentValue();
81   }
82 
83  private:
ShelfButtonAnimation()84   ShelfButtonAnimation()
85       : animation_(this) {
86     animation_.SetThrobDuration(kAttentionThrobDurationMS);
87     animation_.SetTweenType(gfx::Tween::SMOOTH_IN_OUT);
88   }
89 
~ShelfButtonAnimation()90   virtual ~ShelfButtonAnimation() {
91   }
92 
GetThrobAnimation()93   gfx::ThrobAnimation& GetThrobAnimation() {
94     if (!animation_.is_animating()) {
95       animation_.Reset();
96       animation_.StartThrobbing(-1 /*throb indefinitely*/);
97     }
98     return animation_;
99   }
100 
101   // gfx::AnimationDelegate
AnimationProgressed(const gfx::Animation * animation)102   virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE {
103     if (animation != &animation_)
104       return;
105     if (!animation_.is_animating())
106       return;
107     FOR_EACH_OBSERVER(Observer, observers_, AnimationProgressed());
108   }
109 
110   gfx::ThrobAnimation animation_;
111   ObserverList<Observer> observers_;
112 
113   DISALLOW_COPY_AND_ASSIGN(ShelfButtonAnimation);
114 };
115 
116 }  // namespace
117 
118 namespace ash {
119 namespace internal {
120 
121 ////////////////////////////////////////////////////////////////////////////////
122 // ShelfButton::BarView
123 
124 class ShelfButton::BarView : public views::ImageView,
125                              public ShelfButtonAnimation::Observer {
126  public:
BarView(ShelfButton * host)127   BarView(ShelfButton* host)
128       : host_(host),
129         show_attention_(false) {
130   }
131 
~BarView()132   virtual ~BarView() {
133     if (show_attention_)
134       ShelfButtonAnimation::GetInstance()->RemoveObserver(this);
135   }
136 
137   // View
HitTestRect(const gfx::Rect & rect) const138   virtual bool HitTestRect(const gfx::Rect& rect) const OVERRIDE {
139     // Allow Mouse...() messages to go to the parent view.
140     return false;
141   }
142 
OnPaint(gfx::Canvas * canvas)143   virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
144     if (show_attention_) {
145       int alpha = ShelfButtonAnimation::GetInstance()->GetAlpha();
146       canvas->SaveLayerAlpha(alpha);
147       views::ImageView::OnPaint(canvas);
148       canvas->Restore();
149     } else {
150       views::ImageView::OnPaint(canvas);
151     }
152   }
153 
154   // ShelfButtonAnimation::Observer
AnimationProgressed()155   virtual void AnimationProgressed() OVERRIDE {
156     UpdateBounds();
157     SchedulePaint();
158   }
159 
SetBarBoundsRect(const gfx::Rect & bounds)160   void SetBarBoundsRect(const gfx::Rect& bounds) {
161     base_bounds_ = bounds;
162     UpdateBounds();
163   }
164 
ShowAttention(bool show)165   void ShowAttention(bool show) {
166     if (show_attention_ != show) {
167       show_attention_ = show;
168       if (show_attention_)
169         ShelfButtonAnimation::GetInstance()->AddObserver(this);
170       else
171         ShelfButtonAnimation::GetInstance()->RemoveObserver(this);
172     }
173     UpdateBounds();
174   }
175 
176  private:
UpdateBounds()177   void UpdateBounds() {
178     gfx::Rect bounds = base_bounds_;
179     if (show_attention_) {
180       // Scale from .35 to 1.0 of the total width (which is wider than the
181       // visible width of the image, so the animation "rests" briefly at full
182       // visible width.
183       double animation = ShelfButtonAnimation::GetInstance()->GetAnimation();
184       double scale = (.35 + .65 * animation);
185       if (host_->shelf_layout_manager()->GetAlignment() ==
186           SHELF_ALIGNMENT_BOTTOM) {
187         bounds.set_width(base_bounds_.width() * scale);
188         int x_offset = (base_bounds_.width() - bounds.width()) / 2;
189         bounds.set_x(base_bounds_.x() + x_offset);
190       } else {
191         bounds.set_height(base_bounds_.height() * scale);
192         int y_offset = (base_bounds_.height() - bounds.height()) / 2;
193         bounds.set_y(base_bounds_.y() + y_offset);
194       }
195     }
196     SetBoundsRect(bounds);
197   }
198 
199   ShelfButton* host_;
200   bool show_attention_;
201   gfx::Rect base_bounds_;
202 
203   DISALLOW_COPY_AND_ASSIGN(BarView);
204 };
205 
206 ////////////////////////////////////////////////////////////////////////////////
207 // ShelfButton::IconView
208 
IconView()209 ShelfButton::IconView::IconView() : icon_size_(kIconSize) {
210 }
211 
~IconView()212 ShelfButton::IconView::~IconView() {
213 }
214 
HitTestRect(const gfx::Rect & rect) const215 bool ShelfButton::IconView::HitTestRect(const gfx::Rect& rect) const {
216   // Return false so that ShelfButton gets all the mouse events.
217   return false;
218 }
219 
220 ////////////////////////////////////////////////////////////////////////////////
221 // ShelfButton
222 
Create(views::ButtonListener * listener,ShelfButtonHost * host,ShelfLayoutManager * shelf_layout_manager)223 ShelfButton* ShelfButton::Create(views::ButtonListener* listener,
224                                  ShelfButtonHost* host,
225                                  ShelfLayoutManager* shelf_layout_manager) {
226   ShelfButton* button = new ShelfButton(listener, host, shelf_layout_manager);
227   button->Init();
228   return button;
229 }
230 
ShelfButton(views::ButtonListener * listener,ShelfButtonHost * host,ShelfLayoutManager * shelf_layout_manager)231 ShelfButton::ShelfButton(views::ButtonListener* listener,
232                          ShelfButtonHost* host,
233                          ShelfLayoutManager* shelf_layout_manager)
234     : CustomButton(listener),
235       host_(host),
236       icon_view_(NULL),
237       bar_(new BarView(this)),
238       state_(STATE_NORMAL),
239       shelf_layout_manager_(shelf_layout_manager),
240       destroyed_flag_(NULL) {
241   SetAccessibilityFocusable(true);
242 
243   const gfx::ShadowValue kShadows[] = {
244     gfx::ShadowValue(gfx::Point(0, 2), 0, SkColorSetARGB(0x1A, 0, 0, 0)),
245     gfx::ShadowValue(gfx::Point(0, 3), 1, SkColorSetARGB(0x1A, 0, 0, 0)),
246     gfx::ShadowValue(gfx::Point(0, 0), 1, SkColorSetARGB(0x54, 0, 0, 0)),
247   };
248   icon_shadows_.assign(kShadows, kShadows + arraysize(kShadows));
249 
250   AddChildView(bar_);
251 }
252 
~ShelfButton()253 ShelfButton::~ShelfButton() {
254   if (destroyed_flag_)
255     *destroyed_flag_ = true;
256 }
257 
SetShadowedImage(const gfx::ImageSkia & image)258 void ShelfButton::SetShadowedImage(const gfx::ImageSkia& image) {
259   icon_view_->SetImage(gfx::ImageSkiaOperations::CreateImageWithDropShadow(
260       image, icon_shadows_));
261 }
262 
SetImage(const gfx::ImageSkia & image)263 void ShelfButton::SetImage(const gfx::ImageSkia& image) {
264   if (image.isNull()) {
265     // TODO: need an empty image.
266     icon_view_->SetImage(image);
267     return;
268   }
269 
270   if (icon_view_->icon_size() == 0) {
271     SetShadowedImage(image);
272     return;
273   }
274 
275   // Resize the image maintaining our aspect ratio.
276   int pref = icon_view_->icon_size();
277   float aspect_ratio =
278       static_cast<float>(image.width()) / static_cast<float>(image.height());
279   int height = pref;
280   int width = static_cast<int>(aspect_ratio * height);
281   if (width > pref) {
282     width = pref;
283     height = static_cast<int>(width / aspect_ratio);
284   }
285 
286   if (width == image.width() && height == image.height()) {
287     SetShadowedImage(image);
288     return;
289   }
290 
291   SetShadowedImage(gfx::ImageSkiaOperations::CreateResizedImage(image,
292       skia::ImageOperations::RESIZE_BEST, gfx::Size(width, height)));
293 }
294 
GetImage() const295 const gfx::ImageSkia& ShelfButton::GetImage() const {
296   return icon_view_->GetImage();
297 }
298 
AddState(State state)299 void ShelfButton::AddState(State state) {
300   if (!(state_ & state)) {
301     if (!ash::switches::UseAlternateShelfLayout() &&
302         (ShouldHop(state) || !ShouldHop(state_))) {
303       ui::ScopedLayerAnimationSettings scoped_setter(
304           icon_view_->layer()->GetAnimator());
305       scoped_setter.SetTransitionDuration(
306           base::TimeDelta::FromMilliseconds(kHopUpMS));
307     }
308     state_ |= state;
309     Layout();
310     if (state & STATE_ATTENTION)
311       bar_->ShowAttention(true);
312   }
313 }
314 
ClearState(State state)315 void ShelfButton::ClearState(State state) {
316   if (state_ & state) {
317     if (!ash::switches::UseAlternateShelfLayout() &&
318         (!ShouldHop(state) || ShouldHop(state_))) {
319       ui::ScopedLayerAnimationSettings scoped_setter(
320           icon_view_->layer()->GetAnimator());
321       scoped_setter.SetTweenType(gfx::Tween::LINEAR);
322       scoped_setter.SetTransitionDuration(
323           base::TimeDelta::FromMilliseconds(kHopDownMS));
324     }
325     state_ &= ~state;
326     Layout();
327     if (state & STATE_ATTENTION)
328       bar_->ShowAttention(false);
329   }
330 }
331 
GetIconBounds() const332 gfx::Rect ShelfButton::GetIconBounds() const {
333   return icon_view_->bounds();
334 }
335 
ShowContextMenu(const gfx::Point & p,ui::MenuSourceType source_type)336 void ShelfButton::ShowContextMenu(const gfx::Point& p,
337                                   ui::MenuSourceType source_type) {
338   if (!context_menu_controller())
339     return;
340 
341   bool destroyed = false;
342   destroyed_flag_ = &destroyed;
343 
344   CustomButton::ShowContextMenu(p, source_type);
345 
346   if (!destroyed) {
347     destroyed_flag_ = NULL;
348     // The menu will not propagate mouse events while its shown. To address,
349     // the hover state gets cleared once the menu was shown (and this was not
350     // destroyed).
351     ClearState(STATE_HOVERED);
352   }
353 }
354 
OnMousePressed(const ui::MouseEvent & event)355 bool ShelfButton::OnMousePressed(const ui::MouseEvent& event) {
356   CustomButton::OnMousePressed(event);
357   host_->PointerPressedOnButton(this, ShelfButtonHost::MOUSE, event);
358   return true;
359 }
360 
OnMouseReleased(const ui::MouseEvent & event)361 void ShelfButton::OnMouseReleased(const ui::MouseEvent& event) {
362   CustomButton::OnMouseReleased(event);
363   host_->PointerReleasedOnButton(this, ShelfButtonHost::MOUSE, false);
364 }
365 
OnMouseCaptureLost()366 void ShelfButton::OnMouseCaptureLost() {
367   ClearState(STATE_HOVERED);
368   host_->PointerReleasedOnButton(this, ShelfButtonHost::MOUSE, true);
369   CustomButton::OnMouseCaptureLost();
370 }
371 
OnMouseDragged(const ui::MouseEvent & event)372 bool ShelfButton::OnMouseDragged(const ui::MouseEvent& event) {
373   CustomButton::OnMouseDragged(event);
374   host_->PointerDraggedOnButton(this, ShelfButtonHost::MOUSE, event);
375   return true;
376 }
377 
OnMouseMoved(const ui::MouseEvent & event)378 void ShelfButton::OnMouseMoved(const ui::MouseEvent& event) {
379   CustomButton::OnMouseMoved(event);
380   host_->MouseMovedOverButton(this);
381 }
382 
OnMouseEntered(const ui::MouseEvent & event)383 void ShelfButton::OnMouseEntered(const ui::MouseEvent& event) {
384   AddState(STATE_HOVERED);
385   CustomButton::OnMouseEntered(event);
386   host_->MouseEnteredButton(this);
387 }
388 
OnMouseExited(const ui::MouseEvent & event)389 void ShelfButton::OnMouseExited(const ui::MouseEvent& event) {
390   ClearState(STATE_HOVERED);
391   CustomButton::OnMouseExited(event);
392   host_->MouseExitedButton(this);
393 }
394 
GetAccessibleState(ui::AccessibleViewState * state)395 void ShelfButton::GetAccessibleState(ui::AccessibleViewState* state) {
396   state->role = ui::AccessibilityTypes::ROLE_PUSHBUTTON;
397   state->name = host_->GetAccessibleName(this);
398 }
399 
Layout()400 void ShelfButton::Layout() {
401   const gfx::Rect button_bounds(GetContentsBounds());
402   int icon_pad = kIconPad;
403   if (ash::switches::UseAlternateShelfLayout()) {
404       icon_pad =
405           shelf_layout_manager_->GetAlignment() != SHELF_ALIGNMENT_BOTTOM ?
406           kAlternateIconPadVertical : kAlternateIconPad;
407   }
408   int x_offset = shelf_layout_manager_->PrimaryAxisValue(0, icon_pad);
409   int y_offset = shelf_layout_manager_->PrimaryAxisValue(icon_pad, 0);
410 
411   int icon_width = std::min(kIconSize,
412       button_bounds.width() - x_offset);
413   int icon_height = std::min(kIconSize,
414       button_bounds.height() - y_offset);
415 
416   // If on the left or top 'invert' the inset so the constant gap is on
417   // the interior (towards the center of display) edge of the shelf.
418   if (SHELF_ALIGNMENT_LEFT == shelf_layout_manager_->GetAlignment())
419     x_offset = button_bounds.width() - (kIconSize + icon_pad);
420 
421   if (SHELF_ALIGNMENT_TOP == shelf_layout_manager_->GetAlignment())
422     y_offset = button_bounds.height() - (kIconSize + icon_pad);
423 
424   if (ShouldHop(state_) && !ash::switches::UseAlternateShelfLayout()) {
425     x_offset += shelf_layout_manager_->SelectValueForShelfAlignment(
426         0, kHopSpacing, -kHopSpacing, 0);
427     y_offset += shelf_layout_manager_->SelectValueForShelfAlignment(
428         -kHopSpacing, 0, 0, kHopSpacing);
429   }
430 
431   // Center icon with respect to the secondary axis, and ensure
432   // that the icon doesn't occlude the bar highlight.
433   if (shelf_layout_manager_->IsHorizontalAlignment()) {
434     x_offset = std::max(0, button_bounds.width() - icon_width) / 2;
435     if (y_offset + icon_height + kBarSize > button_bounds.height())
436       icon_height = button_bounds.height() - (y_offset + kBarSize);
437   } else {
438     y_offset = std::max(0, button_bounds.height() - icon_height) / 2;
439     if (x_offset + icon_width + kBarSize > button_bounds.width())
440       icon_width = button_bounds.width() - (x_offset + kBarSize);
441   }
442 
443   icon_view_->SetBoundsRect(gfx::Rect(
444       button_bounds.x() + x_offset,
445       button_bounds.y() + y_offset,
446       icon_width,
447       icon_height));
448 
449   // Icon size has been incorrect when running
450   // PanelLayoutManagerTest.PanelAlignmentSecondDisplay on valgrind bot, see
451   // http://crbug.com/234854.
452   DCHECK_LE(icon_width, kIconSize);
453   DCHECK_LE(icon_height, kIconSize);
454 
455   bar_->SetBarBoundsRect(button_bounds);
456 
457   UpdateState();
458 }
459 
ChildPreferredSizeChanged(views::View * child)460 void ShelfButton::ChildPreferredSizeChanged(views::View* child) {
461   Layout();
462 }
463 
OnFocus()464 void ShelfButton::OnFocus() {
465   AddState(STATE_FOCUSED);
466   CustomButton::OnFocus();
467 }
468 
OnBlur()469 void ShelfButton::OnBlur() {
470   ClearState(STATE_FOCUSED);
471   CustomButton::OnBlur();
472 }
473 
OnPaint(gfx::Canvas * canvas)474 void ShelfButton::OnPaint(gfx::Canvas* canvas) {
475   CustomButton::OnPaint(canvas);
476   if (HasFocus()) {
477     gfx::Rect paint_bounds(GetLocalBounds());
478     paint_bounds.Inset(1, 1, 1, 1);
479     canvas->DrawSolidFocusRect(paint_bounds, kFocusBorderColor);
480   }
481 }
482 
OnGestureEvent(ui::GestureEvent * event)483 void ShelfButton::OnGestureEvent(ui::GestureEvent* event) {
484   switch (event->type()) {
485     case ui::ET_GESTURE_TAP_DOWN:
486       AddState(STATE_HOVERED);
487       return CustomButton::OnGestureEvent(event);
488     case ui::ET_GESTURE_END:
489       ClearState(STATE_HOVERED);
490       return CustomButton::OnGestureEvent(event);
491     case ui::ET_GESTURE_SCROLL_BEGIN:
492       host_->PointerPressedOnButton(this, ShelfButtonHost::TOUCH, *event);
493       event->SetHandled();
494       return;
495     case ui::ET_GESTURE_SCROLL_UPDATE:
496       host_->PointerDraggedOnButton(this, ShelfButtonHost::TOUCH, *event);
497       event->SetHandled();
498       return;
499     case ui::ET_GESTURE_SCROLL_END:
500     case ui::ET_SCROLL_FLING_START:
501       host_->PointerReleasedOnButton(this, ShelfButtonHost::TOUCH, false);
502       event->SetHandled();
503       return;
504     default:
505       return CustomButton::OnGestureEvent(event);
506   }
507 }
508 
Init()509 void ShelfButton::Init() {
510   icon_view_ = CreateIconView();
511 
512   // TODO: refactor the layers so each button doesn't require 2.
513   icon_view_->SetPaintToLayer(true);
514   icon_view_->SetFillsBoundsOpaquely(false);
515   icon_view_->SetHorizontalAlignment(views::ImageView::CENTER);
516   icon_view_->SetVerticalAlignment(views::ImageView::LEADING);
517 
518   AddChildView(icon_view_);
519 }
520 
CreateIconView()521 ShelfButton::IconView* ShelfButton::CreateIconView() {
522   return new IconView;
523 }
524 
IsShelfHorizontal() const525 bool ShelfButton::IsShelfHorizontal() const {
526   return shelf_layout_manager_->IsHorizontalAlignment();
527 }
528 
UpdateState()529 void ShelfButton::UpdateState() {
530   UpdateBar();
531 
532   icon_view_->SetHorizontalAlignment(
533       shelf_layout_manager_->PrimaryAxisValue(views::ImageView::CENTER,
534                                               views::ImageView::LEADING));
535   icon_view_->SetVerticalAlignment(
536       shelf_layout_manager_->PrimaryAxisValue(views::ImageView::LEADING,
537                                               views::ImageView::CENTER));
538   SchedulePaint();
539 }
540 
UpdateBar()541 void ShelfButton::UpdateBar() {
542   if (state_ & STATE_HIDDEN) {
543     bar_->SetVisible(false);
544     return;
545   }
546 
547   int bar_id = 0;
548   if (ash::switches::UseAlternateShelfLayout()) {
549     if (state_ & STATE_ACTIVE)
550       bar_id = IDR_AURA_LAUNCHER_UNDERLINE_ACTIVE_ALTERNATE;
551     else if (state_ & STATE_RUNNING)
552       bar_id = IDR_AURA_LAUNCHER_UNDERLINE_RUNNING_ALTERNATE;
553   } else {
554     if (state_ & (STATE_ACTIVE | STATE_ATTENTION))
555       bar_id = IDR_AURA_LAUNCHER_UNDERLINE_ACTIVE;
556     else if (state_ & (STATE_HOVERED | STATE_FOCUSED))
557       bar_id = IDR_AURA_LAUNCHER_UNDERLINE_HOVER;
558     else
559       bar_id = IDR_AURA_LAUNCHER_UNDERLINE_RUNNING;
560   }
561 
562   if (bar_id != 0) {
563     ResourceBundle& rb = ResourceBundle::GetSharedInstance();
564     const gfx::ImageSkia* image = rb.GetImageNamed(bar_id).ToImageSkia();
565     if (shelf_layout_manager_->GetAlignment() == SHELF_ALIGNMENT_BOTTOM) {
566       bar_->SetImage(*image);
567     } else {
568       bar_->SetImage(gfx::ImageSkiaOperations::CreateRotatedImage(*image,
569           shelf_layout_manager_->SelectValueForShelfAlignment(
570               SkBitmapOperations::ROTATION_90_CW,
571               SkBitmapOperations::ROTATION_90_CW,
572               SkBitmapOperations::ROTATION_270_CW,
573               SkBitmapOperations::ROTATION_180_CW)));
574     }
575     bar_->SetHorizontalAlignment(
576         shelf_layout_manager_->SelectValueForShelfAlignment(
577             views::ImageView::CENTER,
578             views::ImageView::LEADING,
579             views::ImageView::TRAILING,
580             views::ImageView::CENTER));
581     bar_->SetVerticalAlignment(
582         shelf_layout_manager_->SelectValueForShelfAlignment(
583             views::ImageView::TRAILING,
584             views::ImageView::CENTER,
585             views::ImageView::CENTER,
586             views::ImageView::LEADING));
587     bar_->SchedulePaint();
588   }
589 
590   bar_->SetVisible(bar_id != 0 && state_ != STATE_NORMAL);
591 }
592 
593 }  // namespace internal
594 }  // namespace ash
595