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