blob: f30c77adedce6876b717eb9090a2b7f1a1e2e649 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/system/brightness/tray_brightness.h"
#include <algorithm>
#include "ash/metrics/user_metrics_recorder.h"
#include "ash/public/cpp/ash_features.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/brightness_control_delegate.h"
#include "ash/system/tray/system_tray.h"
#include "ash/system/tray/tray_constants.h"
#include "ash/system/tray/tray_popup_utils.h"
#include "ash/system/tray/tri_view.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "ash/wm/tablet_mode/tablet_mode_observer.h"
#include "base/bind.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/power_manager/backlight.pb.h"
#include "chromeos/dbus/power_manager_client.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/display/display.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/slider.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/view.h"
namespace ash {
namespace tray {
class BrightnessView : public TabletModeObserver,
public views::View,
public views::SliderListener {
public:
BrightnessView(bool default_view, double initial_percent);
~BrightnessView() override;
bool is_default_view() const { return is_default_view_; }
// |percent| is in the range [0.0, 100.0].
void SetBrightnessPercent(double percent);
// TabletModeObserver:
void OnTabletModeStarted() override;
void OnTabletModeEnded() override;
private:
// views::View:
void OnBoundsChanged(const gfx::Rect& old_bounds) override;
// views:SliderListener:
void SliderValueChanged(views::Slider* sender,
float value,
float old_value,
views::SliderChangeReason reason) override;
// views:SliderListener:
void SliderDragStarted(views::Slider* slider) override;
void SliderDragEnded(views::Slider* slider) override;
views::Slider* slider_;
// Is |slider_| currently being dragged?
bool dragging_;
// True if this view is for the default tray view. Used to control hide/show
// behaviour of the default view when entering or leaving Maximize Mode.
bool is_default_view_;
// Last brightness level that we observed, in the range [0.0, 100.0].
double last_percent_;
DISALLOW_COPY_AND_ASSIGN(BrightnessView);
};
BrightnessView::BrightnessView(bool default_view, double initial_percent)
: dragging_(false),
is_default_view_(default_view),
last_percent_(initial_percent) {
SetLayoutManager(std::make_unique<views::FillLayout>());
// Use CreateMultiTargetRowView() instead of CreateDefaultRowView() because
// that's what the audio row uses and we want the two rows to layout with the
// same insets.
TriView* tri_view = TrayPopupUtils::CreateMultiTargetRowView();
AddChildView(tri_view);
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
views::ImageView* icon = TrayPopupUtils::CreateMainImageView();
icon->SetImage(
gfx::CreateVectorIcon(kSystemMenuBrightnessIcon, kMenuIconColor));
tri_view->AddView(TriView::Container::START, icon);
slider_ = TrayPopupUtils::CreateSlider(this);
slider_->SetValue(static_cast<float>(initial_percent / 100.0));
slider_->GetViewAccessibility().OverrideName(
rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_BRIGHTNESS));
tri_view->AddView(TriView::Container::CENTER, slider_);
if (is_default_view_) {
Shell::Get()->tablet_mode_controller()->AddObserver(this);
SetVisible(Shell::Get()
->tablet_mode_controller()
->IsTabletModeWindowManagerEnabled());
}
tri_view->SetContainerVisible(TriView::Container::END, false);
}
BrightnessView::~BrightnessView() {
if (is_default_view_ && Shell::Get()->tablet_mode_controller())
Shell::Get()->tablet_mode_controller()->RemoveObserver(this);
}
void BrightnessView::SetBrightnessPercent(double percent) {
last_percent_ = percent;
if (!dragging_)
slider_->SetValue(static_cast<float>(percent / 100.0));
}
void BrightnessView::OnTabletModeStarted() {
SetVisible(true);
}
void BrightnessView::OnTabletModeEnded() {
SetVisible(false);
}
void BrightnessView::OnBoundsChanged(const gfx::Rect& old_bounds) {
int w = width() - slider_->x();
slider_->SetSize(gfx::Size(w, slider_->height()));
}
void BrightnessView::SliderValueChanged(views::Slider* sender,
float value,
float old_value,
views::SliderChangeReason reason) {
DCHECK_EQ(sender, slider_);
if (reason != views::VALUE_CHANGED_BY_USER)
return;
BrightnessControlDelegate* brightness_control_delegate =
Shell::Get()->brightness_control_delegate();
if (brightness_control_delegate) {
double percent = std::max(value * 100.0, kMinBrightnessPercent);
brightness_control_delegate->SetBrightnessPercent(percent, true);
}
}
void BrightnessView::SliderDragStarted(views::Slider* slider) {
DCHECK_EQ(slider, slider_);
dragging_ = true;
}
void BrightnessView::SliderDragEnded(views::Slider* slider) {
DCHECK_EQ(slider, slider_);
dragging_ = false;
slider_->SetValue(static_cast<float>(last_percent_ / 100.0));
}
} // namespace tray
TrayBrightness::TrayBrightness(SystemTray* system_tray)
: SystemTrayItem(system_tray,
SystemTrayItemUmaType::UMA_DISPLAY_BRIGHTNESS),
brightness_view_(nullptr),
current_percent_(100.0),
got_current_percent_(false),
weak_ptr_factory_(this) {
// Post a task to get the initial brightness; the BrightnessControlDelegate
// isn't created yet.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&TrayBrightness::GetInitialBrightness,
weak_ptr_factory_.GetWeakPtr()));
chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(
this);
}
TrayBrightness::~TrayBrightness() {
chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(
this);
}
void TrayBrightness::GetInitialBrightness() {
BrightnessControlDelegate* brightness_control_delegate =
Shell::Get()->brightness_control_delegate();
// Worrisome, but happens in unit tests, so don't log anything.
if (!brightness_control_delegate)
return;
brightness_control_delegate->GetBrightnessPercent(
base::BindOnce(&TrayBrightness::HandleInitialBrightness,
weak_ptr_factory_.GetWeakPtr()));
}
void TrayBrightness::HandleInitialBrightness(base::Optional<double> percent) {
if (!got_current_percent_ && percent.has_value())
HandleBrightnessChanged(percent.value(), false);
}
views::View* TrayBrightness::CreateDefaultView(LoginStatus status) {
CHECK(brightness_view_ == nullptr);
brightness_view_ = new tray::BrightnessView(true, current_percent_);
return brightness_view_;
}
views::View* TrayBrightness::CreateDetailedView(LoginStatus status) {
CHECK(brightness_view_ == nullptr);
Shell::Get()->metrics()->RecordUserMetricsAction(
UMA_STATUS_AREA_DETAILED_BRIGHTNESS_VIEW);
brightness_view_ = new tray::BrightnessView(false, current_percent_);
return brightness_view_;
}
void TrayBrightness::OnDefaultViewDestroyed() {
if (brightness_view_ && brightness_view_->is_default_view())
brightness_view_ = nullptr;
}
void TrayBrightness::OnDetailedViewDestroyed() {
if (brightness_view_ && !brightness_view_->is_default_view())
brightness_view_ = nullptr;
}
void TrayBrightness::UpdateAfterLoginStatusChange(LoginStatus status) {}
bool TrayBrightness::ShouldShowShelf() const {
return false;
}
void TrayBrightness::ScreenBrightnessChanged(
const power_manager::BacklightBrightnessChange& change) {
Shell::Get()->metrics()->RecordUserMetricsAction(
UMA_STATUS_AREA_BRIGHTNESS_CHANGED);
const bool user_initiated =
change.cause() ==
power_manager::BacklightBrightnessChange_Cause_USER_REQUEST;
HandleBrightnessChanged(change.percent(), user_initiated);
}
void TrayBrightness::HandleBrightnessChanged(double percent,
bool user_initiated) {
if (features::IsSystemTrayUnifiedEnabled())
return;
current_percent_ = percent;
got_current_percent_ = true;
if (brightness_view_)
brightness_view_->SetBrightnessPercent(percent);
if (!user_initiated)
return;
// Never show the bubble on systems that lack internal displays: if an
// external display's brightness is changed, it may already display the new
// level via an on-screen display.
if (!display::Display::HasInternalDisplay())
return;
if (brightness_view_ && brightness_view_->visible())
SetDetailedViewCloseDelay(kTrayPopupAutoCloseDelayInSeconds);
else
ShowDetailedView(kTrayPopupAutoCloseDelayInSeconds);
}
} // namespace ash