tray_brightness.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
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/system/chromeos/brightness/tray_brightness.h"
6
7#include "ash/accelerators/accelerator_controller.h"
8#include "ash/ash_constants.h"
9#include "ash/display/display_manager.h"
10#include "ash/metrics/user_metrics_recorder.h"
11#include "ash/shell.h"
12#include "ash/shell_observer.h"
13#include "ash/system/brightness_control_delegate.h"
14#include "ash/system/tray/fixed_sized_image_view.h"
15#include "ash/system/tray/system_tray_delegate.h"
16#include "ash/system/tray/system_tray_notifier.h"
17#include "ash/system/tray/tray_constants.h"
18#include "base/bind.h"
19#include "base/message_loop/message_loop.h"
20#include "base/strings/utf_string_conversions.h"
21#include "chromeos/dbus/dbus_thread_manager.h"
22#include "chromeos/dbus/power_manager_client.h"
23#include "grit/ash_resources.h"
24#include "grit/ash_strings.h"
25#include "ui/base/resource/resource_bundle.h"
26#include "ui/gfx/image/image.h"
27#include "ui/views/controls/button/image_button.h"
28#include "ui/views/controls/image_view.h"
29#include "ui/views/controls/label.h"
30#include "ui/views/controls/slider.h"
31#include "ui/views/layout/box_layout.h"
32#include "ui/views/view.h"
33
34namespace ash {
35namespace tray {
36namespace {
37
38// We don't let the screen brightness go lower than this when it's being
39// adjusted via the slider.  Otherwise, if the user doesn't know about the
40// brightness keys, they may turn the backlight off and not know how to turn it
41// back on.
42const double kMinBrightnessPercent = 5.0;
43
44}  // namespace
45
46class BrightnessView : public ShellObserver,
47                       public views::View,
48                       public views::SliderListener {
49 public:
50  BrightnessView(bool default_view, double initial_percent);
51  virtual ~BrightnessView();
52
53  bool is_default_view() const {
54    return is_default_view_;
55  }
56
57  // |percent| is in the range [0.0, 100.0].
58  void SetBrightnessPercent(double percent);
59
60  // ShellObserver:
61  virtual void OnMaximizeModeStarted() OVERRIDE;
62  virtual void OnMaximizeModeEnded() OVERRIDE;
63
64 private:
65  // views::View:
66  virtual void OnBoundsChanged(const gfx::Rect& old_bounds) OVERRIDE;
67
68  // views:SliderListener:
69  virtual void SliderValueChanged(views::Slider* sender,
70                                  float value,
71                                  float old_value,
72                                  views::SliderChangeReason reason) OVERRIDE;
73
74  // views:SliderListener:
75  virtual void SliderDragStarted(views::Slider* slider) OVERRIDE;
76  virtual void SliderDragEnded(views::Slider* slider) OVERRIDE;
77
78  views::Slider* slider_;
79
80  // Is |slider_| currently being dragged?
81  bool dragging_;
82
83  // True if this view is for the default tray view. Used to control hide/show
84  // behaviour of the default view when entering or leaving Maximize Mode.
85  bool is_default_view_;
86
87  // Last brightness level that we observed, in the range [0.0, 100.0].
88  double last_percent_;
89
90  DISALLOW_COPY_AND_ASSIGN(BrightnessView);
91};
92
93BrightnessView::BrightnessView(bool default_view, double initial_percent)
94    : dragging_(false),
95      is_default_view_(default_view),
96      last_percent_(initial_percent) {
97  SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal,
98      kTrayPopupPaddingHorizontal, 0, kTrayPopupPaddingBetweenItems));
99
100  views::ImageView* icon = new FixedSizedImageView(0, kTrayPopupItemHeight);
101  gfx::Image image = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
102      IDR_AURA_UBER_TRAY_BRIGHTNESS);
103  icon->SetImage(image.ToImageSkia());
104  AddChildView(icon);
105
106  slider_ = new views::Slider(this, views::Slider::HORIZONTAL);
107  slider_->set_focus_border_color(kFocusBorderColor);
108  slider_->SetValue(static_cast<float>(initial_percent / 100.0));
109  slider_->SetAccessibleName(
110      ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
111          IDS_ASH_STATUS_TRAY_BRIGHTNESS));
112  AddChildView(slider_);
113
114  if (is_default_view_) {
115    Shell::GetInstance()->AddShellObserver(this);
116    SetVisible(Shell::GetInstance()->IsMaximizeModeWindowManagerEnabled());
117  }
118}
119
120BrightnessView::~BrightnessView() {
121  if (is_default_view_)
122    Shell::GetInstance()->RemoveShellObserver(this);
123}
124
125void BrightnessView::SetBrightnessPercent(double percent) {
126  last_percent_ = percent;
127  if (!dragging_)
128    slider_->SetValue(static_cast<float>(percent / 100.0));
129}
130
131void BrightnessView::OnMaximizeModeStarted() {
132  SetVisible(true);
133}
134
135void BrightnessView::OnMaximizeModeEnded() {
136  SetVisible(false);
137}
138
139void BrightnessView::OnBoundsChanged(const gfx::Rect& old_bounds) {
140  int w = width() - slider_->x();
141  slider_->SetSize(gfx::Size(w, slider_->height()));
142}
143
144void BrightnessView::SliderValueChanged(views::Slider* sender,
145                                float value,
146                                float old_value,
147                                views::SliderChangeReason reason) {
148  DCHECK_EQ(sender, slider_);
149  if (reason != views::VALUE_CHANGED_BY_USER)
150    return;
151  AcceleratorController* ac = Shell::GetInstance()->accelerator_controller();
152  if (ac->brightness_control_delegate()) {
153    double percent = std::max(value * 100.0, kMinBrightnessPercent);
154    ac->brightness_control_delegate()->SetBrightnessPercent(percent, true);
155  }
156}
157
158void BrightnessView::SliderDragStarted(views::Slider* slider) {
159  DCHECK_EQ(slider, slider_);
160  dragging_ = true;
161}
162
163void BrightnessView::SliderDragEnded(views::Slider* slider) {
164  DCHECK_EQ(slider, slider_);
165  dragging_ = false;
166  slider_->SetValue(static_cast<float>(last_percent_ / 100.0));
167}
168
169}  // namespace tray
170
171TrayBrightness::TrayBrightness(SystemTray* system_tray)
172    : SystemTrayItem(system_tray),
173      weak_ptr_factory_(this),
174      brightness_view_(NULL),
175      current_percent_(100.0),
176      got_current_percent_(false) {
177  // Post a task to get the initial brightness; the BrightnessControlDelegate
178  // isn't created yet.
179  base::MessageLoopForUI::current()->PostTask(
180      FROM_HERE,
181      base::Bind(&TrayBrightness::GetInitialBrightness,
182                 weak_ptr_factory_.GetWeakPtr()));
183  chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
184      AddObserver(this);
185}
186
187TrayBrightness::~TrayBrightness() {
188  chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
189      RemoveObserver(this);
190}
191
192void TrayBrightness::GetInitialBrightness() {
193  BrightnessControlDelegate* delegate =
194      Shell::GetInstance()->accelerator_controller()->
195      brightness_control_delegate();
196  // Worrisome, but happens in unit tests, so don't log anything.
197  if (!delegate)
198    return;
199  delegate->GetBrightnessPercent(
200      base::Bind(&TrayBrightness::HandleInitialBrightness,
201                 weak_ptr_factory_.GetWeakPtr()));
202}
203
204void TrayBrightness::HandleInitialBrightness(double percent) {
205  if (!got_current_percent_)
206    HandleBrightnessChanged(percent, false);
207}
208
209views::View* TrayBrightness::CreateTrayView(user::LoginStatus status) {
210  return NULL;
211}
212
213views::View* TrayBrightness::CreateDefaultView(user::LoginStatus status) {
214  CHECK(brightness_view_ == NULL);
215  brightness_view_ = new tray::BrightnessView(true, current_percent_);
216  return brightness_view_;
217}
218
219views::View* TrayBrightness::CreateDetailedView(user::LoginStatus status) {
220  CHECK(brightness_view_ == NULL);
221  Shell::GetInstance()->metrics()->RecordUserMetricsAction(
222      ash::UMA_STATUS_AREA_DETAILED_BRIGHTNESS_VIEW);
223  brightness_view_ = new tray::BrightnessView(false, current_percent_);
224  return brightness_view_;
225}
226
227void TrayBrightness::DestroyTrayView() {
228}
229
230void TrayBrightness::DestroyDefaultView() {
231  if (brightness_view_ && brightness_view_->is_default_view())
232    brightness_view_ = NULL;
233}
234
235void TrayBrightness::DestroyDetailedView() {
236  if (brightness_view_ && !brightness_view_->is_default_view())
237    brightness_view_ = NULL;
238}
239
240void TrayBrightness::UpdateAfterLoginStatusChange(user::LoginStatus status) {
241}
242
243bool TrayBrightness::ShouldHideArrow() const {
244  return true;
245}
246
247bool TrayBrightness::ShouldShowShelf() const {
248  return false;
249}
250
251void TrayBrightness::BrightnessChanged(int level, bool user_initiated) {
252  Shell::GetInstance()->metrics()->RecordUserMetricsAction(
253      ash::UMA_STATUS_AREA_BRIGHTNESS_CHANGED);
254  double percent = static_cast<double>(level);
255  HandleBrightnessChanged(percent, user_initiated);
256}
257
258void TrayBrightness::HandleBrightnessChanged(double percent,
259                                             bool user_initiated) {
260  current_percent_ = percent;
261  got_current_percent_ = true;
262
263  if (brightness_view_)
264    brightness_view_->SetBrightnessPercent(percent);
265
266  if (!user_initiated)
267    return;
268
269  // Never show the bubble on systems that lack internal displays: if an
270  // external display's brightness is changed, it may already display the new
271  // level via an on-screen display.
272  if (!Shell::GetInstance()->display_manager()->HasInternalDisplay())
273    return;
274
275  if (brightness_view_)
276    SetDetailedViewCloseDelay(kTrayPopupAutoCloseDelayInSeconds);
277  else
278    PopupDetailedView(kTrayPopupAutoCloseDelayInSeconds, false);
279}
280
281}  // namespace ash
282