tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

BatteryManager.cpp (6113B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "BatteryManager.h"
      8 
      9 #include <cmath>
     10 #include <limits>
     11 
     12 #include "Constants.h"
     13 #include "mozilla/DOMEventTargetHelper.h"
     14 #include "mozilla/Hal.h"
     15 #include "mozilla/Preferences.h"
     16 #include "mozilla/dom/BatteryManagerBinding.h"
     17 #include "mozilla/dom/Document.h"
     18 #include "nsContentUtils.h"
     19 #include "nsGlobalWindowInner.h"
     20 
     21 /**
     22 * We have to use macros here because our leak analysis tool things we are
     23 * leaking strings when we have |static const nsString|. Sad :(
     24 */
     25 #define LEVELCHANGE_EVENT_NAME u"levelchange"_ns
     26 #define CHARGINGCHANGE_EVENT_NAME u"chargingchange"_ns
     27 #define DISCHARGINGTIMECHANGE_EVENT_NAME u"dischargingtimechange"_ns
     28 #define CHARGINGTIMECHANGE_EVENT_NAME u"chargingtimechange"_ns
     29 
     30 namespace mozilla::dom::battery {
     31 
     32 BatteryManager::BatteryManager(nsPIDOMWindowInner* aWindow)
     33    : DOMEventTargetHelper(aWindow),
     34      mLevel(kDefaultLevel),
     35      mCharging(kDefaultCharging),
     36      mRemainingTime(kDefaultRemainingTime) {}
     37 
     38 void BatteryManager::Init() {
     39  hal::RegisterBatteryObserver(this);
     40 
     41  hal::BatteryInformation batteryInfo;
     42  hal::GetCurrentBatteryInformation(&batteryInfo);
     43 
     44  UpdateFromBatteryInfo(batteryInfo);
     45 }
     46 
     47 void BatteryManager::Shutdown() { hal::UnregisterBatteryObserver(this); }
     48 
     49 JSObject* BatteryManager::WrapObject(JSContext* aCx,
     50                                     JS::Handle<JSObject*> aGivenProto) {
     51  return BatteryManager_Binding::Wrap(aCx, this, aGivenProto);
     52 }
     53 
     54 bool BatteryManager::Charging() const {
     55  MOZ_ASSERT(NS_IsMainThread());
     56  // For testing, unable to report the battery status information
     57  if (Preferences::GetBool("dom.battery.test.default", false)) {
     58    return true;
     59  }
     60  if (Preferences::GetBool("dom.battery.test.charging", false)) {
     61    return true;
     62  }
     63  if (Preferences::GetBool("dom.battery.test.discharging", false)) {
     64    return false;
     65  }
     66 
     67  return mCharging;
     68 }
     69 
     70 double BatteryManager::DischargingTime() const {
     71  MOZ_ASSERT(NS_IsMainThread());
     72  // For testing, unable to report the battery status information
     73  if (Preferences::GetBool("dom.battery.test.default", false)) {
     74    return std::numeric_limits<double>::infinity();
     75  }
     76  if (Preferences::GetBool("dom.battery.test.discharging", false)) {
     77    return 42.0;
     78  }
     79 
     80  if (Charging() || mRemainingTime == kUnknownRemainingTime) {
     81    return std::numeric_limits<double>::infinity();
     82  }
     83 
     84  return mRemainingTime;
     85 }
     86 
     87 double BatteryManager::ChargingTime() const {
     88  MOZ_ASSERT(NS_IsMainThread());
     89  // For testing, unable to report the battery status information
     90  if (Preferences::GetBool("dom.battery.test.default", false)) {
     91    return 0.0;
     92  }
     93  if (Preferences::GetBool("dom.battery.test.charging", false)) {
     94    return 42.0;
     95  }
     96 
     97  if (!Charging() || mRemainingTime == kUnknownRemainingTime) {
     98    return std::numeric_limits<double>::infinity();
     99  }
    100 
    101  return mRemainingTime;
    102 }
    103 
    104 double BatteryManager::Level() const {
    105  MOZ_ASSERT(NS_IsMainThread());
    106  // For testing, unable to report the battery status information
    107  if (Preferences::GetBool("dom.battery.test.default")) {
    108    return 1.0;
    109  }
    110 
    111  return mLevel;
    112 }
    113 
    114 void BatteryManager::UpdateFromBatteryInfo(
    115    const hal::BatteryInformation& aBatteryInfo) {
    116  mLevel = aBatteryInfo.level();
    117 
    118  // Round to the nearest ten percent for non-chrome.
    119  Document* doc = GetOwnerWindow() ? GetOwnerWindow()->GetDoc() : nullptr;
    120 
    121  mCharging = aBatteryInfo.charging();
    122  mRemainingTime = aBatteryInfo.remainingTime();
    123 
    124  if (!nsContentUtils::IsChromeDoc(doc)) {
    125    mLevel = lround(mLevel * 10.0) / 10.0;
    126    if (mLevel == 1.0) {
    127      mRemainingTime =
    128          mCharging ? kDefaultRemainingTime : kUnknownRemainingTime;
    129    } else if (mRemainingTime != kUnknownRemainingTime) {
    130      // Round the remaining time to a multiple of 15 minutes and never zero
    131      const double MINUTES_15 = 15.0 * 60.0;
    132      mRemainingTime =
    133          fmax(lround(mRemainingTime / MINUTES_15) * MINUTES_15, MINUTES_15);
    134    }
    135  }
    136 
    137  // Add some guards to make sure the values are coherent.
    138  if (mLevel == 1.0 && mCharging == true &&
    139      mRemainingTime != kDefaultRemainingTime) {
    140    mRemainingTime = kDefaultRemainingTime;
    141    NS_ERROR(
    142        "Battery API: When charging and level at 1.0, remaining time "
    143        "should be 0. Please fix your backend!");
    144  }
    145 }
    146 
    147 void BatteryManager::Notify(const hal::BatteryInformation& aBatteryInfo) {
    148  double previousLevel = mLevel;
    149  bool previousCharging = mCharging;
    150  double previousRemainingTime = mRemainingTime;
    151 
    152  UpdateFromBatteryInfo(aBatteryInfo);
    153 
    154  if (previousCharging != mCharging) {
    155    DispatchTrustedEvent(CHARGINGCHANGE_EVENT_NAME);
    156  }
    157 
    158  if (previousLevel != mLevel) {
    159    DispatchTrustedEvent(LEVELCHANGE_EVENT_NAME);
    160  }
    161 
    162  /*
    163   * There are a few situations that could happen here:
    164   * 1. Charging state changed:
    165   *   a. Previous remaining time wasn't unkwonw, we have to fire an event for
    166   *      the change.
    167   *   b. New remaining time isn't unkwonw, we have to fire an event for it.
    168   * 2. Charging state didn't change but remainingTime did, we have to fire
    169   *    the event that correspond to the current charging state.
    170   */
    171  if (mCharging != previousCharging) {
    172    if (previousRemainingTime != kUnknownRemainingTime) {
    173      DispatchTrustedEvent(previousCharging ? CHARGINGTIMECHANGE_EVENT_NAME
    174                                            : DISCHARGINGTIMECHANGE_EVENT_NAME);
    175    }
    176    if (mRemainingTime != kUnknownRemainingTime) {
    177      DispatchTrustedEvent(mCharging ? CHARGINGTIMECHANGE_EVENT_NAME
    178                                     : DISCHARGINGTIMECHANGE_EVENT_NAME);
    179    }
    180  } else if (previousRemainingTime != mRemainingTime) {
    181    DispatchTrustedEvent(mCharging ? CHARGINGTIMECHANGE_EVENT_NAME
    182                                   : DISCHARGINGTIMECHANGE_EVENT_NAME);
    183  }
    184 }
    185 
    186 }  // namespace mozilla::dom::battery