michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include michael@0: #include "BatteryManager.h" michael@0: #include "Constants.h" michael@0: #include "mozilla/DOMEventTargetHelper.h" michael@0: #include "mozilla/Hal.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "mozilla/dom/BatteryManagerBinding.h" michael@0: #include "nsIDOMClassInfo.h" michael@0: michael@0: /** michael@0: * We have to use macros here because our leak analysis tool things we are michael@0: * leaking strings when we have |static const nsString|. Sad :( michael@0: */ michael@0: #define LEVELCHANGE_EVENT_NAME NS_LITERAL_STRING("levelchange") michael@0: #define CHARGINGCHANGE_EVENT_NAME NS_LITERAL_STRING("chargingchange") michael@0: #define DISCHARGINGTIMECHANGE_EVENT_NAME NS_LITERAL_STRING("dischargingtimechange") michael@0: #define CHARGINGTIMECHANGE_EVENT_NAME NS_LITERAL_STRING("chargingtimechange") michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: namespace battery { michael@0: michael@0: BatteryManager::BatteryManager(nsPIDOMWindow* aWindow) michael@0: : DOMEventTargetHelper(aWindow) michael@0: , mLevel(kDefaultLevel) michael@0: , mCharging(kDefaultCharging) michael@0: , mRemainingTime(kDefaultRemainingTime) michael@0: { michael@0: } michael@0: michael@0: void michael@0: BatteryManager::Init() michael@0: { michael@0: hal::RegisterBatteryObserver(this); michael@0: michael@0: hal::BatteryInformation batteryInfo; michael@0: hal::GetCurrentBatteryInformation(&batteryInfo); michael@0: michael@0: UpdateFromBatteryInfo(batteryInfo); michael@0: } michael@0: michael@0: void michael@0: BatteryManager::Shutdown() michael@0: { michael@0: hal::UnregisterBatteryObserver(this); michael@0: } michael@0: michael@0: JSObject* michael@0: BatteryManager::WrapObject(JSContext* aCx) michael@0: { michael@0: return BatteryManagerBinding::Wrap(aCx, this); michael@0: } michael@0: michael@0: double michael@0: BatteryManager::DischargingTime() const michael@0: { michael@0: if (mCharging || mRemainingTime == kUnknownRemainingTime) { michael@0: return std::numeric_limits::infinity(); michael@0: } michael@0: michael@0: return mRemainingTime; michael@0: } michael@0: michael@0: double michael@0: BatteryManager::ChargingTime() const michael@0: { michael@0: if (!mCharging || mRemainingTime == kUnknownRemainingTime) { michael@0: return std::numeric_limits::infinity(); michael@0: } michael@0: michael@0: return mRemainingTime; michael@0: } michael@0: michael@0: void michael@0: BatteryManager::UpdateFromBatteryInfo(const hal::BatteryInformation& aBatteryInfo) michael@0: { michael@0: mLevel = aBatteryInfo.level(); michael@0: mCharging = aBatteryInfo.charging(); michael@0: mRemainingTime = aBatteryInfo.remainingTime(); michael@0: michael@0: // Add some guards to make sure the values are coherent. michael@0: if (mLevel == 1.0 && mCharging == true && michael@0: mRemainingTime != kDefaultRemainingTime) { michael@0: mRemainingTime = kDefaultRemainingTime; michael@0: NS_ERROR("Battery API: When charging and level at 1.0, remaining time " michael@0: "should be 0. Please fix your backend!"); michael@0: } michael@0: } michael@0: michael@0: void michael@0: BatteryManager::Notify(const hal::BatteryInformation& aBatteryInfo) michael@0: { michael@0: double previousLevel = mLevel; michael@0: bool previousCharging = mCharging; michael@0: double previousRemainingTime = mRemainingTime; michael@0: michael@0: UpdateFromBatteryInfo(aBatteryInfo); michael@0: michael@0: if (previousCharging != mCharging) { michael@0: DispatchTrustedEvent(CHARGINGCHANGE_EVENT_NAME); michael@0: } michael@0: michael@0: if (previousLevel != mLevel) { michael@0: DispatchTrustedEvent(LEVELCHANGE_EVENT_NAME); michael@0: } michael@0: michael@0: /* michael@0: * There are a few situations that could happen here: michael@0: * 1. Charging state changed: michael@0: * a. Previous remaining time wasn't unkwonw, we have to fire an event for michael@0: * the change. michael@0: * b. New remaining time isn't unkwonw, we have to fire an event for it. michael@0: * 2. Charging state didn't change but remainingTime did, we have to fire michael@0: * the event that correspond to the current charging state. michael@0: */ michael@0: if (mCharging != previousCharging) { michael@0: if (previousRemainingTime != kUnknownRemainingTime) { michael@0: DispatchTrustedEvent(previousCharging ? CHARGINGTIMECHANGE_EVENT_NAME michael@0: : DISCHARGINGTIMECHANGE_EVENT_NAME); michael@0: } michael@0: if (mRemainingTime != kUnknownRemainingTime) { michael@0: DispatchTrustedEvent(mCharging ? CHARGINGTIMECHANGE_EVENT_NAME michael@0: : DISCHARGINGTIMECHANGE_EVENT_NAME); michael@0: } michael@0: } else if (previousRemainingTime != mRemainingTime) { michael@0: DispatchTrustedEvent(mCharging ? CHARGINGTIMECHANGE_EVENT_NAME michael@0: : DISCHARGINGTIMECHANGE_EVENT_NAME); michael@0: } michael@0: } michael@0: michael@0: /* static */ bool michael@0: BatteryManager::HasSupport() michael@0: { michael@0: return Preferences::GetBool("dom.battery.enabled", true); michael@0: } michael@0: michael@0: } // namespace battery michael@0: } // namespace dom michael@0: } // namespace mozilla