1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283
  284
  285
  286
  287
  288
  289
  290
  291
  292
  293
  294
  295
  296
  297
  298
  299
  300
  301
  302
  303
  304
  305
  306
  307
  308
  309
  310
  311
  312
  313
  314
  315
  316
  317
  318
  319

ash / system / power / power_status.h [blame]

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

#ifndef ASH_SYSTEM_POWER_POWER_STATUS_H_
#define ASH_SYSTEM_POWER_POWER_STATUS_H_

#include <optional>
#include <string>
#include <vector>

#include "ash/ash_export.h"
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "chromeos/dbus/power/power_manager_client.h"
#include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/models/image_model.h"
#include "ui/gfx/image/image_skia.h"

namespace gfx {
struct VectorIcon;
}

namespace ui {
class ColorProvider;
}

namespace ash {

struct BatteryColorTemplate {
  bool operator==(const BatteryColorTemplate& other) const {
    bool foreground_colors_match = foreground_color == other.foreground_color;
    bool badge_colors_match = badge_color == other.badge_color;

    return foreground_colors_match && badge_colors_match;
  }

  bool operator!=(const BatteryColorTemplate& other) const {
    return !(*this == other);
  }

  SkColor foreground_color;
  std::optional<SkColor> badge_color;
};

struct BatteryColors {
  SkColor foreground_color;
  SkColor badge_color;
  SkColor alert_color;
};

// PowerStatus is a singleton that receives updates about the system's
// power status from chromeos::PowerManagerClient and makes the information
// available to interested classes within Ash.
class ASH_EXPORT PowerStatus : public chromeos::PowerManagerClient::Observer {
 public:
  // Interface for classes that wish to be notified when the power status
  // has changed.
  class Observer {
   public:
    // Called when the power status changes.
    virtual void OnPowerStatusChanged() = 0;

   protected:
    virtual ~Observer() {}
  };

  // Power source types.
  enum DeviceType {
    // Dedicated charger (AC adapter, USB power supply, etc.).
    DEDICATED_CHARGER,

    // Dual-role device.
    DUAL_ROLE_USB,
  };

  // Information about an available power source.
  struct PowerSource {
    // ID provided by kernel.
    std::string id;

    // Type of power source.
    DeviceType type;

    // Message ID of a description for this port.
    int description_id;
  };

  // Information about the battery image corresponding to the status at a given
  // point in time. This can be cached and later compared to avoid unnecessarily
  // updating onscreen icons (GetBatteryImage() creates a new image on each
  // call).
  struct BatteryImageInfo {
    explicit BatteryImageInfo(
        const SkColor fg_color,
        const std::optional<SkColor> badge_color = std::nullopt)
        : icon_badge(nullptr),
          badge_outline(nullptr),
          alert_if_low(false),
          charge_percent(-1),
          battery_color_preferences({fg_color, badge_color}) {}

    static BatteryColors ResolveColors(const BatteryImageInfo& info,
                                       const ui::ColorProvider* color_provider);
    // Returns true if |this| and |o| are similar enough in terms of the image
    // they'd generate.
    bool ApproximatelyEqual(const BatteryImageInfo& o) const;

    // The badge (lightning bolt, exclamation mark, etc) that should be drawn
    // on top of the battery icon.
    raw_ptr<const gfx::VectorIcon> icon_badge;

    // The outline for the badge, need to draw this to satisfy contrast
    // requirements.
    raw_ptr<const gfx::VectorIcon> badge_outline;

    // When true and |charge_percent| is very low, special colors will be used
    // to alert the user.
    bool alert_if_low;

    double charge_percent;

    BatteryColorTemplate battery_color_preferences;
  };

  // Maximum battery time-to-full or time-to-empty that should be displayed
  // in the UI. If the current is close to zero, battery time estimates can
  // get very large; avoid displaying these large numbers.
  static const int kMaxBatteryTimeToDisplaySec;

  // An alert_if_low badge is drawn over the battery icon if the battery is not
  // connected to a charger and has less than |kCriticalBatteryChargePercentage|
  // percentage of charge remaining.
  static const double kCriticalBatteryChargePercentage;

  PowerStatus(const PowerStatus&) = delete;
  PowerStatus& operator=(const PowerStatus&) = delete;

  // Sets the global instance. Must be called before any calls to Get().
  static void Initialize();

  // Destroys the global instance.
  static void Shutdown();

  // Returns true if the global instance is initialized.
  static bool IsInitialized();

  // Gets the global instance. Initialize must be called first.
  static PowerStatus* Get();

  power_manager::PowerSupplyProperties_ExternalPower external_power() const {
    return proto_.external_power();
  }

  // Adds or removes an observer.
  void AddObserver(Observer* observer);
  void RemoveObserver(Observer* observer);

  // Requests updated status from the power manager.
  void RequestStatusUpdate();

  // Returns true if a battery is present.
  virtual bool IsBatteryPresent() const;

  // Returns true if the battery is full. This also implies that a charger
  // is connected.
  bool IsBatteryFull() const;

  // Returns true if the battery is charging. Note that this implies that a
  // charger is connected but the converse is not necessarily true: the
  // battery may be discharging even while a (perhaps low-power) charger is
  // connected. Use Is*Connected() to test for the presence of a charger
  // and also see IsBatteryDischargingOnLinePower().
  bool IsBatteryCharging() const;

  // Returns true if the battery is discharging (or neither charging nor
  // discharging while not being full) while line power is connected.
  bool IsBatteryDischargingOnLinePower() const;

  // Returns the battery's remaining charge as a value in the range [0.0,
  // 100.0].
  virtual double GetBatteryPercent() const;

  // Returns the battery's remaining charge, rounded to an integer with a
  // maximum value of 100.
  int GetRoundedBatteryPercent() const;

  // Returns true if the battery's time-to-full and time-to-empty estimates
  // should not be displayed because the power manager is still calculating
  // them.
  bool IsBatteryTimeBeingCalculated() const;

  // Returns the estimated time until the battery is empty (if line power
  // is disconnected) or full (if line power is connected). These estimates
  // should only be used if IsBatteryTimeBeingCalculated() returns false.
  //
  // Irrespective of IsBatteryTimeBeingCalculated(), estimates may be
  // unavailable if powerd didn't provide them because the battery current was
  // close to zero (resulting in time estimates approaching infinity).
  std::optional<base::TimeDelta> GetBatteryTimeToEmpty() const;
  std::optional<base::TimeDelta> GetBatteryTimeToFull() const;

  // Returns true if line power (including a charger of any type) is connected.
  virtual bool IsLinePowerConnected() const;

  // Returns true if an official, non-USB charger is connected.
  bool IsMainsChargerConnected() const;

  // Returns true if a USB charger (which is likely to only support a low
  // charging rate) is connected.
  virtual bool IsUsbChargerConnected() const;

  // Returns true if the system allows some connected devices to function as
  // either power sources or sinks.
  bool SupportsDualRoleDevices() const;

  // Returns true if at least one dual-role device is connected.
  bool HasDualRoleDevices() const;

  // Returns a list of available power sources which the user may select.
  std::vector<PowerSource> GetPowerSources() const;

  // Returns the ID of the currently used power source, or an empty string if no
  // power source is selected.
  std::string GetCurrentPowerSourceID() const;

  // Creates a new BatteryImageInfo struct, and populates the struct with
  // information related to the current Battery Status (i.e. the colors
  // used to draw the battery icon, the charge percent of the battery, etc).
  BatteryImageInfo GenerateBatteryImageInfo(
      const SkColor foreground_color,
      const std::optional<SkColor> badge_color = std::nullopt) const;

  // Creates a new image that should be shown for the battery's current state.
  static ui::ImageModel GetBatteryImageModel(const BatteryImageInfo& info,
                                             int height);

  // DEPRECATED: Use `GetBatteryImageModel()` instead.
  // Creates a new image that should be shown for the battery's current state.
  static gfx::ImageSkia GetBatteryImage(
      const BatteryImageInfo& info,
      int height,
      const ui::ColorProvider* color_provider);

  // Returns a string describing the current state for accessibility.
  std::u16string GetAccessibleNameString(bool full_description) const;

  // Returns status strings that are generated by current PowerStatus.
  // The first string is percentage e.g. "53%" and the second one is status in
  // words e.g. "5:00 left". Depending on the status, one of them may return
  // empty string.
  std::pair<std::u16string, std::u16string> GetStatusStrings() const;

  // Returns status strings that are generated by current PowerStatus.
  // For example, "53% - 5:00 left".
  std::u16string GetInlinedStatusString() const;

  // Returns the device's preferred minimum power input in watts (W).
  double GetPreferredMinimumPower() const;

  // Returns true if battery saver is active.
  virtual bool IsBatterySaverActive() const;

  // TODO(b/327054689): This pointer is needed because some power tests delete
  // PowerStatus without the observers knowing about it, so observers have to
  // check for its validity before using it.
  base::WeakPtr<PowerStatus> GetWeakPtr();

  // Updates |proto_|. Does not notify observers.
  void SetProtoForTesting(const power_manager::PowerSupplyProperties& proto);

  // Updates |battery_saver_active_|. Does not notify observers.
  void SetBatterySaverStateForTesting(bool active);

 protected:
  PowerStatus();
  ~PowerStatus() override;

 private:
  friend class ScopedFakePowerStatus;
  friend class FakePowerStatus;

  // Global singleton instance of the PowerStatus
  static PowerStatus* g_power_status_;

  // Overridden from PowerManagerClient::Observer.
  void PowerChanged(const power_manager::PowerSupplyProperties& proto) override;
  void BatterySaverModeStateChanged(
      const power_manager::BatterySaverModeState& state) override;

  // A helper function called by GetBatteryImageInfo(). Populates the fields of
  // |info|.
  void CalculateBatteryImageInfo(BatteryImageInfo* info) const;

  // Callback used to query battery saver state from PowerManagerClient on
  // startup.
  void OnGotBatterySaverState(
      std::optional<power_manager::BatterySaverModeState> state);

  base::ObserverList<Observer>::Unchecked observers_;

  // Current state.
  power_manager::PowerSupplyProperties proto_;

  // Has proto_ been set with a value from Power Manager yet?
  bool proto_initialized_{false};

  // Current state of battery saver, queried on startup and updated in
  // BatterySaverModeStateChanged.
  bool battery_saver_active_{false};

  base::WeakPtrFactory<PowerStatus> weak_ptr_factory_{this};
};

}  // namespace ash

#endif  // ASH_SYSTEM_POWER_POWER_STATUS_H_