chromium/ash/system/power/tray_power.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/system/power/tray_power.h"

#include <utility>

#include "ash/accessibility/accessibility_delegate.h"
#include "ash/constants/ash_features.h"
#include "ash/public/cpp/shelf_config.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_id.h"
#include "ash/system/power/battery_notification.h"
#include "ash/system/power/dual_role_notification.h"
#include "ash/system/power/power_status.h"
#include "ash/system/time/time_view.h"
#include "ash/system/tray/tray_constants.h"
#include "ash/system/tray/tray_item_view.h"
#include "ash/system/tray/tray_utils.h"
#include "base/command_line.h"
#include "base/metrics/histogram.h"
#include "base/time/time.h"
#include "chromeos/constants/chromeos_features.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/chromeos/devicetype_utils.h"
#include "ui/chromeos/styles/cros_styles.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/image/image_skia_source.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/public/cpp/notification.h"
#include "ui/message_center/public/cpp/notification_delegate.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/border.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/view.h"

using message_center::MessageCenter;
using message_center::Notification;

namespace ash {

PowerTrayView::PowerTrayView(Shelf* shelf) : TrayItemView(shelf) {
  CreateImageView();

  previous_battery_saver_state_ = PowerStatus::Get()->IsBatterySaverActive();
  PowerStatus::Get()->AddObserver(this);

  GetViewAccessibility().SetRole(ax::mojom::Role::kImage);
}

PowerTrayView::~PowerTrayView() {
  PowerStatus::Get()->RemoveObserver(this);
}

gfx::Size PowerTrayView::CalculatePreferredSize(
    const views::SizeBounds& available_size) const {
  // The battery icon is a lot thinner than other icons, hence the special
  // logic.
  gfx::Size standard_size =
      TrayItemView::CalculatePreferredSize(available_size);
  if (IsHorizontalAlignment())
    return gfx::Size(kUnifiedTrayBatteryWidth, standard_size.height());

  // Ensure battery isn't too tall in side shelf.
  return gfx::Size(standard_size.width(), kUnifiedTrayIconSize);
}

void PowerTrayView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
  std::u16string accessible_name =
      PowerStatus::Get()->GetAccessibleNameString(/* full_description*/ true);
  if (!accessible_name.empty()) {
    node_data->SetNameChecked(accessible_name);
  }
}

views::View* PowerTrayView::GetTooltipHandlerForPoint(const gfx::Point& point) {
  return GetLocalBounds().Contains(point) ? this : nullptr;
}

std::u16string PowerTrayView::GetTooltipText(const gfx::Point& p) const {
  return tooltip_;
}

void PowerTrayView::OnThemeChanged() {
  TrayItemView::OnThemeChanged();
  UpdateStatus(false);
  UpdateImage(/*icon_color_changed=*/true);
}

void PowerTrayView::HandleLocaleChange() {
  UpdateStatus(false);
}

void PowerTrayView::UpdateLabelOrImageViewColor(bool active) {
  TrayItemView::UpdateLabelOrImageViewColor(active);

  cros_tokens::CrosSysColorIds icon_fg_token = cros_tokens::kCrosSysOnSurface;
  if (active) {
    icon_fg_token = cros_tokens::kCrosSysSystemOnPrimaryContainer;
  } else if (features::IsBatterySaverAvailable() &&
             PowerStatus::Get()->IsBatterySaverActive()) {
    icon_fg_token = cros_tokens::kCrosSysOnWarningContainer;
  }
  const SkColor icon_fg_color = GetColorProvider()->GetColor(icon_fg_token);

  PowerStatus::BatteryImageInfo info =
      PowerStatus::Get()->GenerateBatteryImageInfo(icon_fg_color);

  image_view()->SetImage(PowerStatus::GetBatteryImage(
      info, kUnifiedTrayBatteryIconSize, GetColorProvider()));
}

void PowerTrayView::OnPowerStatusChanged() {
  const bool bsm_active = PowerStatus::Get()->IsBatterySaverActive();
  UpdateStatus(bsm_active != previous_battery_saver_state_);
  previous_battery_saver_state_ = bsm_active;
}

void PowerTrayView::UpdateStatus(bool icon_color_changed) {
  UpdateImage(icon_color_changed);
  SetVisible(PowerStatus::Get()->IsBatteryPresent());
  GetViewAccessibility().SetName(
      PowerStatus::Get()->GetAccessibleNameString(/* full_description */ true));
  tooltip_ = PowerStatus::Get()->GetInlinedStatusString();
  // Currently ChromeVox only reads the inner view when touching the icon.
  // As a result this node's accessible node data will not be read.
  // TODO(crbug.com/325137417): This line should not be needed. Investigate to
  // confirm and remove.
  image_view()->GetViewAccessibility().SetName(
      GetViewAccessibility().GetCachedName());
}

void PowerTrayView::UpdateImage(bool icon_color_changed) {
  SkColor prev_foreground_color = SK_ColorWHITE,
          prev_badge_color = SK_ColorWHITE;
  if (info_) {
    prev_foreground_color = info_->battery_color_preferences.foreground_color;
    prev_badge_color =
        info_->battery_color_preferences.badge_color.value_or(SK_ColorWHITE);
  }

  PowerStatus::BatteryImageInfo info =
      PowerStatus::Get()->GenerateBatteryImageInfo(prev_foreground_color,
                                                   prev_badge_color);

  // Only change the image when the info changes or the icon color has
  // changed. http://crbug.com/589348
  if (info_ && info_->ApproximatelyEqual(info) && !icon_color_changed)
    return;
  info_ = info;

  UpdateLabelOrImageViewColor(is_active());
}

BEGIN_METADATA(PowerTrayView)
END_METADATA

}  // namespace ash