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