summaryrefslogtreecommitdiffstats
path: root/dom/power/WakeLockSentinel.cpp
blob: 1a0739dbd08b8b2164e40b382964b23fad2d2a56 (plain)
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
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/Assertions.h"
#include "mozilla/Telemetry.h"
#include "mozilla/TelemetryHistogramEnums.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/EventBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/WakeLockSentinelBinding.h"
#include "mozilla/Hal.h"
#include "WakeLockJS.h"
#include "WakeLockSentinel.h"

namespace mozilla::dom {

JSObject* WakeLockSentinel::WrapObject(JSContext* cx,
                                       JS::Handle<JSObject*> aGivenProto) {
  return WakeLockSentinel_Binding::Wrap(cx, this, aGivenProto);
}

bool WakeLockSentinel::Released() const { return mReleased; }

void WakeLockSentinel::NotifyLockReleased() {
  MOZ_ASSERT(!mReleased);
  mReleased = true;

  Telemetry::AccumulateTimeDelta(Telemetry::SCREENWAKELOCK_HELD_DURATION_MS,
                                 mCreationTime);

  hal::BatteryInformation batteryInfo;
  hal::GetCurrentBatteryInformation(&batteryInfo);
  if (!batteryInfo.charging()) {
    uint32_t level = static_cast<uint32_t>(100 * batteryInfo.level());
    Telemetry::Accumulate(
        Telemetry::SCREENWAKELOCK_RELEASE_BATTERY_LEVEL_DISCHARGING, level);
  }

  if (mHoldsActualLock) {
    MOZ_ASSERT(mType == WakeLockType::Screen);
    NS_DispatchToMainThread(NS_NewRunnableFunction("ReleaseWakeLock", []() {
      hal::ModifyWakeLock(u"screen"_ns, hal::WAKE_LOCK_REMOVE_ONE,
                          hal::WAKE_LOCK_NO_CHANGE);
    }));
    mHoldsActualLock = false;
  }

  EventInit init;
  init.mBubbles = false;
  init.mCancelable = false;
  RefPtr<Event> event = Event::Constructor(this, u"release"_ns, init);
  DispatchTrustedEvent(event);
}

void WakeLockSentinel::AcquireActualLock() {
  MOZ_ASSERT(mType == WakeLockType::Screen);
  MOZ_ASSERT(!mHoldsActualLock);
  mHoldsActualLock = true;
  NS_DispatchToMainThread(NS_NewRunnableFunction("AcquireWakeLock", []() {
    hal::ModifyWakeLock(u"screen"_ns, hal::WAKE_LOCK_ADD_ONE,
                        hal::WAKE_LOCK_NO_CHANGE);
  }));
}

// https://w3c.github.io/screen-wake-lock/#the-release-method
already_AddRefed<Promise> WakeLockSentinel::ReleaseLock(ErrorResult& aRv) {
  // ReleaseWakeLock will remove this from document.[[ActiveLocks]]
  RefPtr<WakeLockSentinel> kungFuDeathGrip(this);

  if (!mReleased) {
    nsCOMPtr<nsIGlobalObject> global = GetOwnerGlobal();
    if (!global) {
      aRv.Throw(NS_ERROR_NULL_POINTER);
      return nullptr;
    }
    nsCOMPtr<nsPIDOMWindowInner> window = global->GetAsInnerWindow();
    if (!window) {
      aRv.Throw(NS_ERROR_NULL_POINTER);
      return nullptr;
    }
    nsCOMPtr<Document> doc = window->GetExtantDoc();
    if (!doc) {
      aRv.Throw(NS_ERROR_NULL_POINTER);
      return nullptr;
    }
    ReleaseWakeLock(doc, this, mType);
  }

  if (RefPtr<Promise> p =
          Promise::CreateResolvedWithUndefined(GetOwnerGlobal(), aRv)) {
    return p.forget();
  }
  return nullptr;
}

}  // namespace mozilla::dom