| // Copyright 2014 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 "third_party/blink/renderer/modules/battery/battery_manager.h" |
| |
| #include "third_party/blink/public/mojom/frame/lifecycle.mojom-blink.h" |
| #include "third_party/blink/renderer/core/dom/dom_exception.h" |
| #include "third_party/blink/renderer/core/dom/events/event.h" |
| #include "third_party/blink/renderer/core/execution_context/execution_context.h" |
| #include "third_party/blink/renderer/core/frame/local_dom_window.h" |
| #include "third_party/blink/renderer/core/frame/navigator.h" |
| #include "third_party/blink/renderer/modules/battery/battery_dispatcher.h" |
| #include "third_party/blink/renderer/platform/wtf/assertions.h" |
| |
| namespace blink { |
| |
| const char BatteryManager::kSupplementName[] = "BatteryManager"; |
| |
| // static |
| ScriptPromise BatteryManager::getBattery(ScriptState* script_state, |
| Navigator& navigator) { |
| if (!navigator.DomWindow()) |
| return ScriptPromise(); |
| |
| // Check to see if this request would be blocked according to the Battery |
| // Status API specification. |
| LocalDOMWindow* window = navigator.DomWindow(); |
| if (!window->IsSecureContext()) |
| UseCounter::Count(window, WebFeature::kBatteryStatusInsecureOrigin); |
| window->GetFrame()->CountUseIfFeatureWouldBeBlockedByFeaturePolicy( |
| WebFeature::kBatteryStatusCrossOrigin, |
| WebFeature::kBatteryStatusSameOriginABA); |
| |
| auto* supplement = Supplement<Navigator>::From<BatteryManager>(navigator); |
| if (!supplement) { |
| supplement = MakeGarbageCollected<BatteryManager>(navigator); |
| ProvideTo(navigator, supplement); |
| } |
| return supplement->StartRequest(script_state); |
| } |
| |
| BatteryManager::~BatteryManager() = default; |
| |
| BatteryManager::BatteryManager(Navigator& navigator) |
| : Supplement<Navigator>(navigator), |
| ExecutionContextLifecycleStateObserver(navigator.DomWindow()), |
| PlatformEventController(*navigator.DomWindow()), |
| battery_dispatcher_( |
| MakeGarbageCollected<BatteryDispatcher>(navigator.DomWindow())) { |
| UpdateStateIfNeeded(); |
| } |
| |
| ScriptPromise BatteryManager::StartRequest(ScriptState* script_state) { |
| if (!battery_property_) { |
| battery_property_ = MakeGarbageCollected<BatteryProperty>( |
| ExecutionContext::From(script_state)); |
| |
| // If the context is in a stopped state already, do not start updating. |
| if (!GetExecutionContext() || GetExecutionContext()->IsContextDestroyed()) { |
| battery_property_->Resolve(this); |
| } else { |
| has_event_listener_ = true; |
| StartUpdating(); |
| } |
| } |
| |
| return battery_property_->Promise(script_state->World()); |
| } |
| |
| bool BatteryManager::charging() { |
| return battery_status_.Charging(); |
| } |
| |
| double BatteryManager::chargingTime() { |
| return battery_status_.charging_time(); |
| } |
| |
| double BatteryManager::dischargingTime() { |
| return battery_status_.discharging_time(); |
| } |
| |
| double BatteryManager::level() { |
| return battery_status_.Level(); |
| } |
| |
| void BatteryManager::DidUpdateData() { |
| DCHECK(battery_property_); |
| |
| BatteryStatus old_status = battery_status_; |
| battery_status_ = *battery_dispatcher_->LatestData(); |
| |
| if (battery_property_->GetState() == BatteryProperty::kPending) { |
| battery_property_->Resolve(this); |
| return; |
| } |
| |
| DCHECK(GetExecutionContext()); |
| if (GetExecutionContext()->IsContextPaused() || |
| GetExecutionContext()->IsContextDestroyed()) { |
| return; |
| } |
| |
| if (battery_status_.Charging() != old_status.Charging()) |
| DispatchEvent(*Event::Create(event_type_names::kChargingchange)); |
| if (battery_status_.charging_time() != old_status.charging_time()) |
| DispatchEvent(*Event::Create(event_type_names::kChargingtimechange)); |
| if (battery_status_.discharging_time() != old_status.discharging_time()) |
| DispatchEvent(*Event::Create(event_type_names::kDischargingtimechange)); |
| if (battery_status_.Level() != old_status.Level()) |
| DispatchEvent(*Event::Create(event_type_names::kLevelchange)); |
| } |
| |
| void BatteryManager::RegisterWithDispatcher() { |
| battery_dispatcher_->AddController(this, DomWindow()); |
| } |
| |
| void BatteryManager::UnregisterWithDispatcher() { |
| battery_dispatcher_->RemoveController(this); |
| } |
| |
| bool BatteryManager::HasLastData() { |
| return battery_dispatcher_->LatestData(); |
| } |
| |
| void BatteryManager::ContextLifecycleStateChanged( |
| mojom::FrameLifecycleState state) { |
| if (state == mojom::FrameLifecycleState::kRunning) { |
| has_event_listener_ = true; |
| StartUpdating(); |
| } else { |
| has_event_listener_ = false; |
| StopUpdating(); |
| } |
| } |
| |
| void BatteryManager::ContextDestroyed() { |
| has_event_listener_ = false; |
| battery_property_ = nullptr; |
| StopUpdating(); |
| } |
| |
| bool BatteryManager::HasPendingActivity() const { |
| // Prevent V8 from garbage collecting the wrapper object if there are |
| // event listeners or pending promises attached to it. |
| return HasEventListeners() || |
| (battery_property_ && |
| battery_property_->GetState() == BatteryProperty::kPending); |
| } |
| |
| void BatteryManager::Trace(Visitor* visitor) const { |
| visitor->Trace(battery_property_); |
| visitor->Trace(battery_dispatcher_); |
| Supplement<Navigator>::Trace(visitor); |
| PlatformEventController::Trace(visitor); |
| EventTargetWithInlineData::Trace(visitor); |
| ExecutionContextLifecycleStateObserver::Trace(visitor); |
| } |
| |
| } // namespace blink |