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 <algorithm> 8 9 #include "ash/accelerators/accelerator_controller.h" 10 #include "ash/ash_constants.h" 11 #include "ash/display/display_manager.h" 12 #include "ash/metrics/user_metrics_recorder.h" 13 #include "ash/shell.h" 14 #include "ash/shell_observer.h" 15 #include "ash/system/brightness_control_delegate.h" 16 #include "ash/system/tray/fixed_sized_image_view.h" 17 #include "ash/system/tray/system_tray_delegate.h" 18 #include "ash/system/tray/system_tray_notifier.h" 19 #include "ash/system/tray/tray_constants.h" 20 #include "ash/wm/maximize_mode/maximize_mode_controller.h" 21 #include "base/bind.h" 22 #include "base/message_loop/message_loop.h" 23 #include "base/strings/utf_string_conversions.h" 24 #include "chromeos/dbus/dbus_thread_manager.h" 25 #include "chromeos/dbus/power_manager_client.h" 26 #include "grit/ash_resources.h" 27 #include "grit/ash_strings.h" 28 #include "ui/base/resource/resource_bundle.h" 29 #include "ui/gfx/image/image.h" 30 #include "ui/views/controls/button/image_button.h" 31 #include "ui/views/controls/image_view.h" 32 #include "ui/views/controls/label.h" 33 #include "ui/views/controls/slider.h" 34 #include "ui/views/layout/box_layout.h" 35 #include "ui/views/view.h" 36 37 namespace ash { 38 namespace tray { 39 namespace { 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. 45 const double kMinBrightnessPercent = 5.0; 46 47 } // namespace 48 49 class 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 96 BrightnessView::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()->maximize_mode_controller()-> 120 IsMaximizeModeWindowManagerEnabled()); 121 } 122 } 123 124 BrightnessView::~BrightnessView() { 125 if (is_default_view_) 126 Shell::GetInstance()->RemoveShellObserver(this); 127 } 128 129 void BrightnessView::SetBrightnessPercent(double percent) { 130 last_percent_ = percent; 131 if (!dragging_) 132 slider_->SetValue(static_cast<float>(percent / 100.0)); 133 } 134 135 void BrightnessView::OnMaximizeModeStarted() { 136 SetVisible(true); 137 } 138 139 void BrightnessView::OnMaximizeModeEnded() { 140 SetVisible(false); 141 } 142 143 void BrightnessView::OnBoundsChanged(const gfx::Rect& old_bounds) { 144 int w = width() - slider_->x(); 145 slider_->SetSize(gfx::Size(w, slider_->height())); 146 } 147 148 void BrightnessView::SliderValueChanged(views::Slider* sender, 149 float value, 150 float old_value, 151 views::SliderChangeReason reason) { 152 DCHECK_EQ(sender, slider_); 153 if (reason != views::VALUE_CHANGED_BY_USER) 154 return; 155 AcceleratorController* ac = Shell::GetInstance()->accelerator_controller(); 156 if (ac->brightness_control_delegate()) { 157 double percent = std::max(value * 100.0, kMinBrightnessPercent); 158 ac->brightness_control_delegate()->SetBrightnessPercent(percent, true); 159 } 160 } 161 162 void BrightnessView::SliderDragStarted(views::Slider* slider) { 163 DCHECK_EQ(slider, slider_); 164 dragging_ = true; 165 } 166 167 void BrightnessView::SliderDragEnded(views::Slider* slider) { 168 DCHECK_EQ(slider, slider_); 169 dragging_ = false; 170 slider_->SetValue(static_cast<float>(last_percent_ / 100.0)); 171 } 172 173 } // namespace tray 174 175 TrayBrightness::TrayBrightness(SystemTray* system_tray) 176 : SystemTrayItem(system_tray), 177 brightness_view_(NULL), 178 current_percent_(100.0), 179 got_current_percent_(false), 180 weak_ptr_factory_(this) { 181 // Post a task to get the initial brightness; the BrightnessControlDelegate 182 // isn't created yet. 183 base::MessageLoopForUI::current()->PostTask( 184 FROM_HERE, 185 base::Bind(&TrayBrightness::GetInitialBrightness, 186 weak_ptr_factory_.GetWeakPtr())); 187 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> 188 AddObserver(this); 189 } 190 191 TrayBrightness::~TrayBrightness() { 192 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> 193 RemoveObserver(this); 194 } 195 196 void TrayBrightness::GetInitialBrightness() { 197 BrightnessControlDelegate* delegate = 198 Shell::GetInstance()->accelerator_controller()-> 199 brightness_control_delegate(); 200 // Worrisome, but happens in unit tests, so don't log anything. 201 if (!delegate) 202 return; 203 delegate->GetBrightnessPercent( 204 base::Bind(&TrayBrightness::HandleInitialBrightness, 205 weak_ptr_factory_.GetWeakPtr())); 206 } 207 208 void TrayBrightness::HandleInitialBrightness(double percent) { 209 if (!got_current_percent_) 210 HandleBrightnessChanged(percent, false); 211 } 212 213 views::View* TrayBrightness::CreateTrayView(user::LoginStatus status) { 214 return NULL; 215 } 216 217 views::View* TrayBrightness::CreateDefaultView(user::LoginStatus status) { 218 CHECK(brightness_view_ == NULL); 219 brightness_view_ = new tray::BrightnessView(true, current_percent_); 220 return brightness_view_; 221 } 222 223 views::View* TrayBrightness::CreateDetailedView(user::LoginStatus status) { 224 CHECK(brightness_view_ == NULL); 225 Shell::GetInstance()->metrics()->RecordUserMetricsAction( 226 ash::UMA_STATUS_AREA_DETAILED_BRIGHTNESS_VIEW); 227 brightness_view_ = new tray::BrightnessView(false, current_percent_); 228 return brightness_view_; 229 } 230 231 void TrayBrightness::DestroyTrayView() { 232 } 233 234 void TrayBrightness::DestroyDefaultView() { 235 if (brightness_view_ && brightness_view_->is_default_view()) 236 brightness_view_ = NULL; 237 } 238 239 void TrayBrightness::DestroyDetailedView() { 240 if (brightness_view_ && !brightness_view_->is_default_view()) 241 brightness_view_ = NULL; 242 } 243 244 void TrayBrightness::UpdateAfterLoginStatusChange(user::LoginStatus status) { 245 } 246 247 bool TrayBrightness::ShouldHideArrow() const { 248 return true; 249 } 250 251 bool TrayBrightness::ShouldShowShelf() const { 252 return false; 253 } 254 255 void TrayBrightness::BrightnessChanged(int level, bool user_initiated) { 256 Shell::GetInstance()->metrics()->RecordUserMetricsAction( 257 ash::UMA_STATUS_AREA_BRIGHTNESS_CHANGED); 258 double percent = static_cast<double>(level); 259 HandleBrightnessChanged(percent, user_initiated); 260 } 261 262 void TrayBrightness::HandleBrightnessChanged(double percent, 263 bool user_initiated) { 264 current_percent_ = percent; 265 got_current_percent_ = true; 266 267 if (brightness_view_) 268 brightness_view_->SetBrightnessPercent(percent); 269 270 if (!user_initiated) 271 return; 272 273 // Never show the bubble on systems that lack internal displays: if an 274 // external display's brightness is changed, it may already display the new 275 // level via an on-screen display. 276 if (!Shell::GetInstance()->display_manager()->HasInternalDisplay()) 277 return; 278 279 if (brightness_view_) 280 SetDetailedViewCloseDelay(kTrayPopupAutoCloseDelayInSeconds); 281 else 282 PopupDetailedView(kTrayPopupAutoCloseDelayInSeconds, false); 283 } 284 285 } // namespace ash 286