volume_bubble.cc revision 4a5e2dc747d50c653511c68ccb2cfbfb740bd5a7
1// Copyright (c) 2010 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 "chrome/browser/chromeos/volume_bubble.h"
6
7#include <gdk/gdk.h>
8
9#include "base/timer.h"
10#include "chrome/browser/browser_list.h"
11#include "chrome/browser/browser_window.h"
12#include "chrome/browser/profile_manager.h"
13#include "chrome/browser/chromeos/volume_bubble_view.h"
14#include "chrome/browser/ui/browser.h"
15#include "chrome/browser/views/info_bubble.h"
16#include "views/widget/root_view.h"
17
18namespace {
19
20const int kBubbleShowTimeoutSec = 2;
21const int kAnimationDurationMs = 200;
22
23// Horizontal relative position: 0 - leftmost, 0.5 - center, 1 - rightmost.
24const double kVolumeBubbleXRatio = 0.5;
25
26// Vertical gap from the bottom of the screen in pixels.
27const int kVolumeBubbleBottomGap = 30;
28
29}  // namespace
30
31namespace chromeos {
32
33// Temporary helper routine. Returns the widget from the most-recently-focused
34// normal browser window or NULL.
35// TODO(glotov): remove this in favor of enabling InfoBubble class act
36// without |parent| specified. crosbug.com/4025
37static views::Widget* GetToplevelWidget() {
38  // We just use the default profile here -- this gets overridden as needed
39  // in Chrome OS depending on whether the user is logged in or not.
40  Browser* browser =
41      BrowserList::FindBrowserWithType(
42          ProfileManager::GetDefaultProfile(),
43          Browser::TYPE_NORMAL,
44          true);  // match_incognito
45  if (!browser)
46    return NULL;
47
48  views::RootView* root =
49      views::Widget::FindRootView(
50          GTK_WINDOW(browser->window()->GetNativeHandle()));
51  DCHECK(root);
52  if (!root)
53    return NULL;
54
55  return root->GetWidget();
56}
57
58VolumeBubble::VolumeBubble()
59    : previous_percent_(-1),
60      current_percent_(-1),
61      bubble_(NULL),
62      view_(NULL),
63      animation_(this) {
64  animation_.SetSlideDuration(kAnimationDurationMs);
65  animation_.SetTweenType(Tween::LINEAR);
66}
67
68void VolumeBubble::ShowVolumeBubble(int percent) {
69  if (percent < 0)
70    percent = 0;
71  if (percent > 100)
72    percent = 100;
73  if (previous_percent_ == -1)
74    previous_percent_ = percent;
75  current_percent_ = percent;
76  if (!bubble_) {
77    views::Widget* widget = GetToplevelWidget();
78    if (widget == NULL)
79      return;
80    DCHECK(view_ == NULL);
81    view_ = new VolumeBubbleView;
82    view_->Init(previous_percent_);
83    // Calculate position of the volume bubble.
84    // TODO(glotov): Place volume bubble over the keys initiated the
85    // volume change. This metric must be specific to the given
86    // architecture. crosbug.com/4028
87    gfx::Rect bounds;
88    widget->GetBounds(&bounds, false);
89    const gfx::Size view_size = view_->GetPreferredSize();
90    // Note that (x, y) is the point of the center of the bubble.
91    const int x = view_size.width() / 2 +
92        kVolumeBubbleXRatio * (bounds.width() - view_size.width());
93    const int y = bounds.height() - view_size.height() / 2 -
94        kVolumeBubbleBottomGap;
95    bubble_ = InfoBubble::ShowFocusless(widget, gfx::Rect(x, y, 0, 20),
96                                        BubbleBorder::FLOAT, view_, this);
97  } else {
98    DCHECK(view_);
99    timeout_timer_.Stop();
100  }
101  if (animation_.is_animating())
102    animation_.End();
103  animation_.Reset();
104  animation_.Show();
105  timeout_timer_.Start(base::TimeDelta::FromSeconds(kBubbleShowTimeoutSec),
106                       this, &VolumeBubble::OnTimeout);
107}
108
109void VolumeBubble::OnTimeout() {
110  if (bubble_)
111    bubble_->Close();
112}
113
114void VolumeBubble::InfoBubbleClosing(InfoBubble* info_bubble, bool) {
115  DCHECK(info_bubble == bubble_);
116  timeout_timer_.Stop();
117  animation_.Stop();
118  bubble_ = NULL;
119  view_ = NULL;
120}
121
122void VolumeBubble::AnimationEnded(const Animation* animation) {
123  previous_percent_ = current_percent_;
124}
125
126void VolumeBubble::AnimationProgressed(const Animation* animation) {
127  if (view_) {
128    view_->Update(
129        Tween::ValueBetween(animation->GetCurrentValue(),
130                            previous_percent_,
131                            current_percent_));
132  }
133}
134
135}  // namespace chromeos
136